diff --git a/include/qb/qblog.h b/include/qb/qblog.h index d8f0882..3dcdf9c 100644 --- a/include/qb/qblog.h +++ b/include/qb/qblog.h @@ -249,6 +249,7 @@ typedef const char *(*qb_log_tags_stringify_fn)(uint32_t tags); /** * An instance of this structure is created for each log message + * with the message-id */ struct qb_log_callsite { const char *function; @@ -258,6 +259,7 @@ struct qb_log_callsite { uint32_t lineno; uint32_t targets; uint32_t tags; + const char *message_id; } __attribute__((aligned(8))); typedef void (*qb_log_filter_fn)(struct qb_log_callsite * cs); @@ -319,6 +321,39 @@ struct qb_log_callsite* qb_log_callsite_get(const char *function, uint32_t lineno, uint32_t tags); +/** + * Get or create a callsite at the given position. + * The same that qb_log_callsite_get but with the + * message_id parameter. + * + * The result can then be passed into qb_log_real_() + * + * @param message_id in the systemd catalog or NULL + * @param function originating function name + * @param filename originating filename + * @param format format string + * @param priority this takes syslog priorities. + * @param lineno file line number + * @param tags the tag + */ +struct qb_log_callsite* qb_log_callsite_get2(const char *message_id, + const char *function, + const char *filename, + const char *format, + uint8_t priority, + uint32_t lineno, + uint32_t tags); + +void qb_log_from_external_source_va2(const char *message_id, + const char *function, + const char *filename, + const char *format, + uint8_t priority, + uint32_t lineno, + uint32_t tags, + va_list ap) + __attribute__ ((format (printf, 4, 0))); + void qb_log_from_external_source_va(const char *function, const char *filename, const char *format, @@ -332,6 +367,7 @@ void qb_log_from_external_source_va(const char *function, * This is the function to generate a log message if you want to * manually add tags. * + * @param message_id in the systemd catalog or NULL * @param priority this takes syslog priorities. * @param tags this is a uint32_t that you can use with * qb_log_tags_stringify_fn_set() to "tag" a log message @@ -340,13 +376,37 @@ void qb_log_from_external_source_va(const char *function, * @param fmt usual printf style format specifiers * @param args usual printf style args */ -#define qb_logt(priority, tags, fmt, args...) do { \ +#define qb_logt2(message_id, priority, tags, fmt, args...) do { \ struct qb_log_callsite* descriptor_pt = \ - qb_log_callsite_get(__func__, __FILE__, fmt, \ + qb_log_callsite_get2(message_id, __func__, __FILE__, fmt, \ priority, __LINE__, tags); \ qb_log_real_(descriptor_pt, ##args); \ } while(0) +/** + * This is the function to generate a log message if you want to + * manually add tags. + * + * @param priority this takes syslog priorities. + * @param tags this is a uint32_t that you can use with + * qb_log_tags_stringify_fn_set() to "tag" a log message + * with a feature or sub-system then you can use "%g" + * in the format specifer to print it out. + * @param fmt usual printf style format specifiers + * @param args usual printf style args + */ +#define qb_logt(priority, tags, fmt, args...) qb_logt2(NULL, priority, tags, fmt, ##args) + + +/** + * This is the main function to generate a log message. + * + * @param message_id in the systemd catalog or NULL + * @param priority this takes syslog priorities. + * @param fmt usual printf style format specifiers + * @param args usual printf style args + */ +#define qb_log2(message_id, priority, fmt, args...) qb_logt2(message_id, priority, 0, fmt, ##args) /** * This is the main function to generate a log message. diff --git a/lib/log.c b/lib/log.c index d6074b8..4d66018 100644 --- a/lib/log.c +++ b/lib/log.c @@ -317,7 +317,8 @@ qb_log_thread_log_write(struct qb_log_callsite *cs, } struct qb_log_callsite* -qb_log_callsite_get(const char *function, +qb_log_callsite_get2(const char *message_id, + const char *function, const char *filename, const char *format, uint8_t priority, @@ -335,8 +336,9 @@ qb_log_callsite_get(const char *function, return NULL; } - cs = qb_log_dcs_get(&new_dcs, function, filename, - format, priority, lineno, tags); + cs = qb_log_dcs_get(&new_dcs, message_id, function, filename, + format, priority, lineno, tags); + if (cs == NULL) { return NULL; } @@ -380,8 +382,21 @@ qb_log_callsite_get(const char *function, return cs; } +struct qb_log_callsite* +qb_log_callsite_get(const char *function, + const char *filename, + const char *format, + uint8_t priority, + uint32_t lineno, + uint32_t tags) +{ + return qb_log_callsite_get2(NULL, function, filename, format, + priority, lineno, tags); +} + void -qb_log_from_external_source_va(const char *function, +qb_log_from_external_source_va2(const char *message_id, + const char *function, const char *filename, const char *format, uint8_t priority, @@ -393,11 +408,22 @@ qb_log_from_external_source_va(const char *function, return; } - cs = qb_log_callsite_get(function, filename, + cs = qb_log_callsite_get2(message_id, function, filename, format, priority, lineno, tags); qb_log_real_va_(cs, ap); } +void +qb_log_from_external_source_va(const char *function, + const char *filename, + const char *format, + uint8_t priority, + uint32_t lineno, uint32_t tags, va_list ap) +{ + qb_log_from_external_source_va2(NULL, function, filename, + format, priority, lineno, tags, ap); +} + void qb_log_from_external_source(const char *function, const char *filename, diff --git a/lib/log_dcs.c b/lib/log_dcs.c index e8e3b6f..1021a84 100644 --- a/lib/log_dcs.c +++ b/lib/log_dcs.c @@ -58,7 +58,8 @@ _log_register_callsites(qb_array_t * a, uint32_t bin) } static struct qb_log_callsite * -_log_dcs_new_cs(const char *function, +_log_dcs_new_cs(const char *message_id, + const char *function, const char *filename, const char *format, uint8_t priority, uint32_t lineno, uint32_t tags) @@ -70,6 +71,7 @@ _log_dcs_new_cs(const char *function, assert(rc == 0); assert(cs != NULL); + cs->message_id = message_id ? strdup(message_id) : NULL; cs->function = strdup(function); cs->filename = strdup(filename); cs->format = strdup(format); @@ -82,6 +84,7 @@ _log_dcs_new_cs(const char *function, struct qb_log_callsite * qb_log_dcs_get(int32_t * newly_created, + const char *message_id, const char *function, const char *filename, const char *format, @@ -120,6 +123,7 @@ qb_log_dcs_get(int32_t * newly_created, (void)qb_thread_lock(arr_next_lock); if (csl_head->cs && priority == csl_head->cs->priority && + (message_id ? (strcmp(message_id, csl_head->cs->message_id) == 0) : 1) && strcmp(safe_filename, csl_head->cs->filename) == 0 && strcmp(safe_format, csl_head->cs->format) == 0) { (void)qb_thread_unlock(arr_next_lock); @@ -130,7 +134,8 @@ qb_log_dcs_get(int32_t * newly_created, * so we will either have to create it or go through a list */ if (csl_head->cs == NULL) { - csl_head->cs = _log_dcs_new_cs(safe_function, safe_filename, safe_format, + csl_head->cs = _log_dcs_new_cs(message_id, safe_function, + safe_filename, safe_format, priority, lineno, tags); cs = csl_head->cs; csl_head->next = NULL; @@ -152,7 +157,8 @@ qb_log_dcs_get(int32_t * newly_created, if (csl == NULL) { goto cleanup; } - csl->cs = _log_dcs_new_cs(safe_function, safe_filename, safe_format, + csl->cs = _log_dcs_new_cs(message_id, safe_function, + safe_filename, safe_format, priority, lineno, tags); csl->next = NULL; csl_last->next = csl; diff --git a/lib/log_int.h b/lib/log_int.h index 9ae818f..3d17fd6 100644 --- a/lib/log_int.h +++ b/lib/log_int.h @@ -125,6 +125,7 @@ void qb_log_thread_resume(struct qb_log_target *t); void qb_log_dcs_init(void); void qb_log_dcs_fini(void); struct qb_log_callsite *qb_log_dcs_get(int32_t *newly_created, + const char *message_id, const char *function, const char *filename, const char *format, diff --git a/lib/log_syslog.c b/lib/log_syslog.c index b1b8246..f7a68bf 100644 --- a/lib/log_syslog.c +++ b/lib/log_syslog.c @@ -64,13 +64,24 @@ _syslog_logger(int32_t target, } #ifdef USE_JOURNAL if (t->use_journal) { - sd_journal_send("PRIORITY=%d", final_priority, + if (cs->message_id) { + sd_journal_send("MESSAGE_ID=%s", cs->message_id, + "PRIORITY=%d", final_priority, "CODE_LINE=%d", cs->lineno, "CODE_FILE=%s", cs->filename, "CODE_FUNC=%s", cs->function, "SYSLOG_IDENTIFIER=%s", t->name, "MESSAGE=%s", output_buffer, NULL); + } else { + sd_journal_send("PRIORITY=%d", final_priority, + "CODE_LINE=%d", cs->lineno, + "CODE_FILE=%s", cs->filename, + "CODE_FUNC=%s", cs->function, + "SYSLOG_IDENTIFIER=%s", t->name, + "MESSAGE=%s", output_buffer, + NULL); + } } else { #endif syslog(final_priority, "%s", output_buffer); diff --git a/tests/check_log.c b/tests/check_log.c index 994bda9..039a4bb 100644 --- a/tests/check_log.c +++ b/tests/check_log.c @@ -1021,12 +1021,13 @@ START_TEST(test_journal) pid_t log_pid; sd_journal *jnl; int count = 0; + const char *msgid="f77379a8490b408bbe5f6940505a777b"; qb_log_init("check_log", LOG_USER, LOG_DEBUG); qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE); rc = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_USE_JOURNAL, 1); ck_assert_int_eq(rc, 0); - qb_log(LOG_ERR, "Test message 1 from libqb"); + qb_log2(msgid, LOG_ERR, "Test message 1 from libqb"); qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_ENABLED, QB_TRUE); rc = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_USE_JOURNAL, 1); @@ -1046,6 +1047,9 @@ START_TEST(test_journal) if (log_pid == getpid()) { rc = sd_journal_get_data(jnl, "MESSAGE", (const void **)&msg, &len); ck_assert_int_eq(rc, 0); + rc = sd_journal_get_data(jnl, "MESSAGE_ID", (const void **)&msg, &len); + ck_assert_int_eq(rc, 0); + ck_assert_str_eq(msg+11, msgid); break; } if (++count > 20) {