Обратная трассировка ниже меня действительно смущает.
- Обратная трассировка сообщает, что qnx_slog2::log_output() вызывает сам себя, что невозможно, поскольку соответствующий код не функция рекурсии.
- Адрес этого равен 0x2, когда qnx_slog2::log_output вызывается во второй раз, что не является допустимым адресом для экземпляра.
#0 0x0000003ae09b5cc0 in ?? ()
#1 0x0000001b5319cf64 in qnx_slog2::log_output (this=0x2, level=1, fmt=0x3ae09c9138 ,level=1)
at /home/jhone/qnx_slog2.hpp:137
#2 0x0000001b5319cf64 in qnx_slog2::log_output (this=0x1b531e9048 , level=1,
fmt=0x2ec2c7fbd0 "[st_slog2] 0MS-E oms_result_sender.cpp:174 operator()() soa ges dynamic rect width:0, height:0, x:0,y", level=1)
at /home/jhone/qnx_slog2.hpp:137
#3 0x0000003aed61fcc in malloc_lock.constprop.4 ()
from //home/jhone/publish/lib/libc.so.5
#4 0x6c757365725f736d in ??()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Вот код qnx_slog2.hpp: строки с 128 по 149
void log_output(short level, const char* fmt, ...) {
if (true == log_block(level)) {
return;
}
std::unique_lock lock(lock_);
va_list args;
va_start(args, fmt);
switch (log_type_) {
case LOG_TYPE_QNX:
if ((fmt != nullptr) && (match_level(level) > 0) && (*fmt != '\0')) { //line 137
vslog2f(nullptr, log_id_, match_level(level), fmt, args);
}
break;
case LOG_TYPE_PRINTF: {
memset(print_buffer_, 0, sizeof(print_buffer_));
vsnprintf(print_buffer_, sizeof(print_buffer_), fmt, args);
log_print(level);
break;
}
}
va_end(args);
}
Согласно официальному документу, vslog2f является потокобезопасным.
Благодаря совету @Retired Ninja.
slog2_set_default_buffer вызывается первым при инициализации экземпляра. Вот соответствующий фрагмент кода:
class qnx_slog2 {
private:
short log_type_ = LOG_TYPE_QNX;
short log_level_ = LOG_DEBUG;
int log_page_num_ = 4;
int log_id_ = 116;
std::mutex lock_;
char print_buffer_[1024] = {0};
slog2_buffer_t buf = {0};
public:
bool init() {
if (log_type_ != LOG_TYPE_QNX) {
return true;
}
std::unique_lock lock(lock_);
slog2_buffer_set_config_t config{};
config.buffer_set_name = __progname;
config.num_buffers = 1;
config.verbosity_level = SLOG2_DEBUG1;
config.buffer_config[0].buffer_name = LOG_TAG;
config.buffer_config[0].num_pages =
log_page_num_; // one page 4KB
if (0 == slog2_register(&config, &buf, SLOG2_DISCARD_NEWLINE)) {
slog2_set_default_buffer(buf);
return true;
}
return false;
}
//omit not important code
}
Ответ на потенциальную проблему, заключающуюся в том, что спецификатор формата не соответствует типу аргумента.
Это не так. возможно, поскольку все сообщения журнала генерируются библиотекой fmt, которая широко используется spdlog и т. д. Другими словами, как указывает обратная трассировка, входные аргументы для qnx_slog2:: log_output всегда: короткий уровень, за которым следует const char*, и не более того. Ниже приведен простой фрагмент кода, чтобы его было легче понять. .
std::string log_msg = fmt::format(" soa ges dynamic rect width:{}, height:{}, x:{},y:{}", width, height, loc_x, loc_y);
qnx_slog2::get_instance().log_output(log_level, log_msg.c_str());
Может ли кто-нибудь пролить свет на то, как шаг за шагом решить эту проблему? Я действительно не знаю, что делать в первую очередь.
Обновить реализацию
Спасибо всем из вас.
Сначала в проекте использовался spdlog, а позже нам необходимо использовать slog2, который предоставляется самим QNX. Таким образом, во всех форматах журналов используется {}, кроме %d,%s одинаково. Требуется много работы, чтобы выполнить замену одну за другой.
Именно поэтому мы до сих пор используем fmt в качестве инструмента форматирования, а затем передаем форматированную строку в метод qnx_slog2::log_output.
Я согласен с Red.Wave, slogc — лучший выбор для этого условия. Я изменяю реализацию qnx_slog2::log_output и макросы, которые его вызывают, как показано ниже.
ПРИМЕЧАНИЕ: Поскольку в официальном документе говорится что slogc является потокобезопасным, поэтому я больше не использую std::mutex в реализации.
void qnx_slog2::log_output(short level, const std::string& str) {
if (true == log_block(level)) {
return;
}
if (str.empty()) {
return;
}
slog2c(nullptr, log_id_, match_level(level), str.c_str());
}
void qnx_slog2::log_output(short level, const char* ptr) {
if (true == log_block(level)) {
return;
}
slog2c(nullptr, log_id_, match_level(level), ptr);
}
#define LOG_COMMON(log_level, log_level_str, fmt_log, ...) \
do { \
try { \
auto fmt_str = fmt::format("[" LOG_TAG "] [" log_level_str "] {}:{} {}() " fmt_log, \
__BASEFILE__, __LINE__, __func__, ##__VA_ARGS__); \
qnx_slog2::get_log().log_output(log_level, fmt_str); \
} catch (std::exception & e) { \
char internal_print_buffer[MAX_SIZE]; \
int len = snprintf(internal_print_buffer, MAX_SIZE, \
"[\" LOG_TAG \"] [CRITICAL] %s:%d %s() format error", __BASEFILE__, \
__LINE__, __func__); \
qnx_slog2::get_log().log_output(log_level, internal_print_buffer); \
} \
} while (0);
#define SERVICE_CRITICAL(fmt_log, ...) LOG_COMMON(LOG_CRITICAL, "SERVICE-C", fmt_log, ##__VA_ARGS__)
#define SERVICE_ERROR(fmt_log, ...) LOG_COMMON(LOG_ERROR, "SERVICE-E", fmt_log, ##__VA_ARGS__)
#define SERVICE_WARN(fmt_log, ...) LOG_COMMON(LOG_WARN, "SERVICE-W", fmt_log, ##__VA_ARGS__)
#define SERVICE_DEBUG(fmt_log, ...) LOG_COMMON(LOG_DEBUG, "SERVICE-D", fmt_log, ##__VA_ARGS__)
#define SERVICE_INFO(fmt_log, ...) LOG_COMMON(LOG_INFO, "SERVICE-I", fmt_log, ##__VA_ARGS__)
#define SERVICE_TRACE(fmt_log, ...) LOG_COMMON(LOG_INFO, "SERVICE-T", fmt_log, ##__VA_ARGS__)
#define ALG_CRITICAL(fmt_log, ...) LOG_COMMON(LOG_CRITICAL, "ALG-C", fmt_log, ##__VA_ARGS__)
#define ALG_ERROR(fmt_log, ...) LOG_COMMON(LOG_ERROR, "ALG-E", fmt_log, ##__VA_ARGS__)
#define ALG_WARN(fmt_log, ...) LOG_COMMON(LOG_WARN, "ALG-W", fmt_log, ##__VA_ARGS__)
#define ALG_DEBUG(fmt_log, ...) LOG_COMMON(LOG_DEBUG, "ALG-D", fmt_log, ##__VA_ARGS__)
#define ALG_INFO(fmt_log, ...) LOG_COMMON(LOG_INFO, "ALG-I", fmt_log, ##__VA_ARGS__)
#define ALG_TRACE(fmt_log, ...) LOG_COMMON(LOG_INFO, "ALG-T", fmt_log, ##__VA_ARGS__)
//omit simliar macros
Подробнее здесь: https://stackoverflow.com/questions/784 ... -not-as-ex
Мобильная версия