diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/logger.c | 187 |
1 files changed, 128 insertions, 59 deletions
diff --git a/main/logger.c b/main/logger.c index 8c8162d71..6060b3c4d 100644 --- a/main/logger.c +++ b/main/logger.c @@ -86,6 +86,11 @@ static int display_callids; AST_THREADSTORAGE(unique_callid); +static int logger_queue_size; +static int logger_queue_limit = 1000; +static int logger_messages_discarded; +static unsigned int high_water_alert; + static enum rotatestrategy { NONE = 0, /* Do not rotate log files at all, instead rely on external mechanisms */ SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */ @@ -719,6 +724,16 @@ static int init_logger_chain(const char *altconf) fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n"); } } + if ((s = ast_variable_retrieve(cfg, "general", "logger_queue_limit"))) { + if (sscanf(s, "%30d", &logger_queue_limit) != 1) { + fprintf(stderr, "logger_queue_limit has an invalid value. Leaving at default of %d.\n", + logger_queue_limit); + } + if (logger_queue_limit < 10) { + fprintf(stderr, "logger_queue_limit must be >= 10. Setting to 10.\n"); + logger_queue_limit = 10; + } + } var = ast_variable_browse(cfg, "logfiles"); for (; var; var = var->next) { @@ -1297,6 +1312,7 @@ static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struc case CLI_GENERATE: return NULL; } + ast_cli(a->fd, "Logger queue limit: %d\n\n", logger_queue_limit); ast_cli(a->fd, FORMATL, "Channel", "Type", "Formatter", "Status"); ast_cli(a->fd, "Configuration\n"); ast_cli(a->fd, FORMATL, "-------", "----", "---------", "------"); @@ -1585,6 +1601,79 @@ static void logger_print_normal(struct logmsg *logmsg) return; } +static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message_ap(int level, + int sublevel, const char *file, int line, const char *function, ast_callid callid, + const char *fmt, va_list ap) +{ + struct logmsg *logmsg = NULL; + struct ast_str *buf = NULL; + struct ast_tm tm; + struct timeval now = ast_tvnow(); + int res = 0; + char datestring[256]; + + if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) { + return NULL; + } + + /* Build string */ + res = ast_str_set_va(&buf, BUFSIZ, fmt, ap); + + /* If the build failed, then abort and free this structure */ + if (res == AST_DYNSTR_BUILD_FAILED) { + return NULL; + } + + /* Create a new logging message */ + if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) { + return NULL; + } + + /* Copy string over */ + ast_string_field_set(logmsg, message, ast_str_buffer(buf)); + + /* Set type */ + if (level == __LOG_VERBOSE) { + logmsg->type = LOGMSG_VERBOSE; + } else { + logmsg->type = LOGMSG_NORMAL; + } + + if (display_callids && callid) { + logmsg->callid = callid; + } + + /* Create our date/time */ + ast_localtime(&now, &tm, NULL); + ast_strftime(datestring, sizeof(datestring), dateformat, &tm); + ast_string_field_set(logmsg, date, datestring); + + /* Copy over data */ + logmsg->level = level; + logmsg->sublevel = sublevel; + logmsg->line = line; + ast_string_field_set(logmsg, level_name, levels[level]); + ast_string_field_set(logmsg, file, file); + ast_string_field_set(logmsg, function, function); + logmsg->lwp = ast_get_tid(); + + return logmsg; +} + +static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message(int level, + int sublevel, const char *file, int line, const char *function, ast_callid callid, + const char *fmt, ...) +{ + struct logmsg *logmsg; + va_list ap; + + va_start(ap, fmt); + logmsg = format_log_message_ap(level, sublevel, file, line, function, callid, fmt, ap); + va_end(ap); + + return logmsg; +} + /*! \brief Actual logging thread */ static void *logger_thread(void *data) { @@ -1601,8 +1690,21 @@ static void *logger_thread(void *data) ast_cond_wait(&logcond, &logmsgs.lock); } } + + if (high_water_alert) { + msg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0, + "Logging resumed. %d message%s discarded.\n", + logger_messages_discarded, logger_messages_discarded == 1 ? "" : "s"); + if (msg) { + AST_LIST_INSERT_TAIL(&logmsgs, msg, list); + } + high_water_alert = 0; + logger_messages_discarded = 0; + } + next = AST_LIST_FIRST(&logmsgs); AST_LIST_HEAD_INIT_NOLOCK(&logmsgs); + logger_queue_size = 0; AST_LIST_UNLOCK(&logmsgs); /* Otherwise go through and process each message in the order added */ @@ -1861,79 +1963,36 @@ void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created) /*! * \brief send log messages to syslog and/or the console */ -static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap) +static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel, + const char *file, int line, const char *function, ast_callid callid, + const char *fmt, va_list ap) { struct logmsg *logmsg = NULL; - struct ast_str *buf = NULL; - struct ast_tm tm; - struct timeval now = ast_tvnow(); - int res = 0; - char datestring[256]; if (level == __LOG_VERBOSE && ast_opt_remote && ast_opt_exec) { return; } - if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) - return; - - if (level != __LOG_VERBOSE && AST_RWLIST_EMPTY(&logchannels)) { - /* - * we don't have the logger chain configured yet, - * so just log to stdout - */ - int result; - result = ast_str_set_va(&buf, BUFSIZ, fmt, ap); /* XXX BUFSIZ ? */ - if (result != AST_DYNSTR_BUILD_FAILED) { - term_filter_escapes(ast_str_buffer(buf)); - fputs(ast_str_buffer(buf), stdout); + AST_LIST_LOCK(&logmsgs); + if (logger_queue_size >= logger_queue_limit && !close_logger_thread) { + logger_messages_discarded++; + if (!high_water_alert && !close_logger_thread) { + logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0, + "Log queue threshold (%d) exceeded. Discarding new messages.\n", logger_queue_limit); + AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list); + high_water_alert = 1; + ast_cond_signal(&logcond); } + AST_LIST_UNLOCK(&logmsgs); return; } + AST_LIST_UNLOCK(&logmsgs); - /* Ignore anything that never gets logged anywhere */ - if (level != __LOG_VERBOSE && !(global_logmask & (1 << level))) - return; - - /* Build string */ - res = ast_str_set_va(&buf, BUFSIZ, fmt, ap); - - /* If the build failed, then abort and free this structure */ - if (res == AST_DYNSTR_BUILD_FAILED) + logmsg = format_log_message_ap(level, sublevel, file, line, function, callid, fmt, ap); + if (!logmsg) { return; - - /* Create a new logging message */ - if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) - return; - - /* Copy string over */ - ast_string_field_set(logmsg, message, ast_str_buffer(buf)); - - /* Set type */ - if (level == __LOG_VERBOSE) { - logmsg->type = LOGMSG_VERBOSE; - } else { - logmsg->type = LOGMSG_NORMAL; } - if (display_callids && callid) { - logmsg->callid = callid; - } - - /* Create our date/time */ - ast_localtime(&now, &tm, NULL); - ast_strftime(datestring, sizeof(datestring), dateformat, &tm); - ast_string_field_set(logmsg, date, datestring); - - /* Copy over data */ - logmsg->level = level; - logmsg->sublevel = sublevel; - logmsg->line = line; - ast_string_field_set(logmsg, level_name, levels[level]); - ast_string_field_set(logmsg, file, file); - ast_string_field_set(logmsg, function, function); - logmsg->lwp = ast_get_tid(); - /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */ if (logthread != AST_PTHREADT_NULL) { AST_LIST_LOCK(&logmsgs); @@ -1942,6 +2001,7 @@ static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int su logmsg_free(logmsg); } else { AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list); + logger_queue_size++; ast_cond_signal(&logcond); } AST_LIST_UNLOCK(&logmsgs); @@ -2300,3 +2360,12 @@ const char *ast_logger_get_dateformat(void) return dateformat; } +void ast_logger_set_queue_limit(int queue_limit) +{ + logger_queue_limit = queue_limit; +} + +int ast_logger_get_queue_limit(void) +{ + return logger_queue_limit; +} |