From 273b26dbcce52a5b1d2ef11fd7f9bab465f35e23 Mon Sep 17 00:00:00 2001 From: Marco van Wieringen Date: Fri, 1 Jan 2016 15:28:31 +0100 Subject: [PATCH] logging: Add support for setting a log resource timestamp format. This adds support to the generic message resources for overriding the default timestamp format per message resource defined. --- src/dird/dird_conf.c | 3 + src/filed/filed_conf.c | 3 + src/lib/message.c | 50 +++++++++--- src/lib/message.h | 1 + src/lib/msg_res.h | 1 + src/lib/parse_conf.h | 1 + src/lib/protos.h | 3 +- src/lib/res.c | 161 +++++++++++++++++++++------------------ src/stored/stored_conf.c | 3 + 9 files changed, 140 insertions(+), 86 deletions(-) diff --git a/src/dird/dird_conf.c b/src/dird/dird_conf.c index 35f861a2232..5c82a7b120a 100644 --- a/src/dird/dird_conf.c +++ b/src/dird/dird_conf.c @@ -2649,6 +2649,9 @@ void free_resource(RES *sres, int type) if (res->res_msgs.operator_cmd) { free(res->res_msgs.operator_cmd); } + if (res->res_msgs.timestamp_format) { + free(res->res_msgs.timestamp_format); + } free_msgs_res((MSGSRES *)res); /* free message resource */ res = NULL; break; diff --git a/src/filed/filed_conf.c b/src/filed/filed_conf.c index fe6632edc01..f06f3311050 100644 --- a/src/filed/filed_conf.c +++ b/src/filed/filed_conf.c @@ -376,6 +376,9 @@ void free_resource(RES *sres, int type) if (res->res_msgs.operator_cmd) { free(res->res_msgs.operator_cmd); } + if (res->res_msgs.timestamp_format) { + free(res->res_msgs.timestamp_format); + } free_msgs_res((MSGSRES *)res); /* free message resource */ res = NULL; break; diff --git a/src/lib/message.c b/src/lib/message.c index 5e3ade92d3f..5680889e857 100644 --- a/src/lib/message.c +++ b/src/lib/message.c @@ -304,7 +304,7 @@ void init_msg(JCR *jcr, MSGSRES *msg, job_code_callback_t job_code_callback) daemon_msgs = (MSGSRES *)malloc(sizeof(MSGSRES)); memset(daemon_msgs, 0, sizeof(MSGSRES)); for (i=1; i<=M_MAX; i++) { - add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL); + add_msg_dest(daemon_msgs, MD_STDOUT, i, NULL, NULL, NULL); } Dmsg1(050, "Create daemon global message resource %p\n", daemon_msgs); return; @@ -390,7 +390,8 @@ void init_console_msg(const char *wd) * but in the case of MAIL is a space separated list of * email addresses, ... */ -void add_msg_dest(MSGSRES *msg, int dest_code, int msg_type, char *where, char *mail_cmd) +void add_msg_dest(MSGSRES *msg, int dest_code, int msg_type, + char *where, char *mail_cmd, char *timestamp_format) { DEST *d; @@ -404,7 +405,7 @@ void add_msg_dest(MSGSRES *msg, int dest_code, int msg_type, char *where, char * Dmsg4(850, "Add to existing d=%p msgtype=%d destcode=%d where=%s\n", d, msg_type, dest_code, NPRT(where)); set_bit(msg_type, d->msg_types); - set_bit(msg_type, msg->send_msg); /* set msg_type bit in our local */ + set_bit(msg_type, msg->send_msg); /* Set msg_type bit in our local */ return; } } @@ -416,16 +417,23 @@ void add_msg_dest(MSGSRES *msg, int dest_code, int msg_type, char *where, char * memset(d, 0, sizeof(DEST)); d->next = msg->dest_chain; d->dest_code = dest_code; - set_bit(msg_type, d->msg_types); /* set type bit in structure */ - set_bit(msg_type, msg->send_msg); /* set type bit in our local */ + set_bit(msg_type, d->msg_types); /* Set type bit in structure */ + set_bit(msg_type, msg->send_msg); /* Set type bit in our local */ + if (where) { d->where = bstrdup(where); } + if (mail_cmd) { d->mail_cmd = bstrdup(mail_cmd); } - Dmsg5(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s\n", - d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd)); + + if (timestamp_format) { + d->timestamp_format = bstrdup(timestamp_format); + } + + Dmsg6(850, "add new d=%p msgtype=%d destcode=%d where=%s mailcmd=%s timestampformat=%s\n", + d, msg_type, dest_code, NPRT(where), NPRT(d->mail_cmd), NPRT(d->timestamp_format)); msg->dest_chain = d; } @@ -679,6 +687,9 @@ void free_msgs_res(MSGSRES *msgs) if (d->mail_cmd) { free(d->mail_cmd); } + if (d->timestamp_format) { + free(d->timestamp_format); + } old = d; /* save pointer to release */ d = d->next; /* point to next buffer */ free(old); /* free the destination item */ @@ -842,6 +853,7 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg) MSGSRES *msgs; BPIPE *bpipe; const char *mode; + bool dt_conversion = false; Dmsg2(850, "Enter dispatch_message type=%d msg=%s", type, msg); @@ -858,11 +870,9 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg) if (mtime == 1) { *dt = 0; dtlen = 0; - mtime = time(NULL); /* get time for SQL log */ + mtime = time(NULL); /* Get time for SQL log */ } else { - bstrftime(dt, sizeof(dt), mtime, log_timestamp_format); - bstrncat(dt, " ", sizeof(dt)); - dtlen = strlen(dt); + dt_conversion = true; } /* @@ -922,6 +932,10 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg) * If closing this message resource, print and send to syslog, then get out. */ if (msgs->is_closing()) { + if (dt_conversion) { + bstrftime(dt, sizeof(dt), mtime, log_timestamp_format); + bstrncat(dt, " ", sizeof(dt)); + } fputs(dt, stdout); fputs(msg, stdout); fflush(stdout); @@ -931,6 +945,20 @@ void dispatch_message(JCR *jcr, int type, utime_t mtime, char *msg) for (d = msgs->dest_chain; d; d = d->next) { if (bit_is_set(type, d->msg_types)) { + /* + * See if a specific timestamp format was specified for this log resource. + * Otherwise apply the global setting in log_timestamp_format. + */ + if (dt_conversion) { + if (d->timestamp_format) { + bstrftime(dt, sizeof(dt), mtime, d->timestamp_format); + } else { + bstrftime(dt, sizeof(dt), mtime, log_timestamp_format); + } + bstrncat(dt, " ", sizeof(dt)); + dtlen = strlen(dt); + } + switch (d->dest_code) { case MD_CATALOG: if (!jcr || !jcr->db) { diff --git a/src/lib/message.h b/src/lib/message.h index b1f03b58bc1..d7f5e18ae15 100644 --- a/src/lib/message.h +++ b/src/lib/message.h @@ -112,6 +112,7 @@ typedef struct s_dest { char msg_types[NR_MSG_TYPES]; /* Message type mask */ char *where; /* Filename/program name */ char *mail_cmd; /* Mail command */ + char *timestamp_format; /* Timestamp format to use in logging messages */ int syslog_facility; /* Syslog Facility */ POOLMEM *mail_filename; /* Unique mail filename */ } DEST; diff --git a/src/lib/msg_res.h b/src/lib/msg_res.h index 8230b99f7e2..57c938184bf 100644 --- a/src/lib/msg_res.h +++ b/src/lib/msg_res.h @@ -38,6 +38,7 @@ static RES_ITEM msgs_items[] = { { "Description", CFG_TYPE_STR, ITEM(res_msgs.hdr.desc), 0, 0, NULL, NULL, NULL }, { "MailCommand", CFG_TYPE_STR, ITEM(res_msgs.mail_cmd), 0, 0, NULL, NULL, NULL }, { "OperatorCommand", CFG_TYPE_STR, ITEM(res_msgs.operator_cmd), 0, 0, NULL, NULL, NULL }, + { "TimestampFormat", CFG_TYPE_STR, ITEM(res_msgs.timestamp_format), 0, 0, NULL, NULL, NULL }, { "Syslog", CFG_TYPE_MSGS, ITEM(res_msgs), MD_SYSLOG, 0, NULL, NULL, NULL }, { "Mail", CFG_TYPE_MSGS, ITEM(res_msgs), MD_MAIL, 0, NULL, NULL, NULL }, { "MailOnError", CFG_TYPE_MSGS, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, NULL, NULL, NULL }, diff --git a/src/lib/parse_conf.h b/src/lib/parse_conf.h index 80901fbe99b..8b9bdde27ab 100644 --- a/src/lib/parse_conf.h +++ b/src/lib/parse_conf.h @@ -280,6 +280,7 @@ class MSGSRES : public BRSRES { public: char *mail_cmd; /* Mail command */ char *operator_cmd; /* Operator command */ + char *timestamp_format; /* Timestamp format */ DEST *dest_chain; /* chain of destinations */ char send_msg[nbytes_for_bits(M_MAX+1)]; /* Bit array of types */ diff --git a/src/lib/protos.h b/src/lib/protos.h index 2eab2dff47e..5eaeb21cffd 100644 --- a/src/lib/protos.h +++ b/src/lib/protos.h @@ -267,7 +267,8 @@ void my_name_is(int argc, char *argv[], const char *name); void init_msg(JCR *jcr, MSGSRES *msg, job_code_callback_t job_code_callback = NULL); void term_msg(void); void close_msg(JCR *jcr); -void add_msg_dest(MSGSRES *msg, int dest, int type, char *where, char *dest_code); +void add_msg_dest(MSGSRES *msg, int dest, int type, + char *where, char *mail_cmd, char *timestamp_format); void rem_msg_dest(MSGSRES *msg, int dest, int type, char *where); void Jmsg(JCR *jcr, int type, utime_t mtime, const char *fmt, ...); void dispatch_message(JCR *jcr, int type, utime_t mtime, char *buf); diff --git a/src/lib/res.c b/src/lib/res.c index 0cd94d76bf9..d88e4a46588 100644 --- a/src/lib/res.c +++ b/src/lib/res.c @@ -31,7 +31,6 @@ #include "generic_res.h" /* Forward referenced subroutines */ -static void scan_types(LEX *lc, MSGSRES *msg, int dest, char *where, char *cmd); extern CONFIG *my_config; /* Our Global config */ @@ -132,25 +131,82 @@ const char *res_to_str(int rcode) } } +/* + * Scan for message types and add them to the message + * destination. The basic job here is to connect message types + * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate + * destination (MAIL, FILE, OPERATOR, ...) + */ +static void scan_types(LEX *lc, MSGSRES *msg, int dest_code, + char *where, char *cmd, char *timestamp_format) +{ + int i; + bool found, is_not; + int msg_type = 0; + char *str; + + for (;;) { + lex_get_token(lc, T_NAME); /* expect at least one type */ + found = false; + if (lc->str[0] == '!') { + is_not = true; + str = &lc->str[1]; + } else { + is_not = false; + str = &lc->str[0]; + } + for (i = 0; msg_types[i].name; i++) { + if (bstrcasecmp(str, msg_types[i].name)) { + msg_type = msg_types[i].token; + found = true; + break; + } + } + if (!found) { + scan_err1(lc, _("message type: %s not found"), str); + return; + } + + if (msg_type == M_MAX + 1) { /* all? */ + for (i = 1; i <= M_MAX; i++) { /* yes set all types */ + add_msg_dest(msg, dest_code, i, where, cmd, timestamp_format); + } + } else if (is_not) { + rem_msg_dest(msg, dest_code, msg_type, where); + } else { + add_msg_dest(msg, dest_code, msg_type, where, cmd, timestamp_format); + } + if (lc->ch != ',') { + break; + } + Dmsg0(900, "call lex_get_token() to eat comma\n"); + lex_get_token(lc, T_ALL); /* eat comma */ + } + Dmsg0(900, "Done scan_types()\n"); +} + /* * Store Messages Destination information */ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) { int token; - char *cmd; + char *cmd = NULL, + *tsf = NULL; POOLMEM *dest; int dest_len; URES *res_all = (URES *)my_config->m_res_all; Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code); + + tsf = res_all->res_msgs.timestamp_format; if (pass == 1) { switch (item->code) { case MD_STDOUT: case MD_STDERR: case MD_CONSOLE: case MD_CATALOG: - scan_types(lc, (MSGSRES *)(item->value), item->code, NULL, NULL); + scan_types(lc, (MSGSRES *)(item->value), item->code, NULL, NULL, tsf); break; case MD_SYSLOG: { /* syslog */ char *p; @@ -189,24 +245,24 @@ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) /* * Pick up a single facility. */ - token = lex_get_token(lc, T_NAME); /* scan destination */ + token = lex_get_token(lc, T_NAME); /* Scan destination */ pm_strcpy(dest, lc->str); dest_len = lc->str_len; token = lex_get_token(lc, T_SKIP_EOL); - scan_types(lc, (MSGSRES *)(item->value), item->code, dest, NULL); + scan_types(lc, (MSGSRES *)(item->value), item->code, dest, NULL, NULL); free_pool_memory(dest); Dmsg0(900, "done with dest codes\n"); } else { - scan_types(lc, (MSGSRES *)(item->value), item->code, NULL, NULL); + scan_types(lc, (MSGSRES *)(item->value), item->code, NULL, NULL, NULL); } break; } - case MD_OPERATOR: /* send to operator */ - case MD_DIRECTOR: /* send to Director */ - case MD_MAIL: /* mail */ - case MD_MAIL_ON_ERROR: /* mail if Job errors */ - case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */ + case MD_OPERATOR: /* Send to operator */ + case MD_DIRECTOR: /* Send to Director */ + case MD_MAIL: /* Mail */ + case MD_MAIL_ON_ERROR: /* Mail if Job errors */ + case MD_MAIL_ON_SUCCESS: /* Mail if Job succeeds */ if (item->code == MD_OPERATOR) { cmd = res_all->res_msgs.operator_cmd; } else { @@ -215,14 +271,15 @@ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) dest = get_pool_memory(PM_MESSAGE); dest[0] = 0; dest_len = 0; + /* * Pick up comma separated list of destinations. */ for (;;) { - token = lex_get_token(lc, T_NAME); /* scan destination */ + token = lex_get_token(lc, T_NAME); /* Scan destination */ dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2); if (dest[0] != 0) { - pm_strcat(dest, " "); /* separate multiple destinations with space */ + pm_strcat(dest, " "); /* Separate multiple destinations with space */ dest_len++; } pm_strcat(dest, lc->str); @@ -230,7 +287,7 @@ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest)); token = lex_get_token(lc, T_SKIP_EOL); if (token == T_COMMA) { - continue; /* get another destination */ + continue; /* Get another destination */ } if (token != T_EQUALS) { scan_err1(lc, _("expected an =, got: %s"), lc->str); @@ -239,17 +296,18 @@ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) break; } Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd)); - scan_types(lc, (MSGSRES *)(item->value), item->code, dest, cmd); + scan_types(lc, (MSGSRES *)(item->value), item->code, dest, cmd, tsf); free_pool_memory(dest); Dmsg0(900, "done with dest codes\n"); break; - case MD_FILE: /* file */ - case MD_APPEND: /* append */ + case MD_FILE: /* File */ + case MD_APPEND: /* Append */ dest = get_pool_memory(PM_MESSAGE); + /* * Pick up a single destination. */ - token = lex_get_token(lc, T_NAME); /* scan destination */ + token = lex_get_token(lc, T_NAME); /* Scan destination */ pm_strcpy(dest, lc->str); dest_len = lc->str_len; token = lex_get_token(lc, T_SKIP_EOL); @@ -258,7 +316,7 @@ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) scan_err1(lc, _("expected an =, got: %s"), lc->str); return; } - scan_types(lc, (MSGSRES *)(item->value), item->code, dest, NULL); + scan_types(lc, (MSGSRES *)(item->value), item->code, dest, NULL, tsf); free_pool_memory(dest); Dmsg0(900, "done with dest codes\n"); break; @@ -273,59 +331,6 @@ static void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) Dmsg0(900, "Done store_msgs\n"); } -/* - * Scan for message types and add them to the message - * destination. The basic job here is to connect message types - * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate - * destination (MAIL, FILE, OPERATOR, ...) - */ -static void scan_types(LEX *lc, MSGSRES *msg, int dest_code, char *where, char *cmd) -{ - int i; - bool found, is_not; - int msg_type = 0; - char *str; - - for (;;) { - lex_get_token(lc, T_NAME); /* expect at least one type */ - found = false; - if (lc->str[0] == '!') { - is_not = true; - str = &lc->str[1]; - } else { - is_not = false; - str = &lc->str[0]; - } - for (i = 0; msg_types[i].name; i++) { - if (bstrcasecmp(str, msg_types[i].name)) { - msg_type = msg_types[i].token; - found = true; - break; - } - } - if (!found) { - scan_err1(lc, _("message type: %s not found"), str); - return; - } - - if (msg_type == M_MAX + 1) { /* all? */ - for (i = 1; i <= M_MAX; i++) { /* yes set all types */ - add_msg_dest(msg, dest_code, i, where, cmd); - } - } else if (is_not) { - rem_msg_dest(msg, dest_code, msg_type, where); - } else { - add_msg_dest(msg, dest_code, msg_type, where, cmd); - } - if (lc->ch != ',') { - break; - } - Dmsg0(900, "call lex_get_token() to eat comma\n"); - lex_get_token(lc, T_ALL); /* eat comma */ - } - Dmsg0(900, "Done scan_types()\n"); -} - /* * This routine is ONLY for resource names * Store a name at specified address. @@ -1401,7 +1406,7 @@ bool MSGSRES::print_config(POOL_MEM &buff, bool hide_sensitive_data) len = strlen(msgres->mail_cmd); cmdbuf = check_pool_memory_size(cmdbuf, len * 2); escape_string(cmdbuf, msgres->mail_cmd, len); - Mmsg(temp, " mailcommand = \"%s\"\n", cmdbuf); + Mmsg(temp, " MailCommand = \"%s\"\n", cmdbuf); pm_strcat(cfg_str, temp.c_str()); } @@ -1409,7 +1414,15 @@ bool MSGSRES::print_config(POOL_MEM &buff, bool hide_sensitive_data) len = strlen(msgres->operator_cmd); cmdbuf = check_pool_memory_size(cmdbuf, len * 2); escape_string(cmdbuf, msgres->operator_cmd, len); - Mmsg(temp, " operatorcommand = \"%s\"\n", cmdbuf); + Mmsg(temp, " OperatorCommand = \"%s\"\n", cmdbuf); + pm_strcat(cfg_str, temp.c_str()); + } + + if (msgres->timestamp_format) { + len = strlen(msgres->timestamp_format); + cmdbuf = check_pool_memory_size(cmdbuf, len * 2); + escape_string(cmdbuf, msgres->timestamp_format, len); + Mmsg(temp, " TimestampFormat = \"%s\"\n", cmdbuf); pm_strcat(cfg_str, temp.c_str()); } free_pool_memory(cmdbuf); diff --git a/src/stored/stored_conf.c b/src/stored/stored_conf.c index cfe42cf004a..889668bde9e 100644 --- a/src/stored/stored_conf.c +++ b/src/stored/stored_conf.c @@ -688,6 +688,9 @@ void free_resource(RES *sres, int type) if (res->res_msgs.operator_cmd) { free(res->res_msgs.operator_cmd); } + if (res->res_msgs.timestamp_format) { + free(res->res_msgs.timestamp_format); + } free_msgs_res((MSGSRES *)res); /* free message resource */ res = NULL; break;