Asterisk - The Open Source Telephony Project GIT-master-70eff7f
Loading...
Searching...
No Matches
logger.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Asterisk Logger
22 *
23 * Logging routines
24 *
25 * \author Mark Spencer <markster@digium.com>
26 */
27
28/*! \li \ref logger.c uses the configuration file \ref logger.conf
29 * \addtogroup configuration_file Configuration Files
30 */
31
32/*!
33 * \page logger.conf logger.conf
34 * \verbinclude logger.conf.sample
35 */
36
37/*** MODULEINFO
38 <support_level>core</support_level>
39 ***/
40
41#include "asterisk.h"
42
43/* When we include logger.h again it will trample on some stuff in syslog.h, but
44 * nothing we care about in here. */
45#include <syslog.h>
46#include <signal.h>
47#include <time.h>
48#include <sys/stat.h>
49#include <fcntl.h>
50
51#include "asterisk/_private.h"
52#include "asterisk/module.h"
53#include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
54#include "asterisk/logger.h"
56#include "asterisk/lock.h"
57#include "asterisk/channel.h"
58#include "asterisk/config.h"
59#include "asterisk/term.h"
60#include "asterisk/cli.h"
61#include "asterisk/utils.h"
62#include "asterisk/manager.h"
63#include "asterisk/astobj2.h"
65#include "asterisk/strings.h"
66#include "asterisk/pbx.h"
67#include "asterisk/app.h"
68#include "asterisk/syslog.h"
69#include "asterisk/buildinfo.h"
71#include "asterisk/backtrace.h"
72#include "asterisk/json.h"
74
75static int logger_register_level(const char *name);
76static int logger_unregister_level(const char *name);
77static int logger_get_dynamic_level(const char *name);
78
79static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
80
81static char queue_log_name[256] = QUEUELOG;
82static char exec_after_rotate[256] = "";
83
85static unsigned int global_logmask = 0xFFFF;
86static int queuelog_init;
88static volatile int next_unique_callid = 1; /* Used to assign unique call_ids to calls */
89static int display_callids;
90
91AST_THREADSTORAGE(unique_callid);
92
94static int logger_queue_limit = 1000;
95static int logger_queue_over_threshold_limit = 200; /* How many specific messages (WARNING, ERROR) can go over the limit */
97static unsigned int high_water_alert;
98/* This gets set when we are at the absolute maximum number of WARNING/ERROR messages in the
99 * logger queue. This includes the logger queue threshold and the over threshold limit, which
100 * means that the queue is COMPLETELY full of WARNING/ERROR messages, so any new messages
101 * coming in will just need to be discarded, no matter what they are.
102 */
103static unsigned int discard_all_new_msgs;
104
105/* On some platforms, like those with MUSL as the runtime, BUFSIZ is
106 * unreasonably small (1024). Use a larger value in those environments.
107 */
108#define LOGMSG_SIZE MAX(BUFSIZ, 8192)
109
110static enum rotatestrategy {
111 NONE = 0, /* Do not rotate log files at all, instead rely on external mechanisms */
112 SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */
113 ROTATE = 1 << 1, /* Rotate all files, such that the oldest file has the highest suffix */
114 TIMESTAMP = 1 << 2, /* Append the epoch timestamp onto the end of the archived file */
116
117static struct {
118 unsigned int queue_log:1;
119 unsigned int queue_log_to_file:1;
122} logfiles = { 1 };
123
126
127struct logchannel;
128struct logmsg;
129
131 /* The name of the log formatter */
132 const char *name;
133 /* Pointer to the function that will format the log */
134 int (* const format_log)(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size);
135};
136
142
144 /*! How the logs sent to this channel will be formatted */
146 /*! What to log to this channel */
147 unsigned int logmask;
148 /*! If this channel is disabled or not */
150 /*! syslog facility */
152 /*! Verbosity level. (-1 if use option_verbose for the level.) */
154 /*! Type of log channel */
156 /*! logfile logging file pointer */
157 FILE *fileptr;
158 /*! Filename */
160 /*! field for linking to list */
162 /*! Line number from configuration file */
164 /*! Whether this log channel was created dynamically */
166 /*! Components (levels) from last config load */
167 char components[0];
168};
169
171
176
177struct logmsg {
179 int level;
181 int line;
182 int lwp;
184 unsigned int hidecli:1; /*!< Whether to suppress log message from CLI output (but log normally to other log channels */
191 );
193};
194
195static void logmsg_free(struct logmsg *msg)
196{
198 ast_free(msg);
199}
200
202
203/* This pointer should not be modified. It will be set if and only if the logger queue
204 * gets to a point where we need to start discarding messages to make room for new
205 * WARNING/ERROR messages. At that point, it will always point to the last logmsg that
206 * was looked at for discard, or NULL if we discarded everything we looked at, which
207 * means that we just start at the HEAD of the list for the next search.
208 */
210static pthread_t logthread = AST_PTHREADT_NULL;
212static int close_logger_thread = 0;
213
214static FILE *qlog;
215
216/*! \brief Logging channels used in the Asterisk logging system
217 *
218 * The first 16 levels are reserved for system usage, and the remaining
219 * levels are reserved for usage by dynamic levels registered via
220 * ast_logger_register_level.
221 */
222
223/* Modifications to this array are protected by the rwlock in the
224 * logchannels list.
225 */
226
227static char *levels[NUMLOGLEVELS] = {
228 "DEBUG",
229 "TRACE",
230 "NOTICE",
231 "WARNING",
232 "ERROR",
233 "VERBOSE",
234 "DTMF",
235};
236
237/*! \brief Custom dynamic logging levels added by the user
238 *
239 * The first 16 levels are reserved for system usage, and the remaining
240 * levels are reserved for usage by dynamic levels registered via
241 * ast_logger_register_level.
242 */
243
245
246/*! \brief Colors used in the console for logging */
247static const int colors[NUMLOGLEVELS] = {
249 COLOR_BRBLUE, /* no longer used */
252 COLOR_RED,
255 0,
256 0,
257 0,
258 0,
259 0,
260 0,
261 0,
262 0,
263 0,
280};
281
282AST_THREADSTORAGE(verbose_buf);
283AST_THREADSTORAGE(verbose_build_buf);
284#define VERBOSE_BUF_INIT_SIZE 256
285
287#define LOG_BUF_INIT_SIZE 256
288
289static int format_log_json(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
290{
291 struct ast_json *json;
292 char *str;
293 char call_identifier_str[13];
294 size_t json_str_len;
295
296 if (msg->callid) {
297 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
298 } else {
299 call_identifier_str[0] = '\0';
300 }
301
302 json = ast_json_pack("{s: s, s: s, "
303 "s: {s: i, s: s}, "
304 "s: {s: {s: s, s: s, s: i}, "
305 "s: s, s: s} }",
306 "hostname", ast_config_AST_SYSTEM_NAME,
307 "timestamp", msg->date,
308 "identifiers",
309 "lwp", msg->lwp,
310 "callid", S_OR(call_identifier_str, ""),
311 "logmsg",
312 "location",
313 "filename", msg->file,
314 "function", msg->function,
315 "line", msg->line,
316 "level", msg->level_name,
317 "message", msg->message);
318 if (!json) {
319 return -1;
320 }
321
323 if (!str) {
324 ast_json_unref(json);
325 return -1;
326 }
327
328 ast_copy_string(buf, str, size);
329 json_str_len = strlen(str);
330 if (json_str_len > size - 1) {
331 json_str_len = size - 1;
332 }
333 buf[json_str_len] = '\n';
334 buf[json_str_len + 1] = '\0';
335
336 term_strip(buf, buf, size);
337
339 ast_json_unref(json);
340
341 return 0;
342}
343
345 .name = "json",
346 .format_log = format_log_json
347};
348
349static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size)
350{
351 const char *p;
352 const char *fmt;
353 struct ast_str *prefixed;
354 signed char magic = logmsg->sublevel > 9 ? -10 : -logmsg->sublevel - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */
355
356 /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */
357 if (logmsg->sublevel < 0) {
358 if (!strncmp(logmsg->message, VERBOSE_PREFIX_10, strlen(VERBOSE_PREFIX_10))) {
359 magic = -11;
360 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_9, strlen(VERBOSE_PREFIX_9))) {
361 magic = -10;
362 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_8, strlen(VERBOSE_PREFIX_8))) {
363 magic = -9;
364 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_7, strlen(VERBOSE_PREFIX_7))) {
365 magic = -8;
366 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_6, strlen(VERBOSE_PREFIX_6))) {
367 magic = -7;
368 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_5, strlen(VERBOSE_PREFIX_5))) {
369 magic = -6;
370 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) {
371 magic = -5;
372 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) {
373 magic = -4;
374 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) {
375 magic = -3;
376 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) {
377 magic = -2;
378 } else {
379 magic = -1;
380 }
381 }
382
383 if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE))) {
384 return -1;
385 }
386
387 ast_str_reset(prefixed);
388
389 /* for every newline found in the buffer add verbose prefix data */
390 fmt = logmsg->message;
391 do {
392 if (!(p = strchr(fmt, '\n'))) {
393 p = strchr(fmt, '\0') - 1;
394 }
395 ++p;
396
397 ast_str_append(&prefixed, 0, "%c", (char)magic);
398 ast_str_append_substr(&prefixed, 0, fmt, p - fmt);
399 fmt = p;
400 } while (p && *p);
401
402 snprintf(buf, size, "%s", ast_str_buffer(prefixed));
403
404 return 0;
405}
406
407static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
408{
409 char call_identifier_str[13];
410
411 if (msg->callid) {
412 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
413 } else {
414 call_identifier_str[0] = '\0';
415 }
416
417 switch (chan->type) {
418 case LOGTYPE_SYSLOG:
419 snprintf(buf, size, "%s[%d]%s: %s:%d in %s: %s",
420 levels[msg->level], msg->lwp, call_identifier_str, msg->file,
421 msg->line, msg->function, msg->message);
422 term_strip(buf, buf, size);
423 break;
424 case LOGTYPE_FILE:
425 snprintf(buf, size, "[%s] %s[%d]%s %s: %s",
426 msg->date, msg->level_name, msg->lwp, call_identifier_str,
427 msg->file, msg->message);
428 term_strip(buf, buf, size);
429 break;
430 case LOGTYPE_CONSOLE:
431 {
432 char linestr[32];
433 int has_file = !ast_strlen_zero(msg->file);
434 int has_line = (msg->line > 0);
435 int has_func = !ast_strlen_zero(msg->function);
436
437 /*
438 * Verbose messages are interpreted by console channels in their own
439 * special way
440 */
441 if (msg->level == __LOG_VERBOSE) {
442 return logger_add_verbose_magic(msg, buf, size);
443 }
444
445 /* Turn the numerical line number into a string */
446 snprintf(linestr, sizeof(linestr), "%d", msg->line);
447 /* Build string to print out */
448 snprintf(buf, size, "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT "%s" COLORIZE_FMT " " COLORIZE_FMT "%s %s",
449 msg->date,
450 COLORIZE(colors[msg->level], 0, msg->level_name),
451 msg->lwp,
452 call_identifier_str,
453 COLORIZE(COLOR_BRWHITE, 0, has_file ? msg->file : ""),
454 has_file ? ":" : "",
455 COLORIZE(COLOR_BRWHITE, 0, has_line ? linestr : ""),
456 COLORIZE(COLOR_BRWHITE, 0, has_func ? msg->function : ""),
457 has_func ? ":" : "",
458 msg->message);
459 }
460 break;
461 }
462
463 return 0;
464}
465
467 .name = "default",
468 .format_log = format_log_default,
469};
470
471static int format_log_plain(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
472{
473 char call_identifier_str[13];
474 char linestr[32];
475 int has_file = !ast_strlen_zero(msg->file);
476 int has_line = (msg->line > 0);
477 int has_func = !ast_strlen_zero(msg->function);
478
479 if (msg->callid) {
480 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
481 } else {
482 call_identifier_str[0] = '\0';
483 }
484
485 switch (chan->type) {
486 case LOGTYPE_SYSLOG:
487 snprintf(buf, size, "%s[%d]%s: %s:%d in %s: %s",
488 levels[msg->level], msg->lwp, call_identifier_str, msg->file,
489 msg->line, msg->function, msg->message);
490 term_strip(buf, buf, size);
491 break;
492 case LOGTYPE_FILE:
493 case LOGTYPE_CONSOLE:
494 /* Turn the numerical line number into a string */
495 snprintf(linestr, sizeof(linestr), "%d", msg->line);
496 /* Build string to print out */
497 snprintf(buf, size, "[%s] %s[%d]%s: %s%s%s%s%s%s%s",
498 msg->date,
499 msg->level_name,
500 msg->lwp,
501 call_identifier_str,
502 has_file ? msg->file : "",
503 has_file ? ":" : "",
504 has_line ? linestr : "",
505 has_line ? " " : "",
506 has_func ? msg->function : "",
507 has_func ? ": " : "",
508 msg->message);
509 term_strip(buf, buf, size);
510 break;
511 }
512
513 return 0;
514}
515
517 .name = "plain",
518 .format_log = format_log_plain,
519};
520
521static void make_components(struct logchannel *chan)
522{
523 char *w;
524 unsigned int logmask = 0;
525 char *stringp = ast_strdupa(chan->components);
526 unsigned int x;
527 unsigned int verb_level;
528
529 /* Default to using option_verbose as the verbosity level of the logging channel. */
530 verb_level = -1;
531
532 w = strchr(stringp, '[');
533 if (w) {
534 char *end = strchr(w + 1, ']');
535 if (!end) {
536 fprintf(stderr, "Logger Warning: bad formatter definition for %s in logger.conf\n", chan->filename);
537 } else {
538 char *formatter_name = w + 1;
539
540 *end = '\0';
541 stringp = end + 1;
542
543 if (!strcasecmp(formatter_name, "json")) {
544 memcpy(&chan->formatter, &logformatter_json, sizeof(chan->formatter));
545 } else if (!strcasecmp(formatter_name, "default")) {
546 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
547 } else if (!strcasecmp(formatter_name, "plain")) {
548 memcpy(&chan->formatter, &logformatter_plain, sizeof(chan->formatter));
549 } else {
550 fprintf(stderr, "Logger Warning: Unknown formatter definition %s for %s in logger.conf; using 'default'\n",
551 formatter_name, chan->filename);
552 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
553 }
554 }
555 }
556
557 if (!chan->formatter.name) {
558 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
559 }
560
561 while ((w = strsep(&stringp, ","))) {
562 w = ast_strip(w);
563 if (ast_strlen_zero(w)) {
564 continue;
565 }
566 if (!strcmp(w, "*")) {
567 logmask = 0xFFFFFFFF;
568 } else if (!strncasecmp(w, "verbose(", 8)) {
569 if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
570 logmask |= (1 << __LOG_VERBOSE);
571 }
572 } else {
573 for (x = 0; x < ARRAY_LEN(levels); ++x) {
574 if (levels[x] && !strcasecmp(w, levels[x])) {
575 logmask |= (1 << x);
576 break;
577 }
578 }
579 }
580 }
581 if (chan->type == LOGTYPE_CONSOLE) {
582 /*
583 * Force to use the root console verbose level so if the
584 * user specified any verbose level then it does not interfere
585 * with calculating the ast_verb_sys_level value.
586 */
587 chan->verbosity = -1;
588 logmask |= (1 << __LOG_VERBOSE);
589 } else {
590 chan->verbosity = verb_level;
591 }
592 chan->logmask = logmask;
593}
594
595/*!
596 * \brief create the filename that will be used for a logger channel.
597 *
598 * \param channel The name of the logger channel
599 * \param[out] filename The filename for the logger channel
600 * \param size The size of the filename buffer
601 */
602static void make_filename(const char *channel, char *filename, size_t size)
603{
604 const char *log_dir_prefix = "";
605 const char *log_dir_separator = "";
606
607 *filename = '\0';
608
609 if (!strcasecmp(channel, "console")) {
610 return;
611 }
612
613 if (!strncasecmp(channel, "syslog", 6)) {
614 ast_copy_string(filename, channel, size);
615 return;
616 }
617
618 /* It's a filename */
619
620 if (channel[0] != '/') {
621 log_dir_prefix = ast_config_AST_LOG_DIR;
622 log_dir_separator = "/";
623 }
624
626 snprintf(filename, size, "%s%s%s.%s",
627 log_dir_prefix, log_dir_separator, channel, hostname);
628 } else {
629 snprintf(filename, size, "%s%s%s",
630 log_dir_prefix, log_dir_separator, channel);
631 }
632}
633
634/*!
635 * \brief Find a particular logger channel by name
636 *
637 * \pre logchannels list is locked
638 *
639 * \param channel The name of the logger channel to find
640 * \retval non-NULL The corresponding logger channel
641 * \retval NULL Unable to find a logger channel with that particular name
642 */
643static struct logchannel *find_logchannel(const char *channel)
644{
645 char filename[PATH_MAX];
646 struct logchannel *chan;
647
648 make_filename(channel, filename, sizeof(filename));
649
651 if (!strcmp(chan->filename, filename)) {
652 return chan;
653 }
654 }
655
656 return NULL;
657}
658
659static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno, int dynamic)
660{
661 struct logchannel *chan;
662 const char *facility;
663 struct ast_tm tm;
664 struct timeval now = ast_tvnow();
665 char datestring[256];
666
667 if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
668 return NULL;
669
670 strcpy(chan->components, components);
671 chan->lineno = lineno;
672 chan->dynamic = dynamic;
673
674 make_filename(channel, chan->filename, sizeof(chan->filename));
675
676 if (!strcasecmp(channel, "console")) {
677 chan->type = LOGTYPE_CONSOLE;
678 } else if (!strncasecmp(channel, "syslog", 6)) {
679 /*
680 * syntax is:
681 * syslog.facility => level,level,level
682 */
683 facility = strchr(channel, '.');
684 if (!facility++ || !facility) {
685 facility = "local0";
686 }
687
688 chan->facility = ast_syslog_facility(facility);
689
690 if (chan->facility < 0) {
691 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
692 ast_free(chan);
693 return NULL;
694 }
695
696 chan->type = LOGTYPE_SYSLOG;
697 openlog("asterisk", LOG_PID, chan->facility);
698 } else {
699 if (!(chan->fileptr = fopen(chan->filename, "a"))) {
700 /* Can't do real logging here since we're called with a lock
701 * so log to any attached consoles */
702 ast_console_puts_mutable("ERROR: Unable to open log file '", __LOG_ERROR);
707 ast_free(chan);
708 return NULL;
709 } else {
710 /* Create our date/time */
711 ast_localtime(&now, &tm, NULL);
712 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
713
714 fprintf(chan->fileptr, "[%s] Asterisk %s built by %s @ %s on a %s running %s on %s\n",
717 fflush(chan->fileptr);
718 }
719 chan->type = LOGTYPE_FILE;
720 }
721 make_components(chan);
722
723 return chan;
724}
725
727{
728 struct ast_config *cfg;
729 const char *s;
730 struct ast_flags config_flags = { 0 };
731
732 if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
733 return;
734 }
735
736 if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
738 }
739
741}
742
743/*!
744 * \brief Checks if level exists in array of level names
745 * \param levels Array of level names
746 * \param level Name to search for
747 * \param len Size of levels
748 *
749 * \retval 1 Found
750 * \retval 0 Not Found
751 */
752static int custom_level_still_exists(char **levels, char *level, size_t len)
753{
754 int i;
755 for (i = 0; i < len; i++) {
756 if (!strcmp(levels[i], level)) {
757 return 1;
758 }
759 }
760 return 0;
761}
762
763/*!
764 * \brief Read config, setup channels.
765 * \param altconf Alternate configuration file to read.
766 *
767 * \pre logchannels list is write locked
768 *
769 * \retval 0 Success
770 * \retval -1 No config found or Failed
771 */
772static int init_logger_chain(const char *altconf)
773{
774 struct logchannel *chan;
775 struct ast_config *cfg;
776 struct ast_variable *var;
777 const char *s;
778 struct ast_flags config_flags = { 0 };
779
780 if (!(cfg = ast_config_load2(S_OR(altconf, "logger.conf"), "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
781 cfg = NULL;
782 }
783
784 /* Set defaults */
785 hostname[0] = '\0';
786 display_callids = 1;
787 memset(&logfiles, 0, sizeof(logfiles));
788 logfiles.queue_log = 1;
789 ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
791 exec_after_rotate[0] = '\0';
793
794 /* delete our list of log channels */
795 while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
796 ast_free(chan);
797 }
798 global_logmask = 0;
799
800 errno = 0;
801 /* close syslog */
802 closelog();
803
804 /* If no config file, we're fine, set default options. */
805 if (!cfg) {
806 chan = make_logchannel("console", "error,warning,notice,verbose", 0, 0);
807 if (!chan) {
808 fprintf(stderr, "ERROR: Failed to initialize default logging\n");
809 return -1;
810 }
811
813 global_logmask |= chan->logmask;
814
815 return -1;
816 }
817
818 if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
819 if (ast_true(s)) {
820 if (gethostname(hostname, sizeof(hostname) - 1)) {
821 ast_copy_string(hostname, "unknown", sizeof(hostname));
822 fprintf(stderr, "What box has no hostname???\n");
823 }
824 }
825 }
826 if ((s = ast_variable_retrieve(cfg, "general", "display_callids"))) {
828 }
829 if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
831 }
832 if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
833 logfiles.queue_log = ast_true(s);
834 }
835 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
836 logfiles.queue_log_to_file = ast_true(s);
837 }
838 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
840 }
841 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_realtime_use_gmt"))) {
842 logfiles.queue_log_realtime_use_gmt = ast_true(s);
843 }
844 if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
846 }
847 if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
848 if (strcasecmp(s, "timestamp") == 0) {
850 } else if (strcasecmp(s, "rotate") == 0) {
852 } else if (strcasecmp(s, "sequential") == 0) {
854 } else if (strcasecmp(s, "none") == 0) {
856 } else {
857 fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
858 }
859 }
860 if ((s = ast_variable_retrieve(cfg, "general", "logger_queue_limit"))) {
861 if (sscanf(s, "%30d", &logger_queue_limit) != 1) {
862 fprintf(stderr, "logger_queue_limit has an invalid value. Leaving at default of %d.\n",
864 }
865 if (logger_queue_limit < 10) {
866 fprintf(stderr, "logger_queue_limit must be >= 10. Setting to 10.\n");
868 }
869 }
870
871 /* Custom dynamic logging levels defined by user */
872 if ((s = ast_variable_retrieve(cfg, "general", "custom_levels"))) {
873 char *customlogs = ast_strdupa(s);
874 char *logfile;
875 char *new_custom_levels[16] = { };
876 unsigned int level, new_level = 0;
877
878 /* get the custom levels we need to register or reload */
879 while ((logfile = strsep(&customlogs, ","))) {
880 new_custom_levels[new_level++] = logfile;
881 }
882
883 /* unregister existing custom levels, if they're not still
884 specified in customlogs, to make room for new levels */
885 for (level = 16; level < ARRAY_LEN(levels); level++) {
886 if (levels[level] && custom_dynamic_levels[level] &&
887 !custom_level_still_exists(new_custom_levels, levels[level], ARRAY_LEN(new_custom_levels))) {
889 custom_dynamic_levels[level] = 0;
890 }
891 }
892
893 new_level = 0;
894 while ((logfile = new_custom_levels[new_level++])) {
895 /* Lock already held, so directly register the level,
896 unless it's already registered (as during reload) */
897 if (logger_get_dynamic_level(logfile) == -1) {
898 int custom_level = logger_register_level(logfile);
899 custom_dynamic_levels[custom_level] = logfile;
900 }
901 }
902 }
903
904 var = ast_variable_browse(cfg, "logfiles");
905 for (; var; var = var->next) {
906 chan = make_logchannel(var->name, var->value, var->lineno, 0);
907 if (!chan) {
908 /* Print error message directly to the consoles since the lock is held
909 * and we don't want to unlock with the list partially built */
910 ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
913 continue;
914 }
916 global_logmask |= chan->logmask;
917 }
918
919 if (qlog) {
920 fclose(qlog);
921 qlog = NULL;
922 }
923
925
926 return 0;
927}
928
929void ast_child_verbose(int level, const char *fmt, ...)
930{
931 char *msg = NULL, *emsg = NULL, *sptr, *eptr;
932 va_list ap, aq;
933 int size;
934
935 va_start(ap, fmt);
936 va_copy(aq, ap);
937 if ((size = vsnprintf(msg, 0, fmt, ap)) < 0) {
938 va_end(ap);
939 va_end(aq);
940 return;
941 }
942 va_end(ap);
943
944 if (!(msg = ast_malloc(size + 1))) {
945 va_end(aq);
946 return;
947 }
948
949 vsnprintf(msg, size + 1, fmt, aq);
950 va_end(aq);
951
952 if (!(emsg = ast_malloc(size * 2 + 1))) {
953 ast_free(msg);
954 return;
955 }
956
957 for (sptr = msg, eptr = emsg; ; sptr++) {
958 if (*sptr == '"') {
959 *eptr++ = '\\';
960 }
961 *eptr++ = *sptr;
962 if (*sptr == '\0') {
963 break;
964 }
965 }
966 ast_free(msg);
967
968 fprintf(stdout, "verbose \"%s\" %d\n", emsg, level);
969 fflush(stdout);
970 ast_free(emsg);
971}
972
973void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
974{
975 va_list ap;
976 struct timeval tv;
977 struct ast_tm tm;
978 char qlog_msg[8192];
979 int qlog_len;
980 char time_str[30];
981
982 if (!logger_initialized) {
983 /* You are too early. We are not open yet! */
984 return;
985 }
986 if (!queuelog_init) {
987 /* We must initialize now since someone is trying to log something. */
989 }
990
991 if (ast_check_realtime("queue_log")) {
992 tv = ast_tvnow();
993 ast_localtime(&tv, &tm, logfiles.queue_log_realtime_use_gmt ? "GMT" : NULL);
994 ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
995 va_start(ap, fmt);
996 vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
997 va_end(ap);
998 if (logfiles.queue_adaptive_realtime) {
1000 AST_APP_ARG(data)[5];
1001 );
1002 AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
1003 /* Ensure fields are large enough to receive data */
1004 ast_realtime_require_field("queue_log",
1005 "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
1006 "data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
1007 "data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
1008 "data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
1009 "data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
1010 SENTINEL);
1011
1012 /* Store the log */
1013 ast_store_realtime("queue_log", "time", time_str,
1014 "callid", callid,
1015 "queuename", queuename,
1016 "agent", agent,
1017 "event", event,
1018 "data1", S_OR(args.data[0], ""),
1019 "data2", S_OR(args.data[1], ""),
1020 "data3", S_OR(args.data[2], ""),
1021 "data4", S_OR(args.data[3], ""),
1022 "data5", S_OR(args.data[4], ""),
1023 SENTINEL);
1024 } else {
1025 ast_store_realtime("queue_log", "time", time_str,
1026 "callid", callid,
1027 "queuename", queuename,
1028 "agent", agent,
1029 "event", event,
1030 "data", qlog_msg,
1031 SENTINEL);
1032 }
1033
1034 if (!logfiles.queue_log_to_file) {
1035 return;
1036 }
1037 }
1038
1039 if (qlog) {
1040 va_start(ap, fmt);
1041 qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
1042 vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
1043 va_end(ap);
1045 if (qlog) {
1046 fprintf(qlog, "%s\n", qlog_msg);
1047 fflush(qlog);
1048 }
1050 }
1051}
1052
1053static int rotate_file(const char *filename)
1054{
1055 char old[PATH_MAX];
1056 char new[PATH_MAX];
1057 int x, y, which, found, res = 0, fd;
1058 char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
1059
1060 switch (rotatestrategy) {
1061 case NONE:
1062 /* No rotation */
1063 break;
1064 case SEQUENTIAL:
1065 for (x = 0; ; x++) {
1066 snprintf(new, sizeof(new), "%s.%d", filename, x);
1067 fd = open(new, O_RDONLY);
1068 if (fd > -1)
1069 close(fd);
1070 else
1071 break;
1072 }
1073 if (rename(filename, new)) {
1074 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
1075 res = -1;
1076 } else {
1077 filename = new;
1078 }
1079 break;
1080 case TIMESTAMP:
1081 snprintf(new, sizeof(new), "%s.%ld", filename, (long)time(NULL));
1082 if (rename(filename, new)) {
1083 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
1084 res = -1;
1085 } else {
1086 filename = new;
1087 }
1088 break;
1089 case ROTATE:
1090 /* Find the next empty slot, including a possible suffix */
1091 for (x = 0; ; x++) {
1092 found = 0;
1093 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
1094 snprintf(new, sizeof(new), "%s.%d%s", filename, x, suffixes[which]);
1095 fd = open(new, O_RDONLY);
1096 if (fd > -1) {
1097 close(fd);
1098 found = 1;
1099 break;
1100 }
1101 }
1102 if (!found) {
1103 break;
1104 }
1105 }
1106
1107 /* Found an empty slot */
1108 for (y = x; y > 0; y--) {
1109 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
1110 snprintf(old, sizeof(old), "%s.%d%s", filename, y - 1, suffixes[which]);
1111 fd = open(old, O_RDONLY);
1112 if (fd > -1) {
1113 /* Found the right suffix */
1114 close(fd);
1115 snprintf(new, sizeof(new), "%s.%d%s", filename, y, suffixes[which]);
1116 if (rename(old, new)) {
1117 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
1118 res = -1;
1119 }
1120 break;
1121 }
1122 }
1123 }
1124
1125 /* Finally, rename the current file */
1126 snprintf(new, sizeof(new), "%s.0", filename);
1127 if (rename(filename, new)) {
1128 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
1129 res = -1;
1130 } else {
1131 filename = new;
1132 }
1133 }
1134
1137 char buf[512];
1138
1139 pbx_builtin_setvar_helper(c, "filename", filename);
1141 if (c) {
1143 }
1144 if (ast_safe_system(buf) == -1) {
1145 ast_log(LOG_WARNING, "error executing '%s'\n", buf);
1146 }
1147 }
1148 return res;
1149}
1150
1151/*!
1152 * \internal
1153 * \brief Start the realtime queue logging if configured.
1154 *
1155 * \retval TRUE if not to open queue log file.
1156 */
1158{
1159 if (ast_check_realtime("queue_log")) {
1160 if (!ast_realtime_require_field("queue_log",
1161 "time", RQ_DATETIME, 26,
1162 "data1", RQ_CHAR, 20,
1163 "data2", RQ_CHAR, 20,
1164 "data3", RQ_CHAR, 20,
1165 "data4", RQ_CHAR, 20,
1166 "data5", RQ_CHAR, 20,
1167 SENTINEL)) {
1168 logfiles.queue_adaptive_realtime = 1;
1169 } else {
1170 logfiles.queue_adaptive_realtime = 0;
1171 }
1172
1173 if (!logfiles.queue_log_to_file) {
1174 /* Don't open the log file. */
1175 return 1;
1176 }
1177 }
1178 return 0;
1179}
1180
1181/*!
1182 * \internal
1183 * \brief Rotate the queue log file and restart.
1184 *
1185 * \param queue_rotate Log queue rotation mode.
1186 *
1187 * \note Assumes logchannels is write locked on entry.
1188 *
1189 * \retval 0 on success.
1190 * \retval -1 on error.
1191 */
1192static int logger_queue_restart(int queue_rotate)
1193{
1194 int res = 0;
1195 char qfname[PATH_MAX];
1196
1197 if (logger_queue_rt_start()) {
1198 return res;
1199 }
1200
1201 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
1202 if (qlog) {
1203 /* Just in case it was still open. */
1204 fclose(qlog);
1205 qlog = NULL;
1206 }
1207 if (queue_rotate) {
1208 rotate_file(qfname);
1209 }
1210
1211 /* Open the log file. */
1212 qlog = fopen(qfname, "a");
1213 if (!qlog) {
1214 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
1215 res = -1;
1216 }
1217 return res;
1218}
1219
1220static int reload_logger(int rotate, const char *altconf)
1221{
1222 int queue_rotate = rotate;
1223 struct logchannel *f;
1224 int res = 0;
1225
1227
1228 if (qlog) {
1229 if (rotate < 0) {
1230 /* Check filesize - this one typically doesn't need an auto-rotate */
1231 if (ftello(qlog) > 0x40000000) { /* Arbitrarily, 1 GB */
1232 fclose(qlog);
1233 qlog = NULL;
1234 } else {
1235 queue_rotate = 0;
1236 }
1237 } else {
1238 fclose(qlog);
1239 qlog = NULL;
1240 }
1241 } else {
1242 queue_rotate = 0;
1243 }
1244
1246
1248 if (f->disabled) {
1249 f->disabled = 0; /* Re-enable logging at reload */
1250 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
1251 }
1252 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1253 int rotate_this = 0;
1254 if (rotatestrategy != NONE && ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
1255 /* Be more proactive about rotating massive log files */
1256 rotate_this = 1;
1257 }
1258 fclose(f->fileptr); /* Close file */
1259 f->fileptr = NULL;
1260 if (rotate || rotate_this) {
1262 }
1263 }
1264 }
1265
1267
1268 init_logger_chain(altconf);
1269
1270 ast_unload_realtime("queue_log");
1271 if (logfiles.queue_log) {
1272 res = logger_queue_restart(queue_rotate);
1275 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
1276 ast_verb(1, "Asterisk Queue Logger restarted\n");
1277 } else {
1280 }
1281
1282 return res;
1283}
1284
1285static char *handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1286{
1287 switch (cmd) {
1288 case CLI_INIT:
1289 e->command = "logger reload";
1290 e->usage =
1291 "Usage: logger reload [<alt-conf>]\n"
1292 " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
1293 return NULL;
1294 case CLI_GENERATE:
1295 return NULL;
1296 }
1297 if (reload_logger(0, a->argc == 3 ? a->argv[2] : NULL)) {
1298 ast_cli(a->fd, "Failed to reload the logger\n");
1299 return CLI_FAILURE;
1300 }
1301 return CLI_SUCCESS;
1302}
1303
1304static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1305{
1306 switch (cmd) {
1307 case CLI_INIT:
1308 e->command = "logger rotate";
1309 e->usage =
1310 "Usage: logger rotate\n"
1311 " Rotates and Reopens the log files.\n";
1312 return NULL;
1313 case CLI_GENERATE:
1314 return NULL;
1315 }
1316 if (reload_logger(1, NULL)) {
1317 ast_cli(a->fd, "Failed to reload the logger and rotate log files\n");
1318 return CLI_FAILURE;
1319 }
1320 return CLI_SUCCESS;
1321}
1322
1324{
1325 return reload_logger(1, NULL);
1326}
1327
1328int ast_logger_rotate_channel(const char *log_channel)
1329{
1330 struct logchannel *f;
1331 int success = AST_LOGGER_FAILURE;
1332 char filename[PATH_MAX];
1333
1334 make_filename(log_channel, filename, sizeof(filename));
1335
1337
1339
1341 if (f->disabled) {
1342 f->disabled = 0; /* Re-enable logging at reload */
1343 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n",
1344 f->filename);
1345 }
1346 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1347 fclose(f->fileptr); /* Close file */
1348 f->fileptr = NULL;
1349 if (strcmp(filename, f->filename) == 0) {
1351 success = AST_LOGGER_SUCCESS;
1352 }
1353 }
1354 }
1355
1357
1359
1360 return success;
1361}
1362
1363static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1364{
1365 int x;
1366 int state;
1367 int level = -1;
1368
1369 switch (cmd) {
1370 case CLI_INIT:
1371 e->command = "logger set level {DEBUG|TRACE|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";
1372 e->usage =
1373 "Usage: logger set level {DEBUG|TRACE|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"
1374 " Set a specific log level to enabled/disabled for this console.\n";
1375 return NULL;
1376 case CLI_GENERATE:
1377 return NULL;
1378 }
1379
1380 if (a->argc < 5)
1381 return CLI_SHOWUSAGE;
1382
1384
1385 for (x = 0; x < ARRAY_LEN(levels); x++) {
1386 if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
1387 level = x;
1388 break;
1389 }
1390 }
1391
1393
1394 state = ast_true(a->argv[4]) ? 1 : 0;
1395
1396 if (level != -1) {
1397 ast_console_toggle_loglevel(a->fd, level, state);
1398 ast_cli(a->fd, "Logger status for '%s' has been set to '%s'.\n", levels[level], state ? "on" : "off");
1399 } else
1400 return CLI_SHOWUSAGE;
1401
1402 return CLI_SUCCESS;
1403}
1404
1405int ast_logger_get_channels(int (*logentry)(const char *channel, const char *type,
1406 const char *status, const char *configuration, void *data), void *data)
1407{
1408 struct logchannel *chan;
1409 struct ast_str *configs = ast_str_create(64);
1410 int res = AST_LOGGER_SUCCESS;
1411
1412 if (!configs) {
1414 }
1415
1417 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
1418 unsigned int level;
1419
1421
1422 for (level = 0; level < ARRAY_LEN(levels); level++) {
1423 if ((chan->logmask & (1 << level)) && levels[level]) {
1424 ast_str_append(&configs, 0, "%s ", levels[level]);
1425 }
1426 }
1427
1428 res = logentry(chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" :
1429 (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"), chan->disabled ?
1430 "Disabled" : "Enabled", ast_str_buffer(configs), data);
1431
1432 if (res) {
1435 configs = NULL;
1436 return AST_LOGGER_FAILURE;
1437 }
1438 }
1440
1442 configs = NULL;
1443
1444 return AST_LOGGER_SUCCESS;
1445}
1446
1447/*! \brief CLI command to show logging system configuration */
1448static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1449{
1450#define FORMATL "%-35.35s %-8.8s %-10.10s %-9.9s "
1451 struct logchannel *chan;
1452 switch (cmd) {
1453 case CLI_INIT:
1454 e->command = "logger show channels";
1455 e->usage =
1456 "Usage: logger show channels\n"
1457 " List configured logger channels.\n";
1458 return NULL;
1459 case CLI_GENERATE:
1460 return NULL;
1461 }
1462 ast_cli(a->fd, "Logger queue limit: %d\n\n", logger_queue_limit);
1463 ast_cli(a->fd, FORMATL, "Channel", "Type", "Formatter", "Status");
1464 ast_cli(a->fd, "Configuration\n");
1465 ast_cli(a->fd, FORMATL, "-------", "----", "---------", "------");
1466 ast_cli(a->fd, "-------------\n");
1469 unsigned int level;
1470
1471 ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
1472 chan->formatter.name,
1473 chan->disabled ? "Disabled" : "Enabled");
1474 ast_cli(a->fd, " - ");
1475 for (level = 0; level < ARRAY_LEN(levels); level++) {
1476 if ((chan->logmask & (1 << level)) && levels[level]) {
1477 ast_cli(a->fd, "%s ", levels[level]);
1478 }
1479 }
1480 ast_cli(a->fd, "\n");
1481 }
1483 ast_cli(a->fd, "\n");
1484
1485 return CLI_SUCCESS;
1486}
1487
1488/*! \brief CLI command to show logging levels */
1489static char *handle_logger_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1490{
1491#define FORMATL2 "%5s %s\n"
1492 unsigned int level;
1493 switch (cmd) {
1494 case CLI_INIT:
1495 e->command = "logger show levels";
1496 e->usage =
1497 "Usage: logger show levels\n"
1498 " List configured logger levels.\n";
1499 return NULL;
1500 case CLI_GENERATE:
1501 return NULL;
1502 }
1503 ast_cli(a->fd, FORMATL2, "Level", "Name");
1504 ast_cli(a->fd, FORMATL2, "-----", "----");
1506 for (level = 0; level < ARRAY_LEN(levels); level++) {
1507 if (levels[level]) {
1508 ast_cli(a->fd, "%5d %s\n", level, levels[level]);
1509 }
1510 }
1512 ast_cli(a->fd, "\n");
1513
1514 return CLI_SUCCESS;
1515}
1516
1517int ast_logger_create_channel(const char *log_channel, const char *components)
1518{
1519 struct logchannel *chan;
1520
1522 return AST_LOGGER_DECLINE;
1523 }
1524
1526
1527 chan = find_logchannel(log_channel);
1528 if (chan) {
1530 return AST_LOGGER_FAILURE;
1531 }
1532
1533 chan = make_logchannel(log_channel, components, 0, 1);
1534 if (!chan) {
1537 }
1538
1540 global_logmask |= chan->logmask;
1541
1543
1544 return AST_LOGGER_SUCCESS;
1545}
1546
1547static char *handle_logger_add_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1548{
1549 switch (cmd) {
1550 case CLI_INIT:
1551 e->command = "logger add channel";
1552 e->usage =
1553 "Usage: logger add channel <name> <levels>\n"
1554 " Adds a temporary logger channel. This logger channel\n"
1555 " will exist until removed or until Asterisk is restarted.\n"
1556 " <levels> is a comma-separated list of desired logger\n"
1557 " levels such as: verbose,warning,error\n"
1558 " An optional formatter may be specified with the levels;\n"
1559 " valid values are '[json]' and '[default]'.\n";
1560 return NULL;
1561 case CLI_GENERATE:
1562 return NULL;
1563 }
1564
1565 if (a->argc < 5) {
1566 return CLI_SHOWUSAGE;
1567 }
1568
1569 switch (ast_logger_create_channel(a->argv[3], a->argv[4])) {
1570 case AST_LOGGER_SUCCESS:
1571 return CLI_SUCCESS;
1572 case AST_LOGGER_FAILURE:
1573 ast_cli(a->fd, "Logger channel '%s' already exists\n", a->argv[3]);
1574 return CLI_SUCCESS;
1575 case AST_LOGGER_DECLINE:
1577 default:
1578 ast_cli(a->fd, "ERROR: Unable to create log channel '%s'\n", a->argv[3]);
1579 return CLI_FAILURE;
1580 }
1581}
1582
1583int ast_logger_remove_channel(const char *log_channel)
1584{
1585 struct logchannel *chan;
1586
1588
1589 chan = find_logchannel(log_channel);
1590 if (chan && chan->dynamic) {
1592 } else {
1594 return AST_LOGGER_FAILURE;
1595 }
1597
1598 if (chan->fileptr) {
1599 fclose(chan->fileptr);
1600 chan->fileptr = NULL;
1601 }
1602 ast_free(chan);
1603 chan = NULL;
1604
1605 return AST_LOGGER_SUCCESS;
1606}
1607
1608static char *handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1609{
1610 struct logchannel *chan;
1611 int gen_count = 0;
1612 char *gen_ret = NULL;
1613
1614 switch (cmd) {
1615 case CLI_INIT:
1616 e->command = "logger remove channel";
1617 e->usage =
1618 "Usage: logger remove channel <name>\n"
1619 " Removes a temporary logger channel.\n";
1620 return NULL;
1621 case CLI_GENERATE:
1622 if (a->argc > 4 || (a->argc == 4 && a->pos > 3)) {
1623 return NULL;
1624 }
1627 if (chan->dynamic && (ast_strlen_zero(a->argv[3])
1628 || !strncmp(a->argv[3], chan->filename, strlen(a->argv[3])))) {
1629 if (gen_count == a->n) {
1630 gen_ret = ast_strdup(chan->filename);
1631 break;
1632 }
1633 gen_count++;
1634 }
1635 }
1637 return gen_ret;
1638 }
1639
1640 if (a->argc < 4) {
1641 return CLI_SHOWUSAGE;
1642 }
1643
1644 switch (ast_logger_remove_channel(a->argv[3])) {
1645 case AST_LOGGER_SUCCESS:
1646 ast_cli(a->fd, "Removed dynamic logger channel '%s'\n", a->argv[3]);
1647 return CLI_SUCCESS;
1648 case AST_LOGGER_FAILURE:
1649 ast_cli(a->fd, "Unable to find dynamic logger channel '%s'\n", a->argv[3]);
1650 return CLI_SUCCESS;
1651 default:
1652 ast_cli(a->fd, "Internal failure attempting to delete dynamic logger channel '%s'\n", a->argv[3]);
1653 return CLI_FAILURE;
1654 }
1655}
1656
1657/* Call ID filtering */
1658
1659AST_THREADSTORAGE(callid_group_name);
1660
1661/*! \brief map call ID to group */
1666
1668
1669static int callid_filtering = 0;
1670
1671static const char *get_callid_group(void)
1672{
1673 char **callid_group;
1674 callid_group = ast_threadstorage_get(&callid_group_name, sizeof(*callid_group));
1675 return callid_group ? *callid_group : NULL;
1676}
1677
1678static int callid_set_chanloggroup(const char *group)
1679{
1680 /* Use threadstorage for constant time access, rather than a linked list */
1681 ast_callid callid;
1682 char **callid_group;
1683
1685 if (!callid) {
1686 /* Should never be called on non-PBX threads */
1687 ast_assert(0);
1688 return -1;
1689 }
1690
1691 callid_group = ast_threadstorage_get(&callid_group_name, sizeof(*callid_group));
1692
1693 if (!group) {
1694 /* Remove from list */
1695 if (!*callid_group) {
1696 return 0; /* Wasn't in any group to begin with */
1697 }
1698 ast_free(*callid_group);
1699 return 0; /* Set Call ID group for the first time */
1700 }
1701 /* Existing group */
1702 ast_free(*callid_group);
1703 *callid_group = ast_strdup(group);
1704 if (!*callid_group) {
1705 return -1;
1706 }
1707 return 0; /* Set Call ID group for the first time */
1708}
1709
1711{
1712 int i = 0;
1713 struct chan_group_lock *cgl;
1714
1717 ast_free(cgl);
1718 i++;
1719 }
1720 callid_filtering = 0;
1722 return i;
1723}
1724
1725static int callid_group_set_filter(const char *group, int enabled)
1726{
1727 struct chan_group_lock *cgl;
1728
1731 if (!strcmp(group, cgl->name)) {
1732 if (!enabled) {
1734 ast_free(cgl);
1735 }
1736 break;
1737 }
1738 }
1740
1741 if (!enabled) {
1743 callid_filtering = 0;
1744 }
1746 return 0;
1747 }
1748
1749 if (!cgl) {
1750 cgl = ast_calloc(1, sizeof(*cgl) + strlen(group) + 1);
1751 if (!cgl) {
1753 return -1;
1754 }
1755 strcpy(cgl->name, group); /* Safe */
1757 } /* else, already existed, and was already enabled, no change */
1758 callid_filtering = 1;
1760 return 0;
1761}
1762
1764{
1765 struct chan_group_lock *cgl;
1766 const char *callidgroup;
1767
1768 if (!callid_filtering) {
1769 return 1; /* Everything enabled by default, if no filtering */
1770 }
1771
1772 callidgroup = get_callid_group();
1773 if (!callidgroup) {
1774 return 0; /* Filtering, but no call group, not enabled */
1775 }
1776
1779 if (!strcmp(callidgroup, cgl->name)) {
1780 break;
1781 }
1782 }
1784 return cgl ? 1 : 0; /* If found, enabled, otherwise not */
1785}
1786
1787static int log_group_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1788{
1789 int res = callid_set_chanloggroup(value);
1790 if (res) {
1791 ast_log(LOG_ERROR, "Failed to set channel log group for %s\n", ast_channel_name(chan));
1792 return -1;
1793 }
1794 return 0;
1795}
1796
1798 .name = "LOG_GROUP",
1799 .write = log_group_write,
1800};
1801
1802static char *handle_logger_chanloggroup_filter(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1803{
1804 int enabled;
1805
1806 switch (cmd) {
1807 case CLI_INIT:
1808 e->command = "logger filter changroup";
1809 e->usage =
1810 "Usage: logger filter changroup <group> {on|off}\n"
1811 " Add or remove channel groups from log filtering.\n"
1812 " If filtering is active, only channels assigned\n"
1813 " to a group that has been enabled using this command\n"
1814 " will have execution shown in the CLI.\n";
1815 return NULL;
1816 case CLI_GENERATE:
1817 return NULL;
1818 }
1819
1820 if (a->argc < 5) {
1821 return CLI_SHOWUSAGE;
1822 }
1823
1824 enabled = ast_true(a->argv[4]) ? 1 : 0;
1825 if (callid_group_set_filter(a->argv[3], enabled)) {
1826 ast_cli(a->fd, "Failed to set channel group filter for group %s\n", a->argv[3]);
1827 return CLI_FAILURE;
1828 }
1829
1830 ast_cli(a->fd, "Logging of channel group '%s' is now %s\n", a->argv[3], enabled ? "enabled" : "disabled");
1831 return CLI_SUCCESS;
1832}
1833
1834static char *handle_logger_filter_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1835{
1836 int i = 0;
1837 struct chan_group_lock *cgl;
1838
1839 switch (cmd) {
1840 case CLI_INIT:
1841 e->command = "logger filter show";
1842 e->usage =
1843 "Usage: logger filter show\n"
1844 " Show current logger filtering settings.\n";
1845 return NULL;
1846 case CLI_GENERATE:
1847 return NULL;
1848 }
1849
1852 ast_cli(a->fd, "%3d %-32s\n", ++i, cgl->name);
1853 }
1855
1856 if (i) {
1857 ast_cli(a->fd, "%d channel group%s currently enabled\n", i, ESS(i));
1858 } else {
1859 ast_cli(a->fd, "No filtering currently active\n");
1860 }
1861 return CLI_SUCCESS;
1862}
1863
1864static char *handle_logger_filter_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1865{
1866 int removed;
1867
1868 switch (cmd) {
1869 case CLI_INIT:
1870 e->command = "logger filter reset";
1871 e->usage =
1872 "Usage: logger filter reset\n"
1873 " Reset the logger filter.\n"
1874 " This removes any channel groups from filtering\n"
1875 " (all channel execution will be shown)\n";
1876 return NULL;
1877 case CLI_GENERATE:
1878 return NULL;
1879 }
1880
1881 removed = callid_group_remove_filters();
1882
1883 ast_cli(a->fd, "Log filtering has been reset (%d filter%s removed)\n", removed, ESS(removed));
1884 return CLI_SUCCESS;
1885}
1886
1887static struct ast_cli_entry cli_logger[] = {
1888 AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),
1889 AST_CLI_DEFINE(handle_logger_show_levels, "List configured log levels"),
1890 AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
1891 AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
1892 AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),
1893 AST_CLI_DEFINE(handle_logger_add_channel, "Adds a new logging channel"),
1894 AST_CLI_DEFINE(handle_logger_remove_channel, "Removes a logging channel"),
1895 AST_CLI_DEFINE(handle_logger_chanloggroup_filter, "Filter PBX logs by channel log group"),
1896 AST_CLI_DEFINE(handle_logger_filter_show, "Show current PBX channel filtering"),
1897 AST_CLI_DEFINE(handle_logger_filter_reset, "Reset PBX channel filtering"),
1898};
1899
1900static void _handle_SIGXFSZ(int sig)
1901{
1902 /* Indicate need to reload */
1904}
1905
1906static struct sigaction handle_SIGXFSZ = {
1907 .sa_handler = _handle_SIGXFSZ,
1908 .sa_flags = SA_RESTART,
1909};
1910
1911/*! \brief Print a normal log message to the channels */
1913{
1914 struct logchannel *chan = NULL;
1915 char buf[LOGMSG_SIZE];
1916 int level = 0;
1917
1921
1922 /* If the channel is disabled, then move on to the next one */
1923 if (chan->disabled) {
1924 continue;
1925 }
1926 if (logmsg->level == __LOG_VERBOSE
1927 && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
1928 continue;
1929 }
1930
1931 if (!(chan->logmask & (1 << logmsg->level))) {
1932 continue;
1933 }
1934
1935 switch (chan->type) {
1936 case LOGTYPE_SYSLOG:
1937 {
1938 int syslog_level = ast_syslog_priority_from_loglevel(logmsg->level);
1939
1940 if (syslog_level < 0) {
1941 /* we are locked here, so cannot ast_log() */
1942 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", logmsg->level);
1943 continue;
1944 }
1945
1946 /* Don't use LOG_MAKEPRI because it's broken in glibc<2.17 */
1947 syslog_level = chan->facility | syslog_level; /* LOG_MAKEPRI(chan->facility, syslog_level); */
1948 if (!chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) {
1949 syslog(syslog_level, "%s", buf);
1950 }
1951 }
1952 break;
1953 case LOGTYPE_CONSOLE:
1954 if (!logmsg->hidecli && !chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) {
1956 }
1957 break;
1958 case LOGTYPE_FILE:
1959 {
1960 int res = 0;
1961
1962 if (!chan->fileptr) {
1963 continue;
1964 }
1965
1966 if (chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) {
1967 continue;
1968 }
1969
1970 /* Print out to the file */
1971 res = fprintf(chan->fileptr, "%s", buf);
1972 if (res > 0) {
1973 fflush(chan->fileptr);
1974 } else if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
1975 fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
1976 if (errno == ENOMEM || errno == ENOSPC) {
1977 fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
1978 } else {
1979 fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
1980 }
1981
1982 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
1983 chan->disabled = 1;
1984 }
1985 }
1986 break;
1987 }
1988 }
1989 } else if (logmsg->level != __LOG_VERBOSE || option_verbose >= logmsg->sublevel) {
1990 fputs(logmsg->message, stdout);
1991 }
1992
1994
1995 /* If we need to reload because of the file size, then do so */
1997 reload_logger(-1, NULL);
1998 ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
1999 }
2000
2001 return;
2002}
2003
2004static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message_ap(int level,
2005 int sublevel, const char *file, int line, const char *function, ast_callid callid,
2006 const char *fmt, va_list ap)
2007{
2008 struct logmsg *logmsg = NULL;
2009 struct ast_str *buf = NULL;
2010 struct ast_tm tm;
2011 struct timeval now = ast_tvnow();
2012 int res = 0;
2013 char datestring[256];
2014
2015 if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) {
2016 return NULL;
2017 }
2018
2019 /* Build string */
2020 res = ast_str_set_va(&buf, LOGMSG_SIZE, fmt, ap);
2021
2022 /* If the build failed, then abort and free this structure */
2023 if (res == AST_DYNSTR_BUILD_FAILED) {
2024 return NULL;
2025 }
2026
2027 /* Automatically add a newline to format strings that don't have one */
2028 if (!ast_ends_with(ast_str_buffer(buf), "\n")) {
2029 ast_str_append(&buf, 0, "\n");
2030 }
2031
2032 /* Create a new logging message */
2033 if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) {
2034 return NULL;
2035 }
2036
2037 /* Copy string over */
2039
2040 /* Set type */
2041 if (level == __LOG_VERBOSE) {
2043 } else {
2045 }
2046
2047 if (display_callids && callid) {
2048 logmsg->callid = callid;
2049 }
2050
2051 /* Create our date/time */
2052 ast_localtime(&now, &tm, NULL);
2053 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
2054 ast_string_field_set(logmsg, date, datestring);
2055
2056 /* Copy over data */
2057 logmsg->level = level;
2058 logmsg->sublevel = sublevel;
2059 logmsg->line = line;
2060 ast_string_field_set(logmsg, level_name, levels[level]);
2061 ast_string_field_set(logmsg, file, file);
2062 ast_string_field_set(logmsg, function, function);
2063 logmsg->lwp = ast_get_tid();
2064
2065 return logmsg;
2066}
2067
2068static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message(int level,
2069 int sublevel, const char *file, int line, const char *function, ast_callid callid,
2070 const char *fmt, ...)
2071{
2072 struct logmsg *logmsg;
2073 va_list ap;
2074
2075 va_start(ap, fmt);
2077 va_end(ap);
2078
2079 return logmsg;
2080}
2081
2082/*! \brief Actual logging thread */
2083static void *logger_thread(void *data)
2084{
2085 struct logmsg *next = NULL, *msg = NULL;
2086
2087 for (;;) {
2088 /* We lock the message list, and see if any message exists... if not we wait on the condition to be signalled */
2090 if (AST_DLLIST_EMPTY(&logmsgs)) {
2091 if (close_logger_thread) {
2093 break;
2094 } else {
2096 }
2097 }
2098
2099 if (high_water_alert) {
2100 msg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
2101 "Logging resumed. %d message%s discarded.\n",
2103 if (msg) {
2105 }
2106 high_water_alert = 0;
2108 }
2109
2112
2113 next = AST_DLLIST_FIRST(&logmsgs);
2117
2118 /* Otherwise go through and process each message in the order added */
2119 while ((msg = next)) {
2120 /* Get the next entry now so that we can free our current structure later */
2121 next = AST_DLLIST_NEXT(msg, list);
2122
2123 /* Depending on the type, send it to the proper function */
2125
2126 /* Free the data since we are done */
2127 logmsg_free(msg);
2128 }
2129 }
2130
2131 return NULL;
2132}
2133
2134/*!
2135 * \internal
2136 * \brief Initialize the logger queue.
2137 *
2138 * \note Assumes logchannels is write locked on entry.
2139 */
2140static void logger_queue_init(void)
2141{
2142 ast_unload_realtime("queue_log");
2143 if (logfiles.queue_log) {
2144 char qfname[PATH_MAX];
2145
2146 if (logger_queue_rt_start()) {
2147 return;
2148 }
2149
2150 /* Open the log file. */
2151 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR,
2153 if (qlog) {
2154 /* Just in case it was already open. */
2155 fclose(qlog);
2156 }
2157 qlog = fopen(qfname, "a");
2158 if (!qlog) {
2159 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
2160 }
2161 }
2162}
2163
2165{
2166 return logger_initialized;
2167}
2168
2169/*!
2170 * \brief Start the ast_queue_log() logger.
2171 *
2172 * \note Called when the system is fully booted after startup
2173 * so preloaded realtime modules can get up.
2174 */
2176{
2177 /* Must not be called before the logger is initialized. */
2179
2181 if (!queuelog_init) {
2183 queuelog_init = 1;
2185 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
2186 } else {
2188 }
2189}
2190
2192{
2193 int res;
2194 /* auto rotate if sig SIGXFSZ comes a-knockin */
2195 sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
2196
2197 /* Re-initialize the logmsgs mutex. The recursive mutex can be accessed prior
2198 * to Asterisk being forked into the background, which can cause the thread
2199 * ID tracked by the underlying pthread mutex to be different than the ID of
2200 * the thread that unlocks the mutex. Since init_logger is called after the
2201 * fork, it is safe to initialize the mutex here for future accesses.
2202 */
2206
2207 /* start logger thread */
2210 return -1;
2211 }
2212
2213 /* register the logger cli commands */
2216
2218
2219 /* create log channels */
2221 res = init_logger_chain(NULL);
2225 if (res) {
2226 ast_log(LOG_ERROR, "Errors detected in logger.conf. Default console logging is being used.\n");
2227 }
2228
2230
2231 return 0;
2232}
2233
2235{
2236 struct logchannel *f = NULL;
2237
2239
2242
2244
2245 /* Stop logger thread */
2250
2252 pthread_join(logthread, NULL);
2253 }
2254
2256
2257 if (qlog) {
2258 fclose(qlog);
2259 qlog = NULL;
2260 }
2261
2262 while ((f = AST_LIST_REMOVE_HEAD(&logchannels, list))) {
2263 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
2264 fclose(f->fileptr);
2265 f->fileptr = NULL;
2266 }
2267 ast_free(f);
2268 }
2269
2271
2272 closelog(); /* syslog */
2273
2275}
2276
2277void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid)
2278{
2279 snprintf(buffer, buffer_size, "[C-%08x]", callid);
2280}
2281
2286
2288{
2289 ast_callid *callid;
2290
2291 callid = ast_threadstorage_get(&unique_callid, sizeof(*callid));
2292
2293 return callid ? *callid : 0;
2294}
2295
2297{
2298 ast_callid *id = ast_threadstorage_get(&unique_callid, sizeof(*id));
2299
2300 if (!id) {
2301 return -1;
2302 }
2303
2304 *id = callid;
2305
2306 return 0;
2307}
2308
2310{
2311 ast_callid *pointing;
2312
2313 pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
2314 if (!pointing) {
2315 return -1;
2316 }
2317
2318 if (*pointing) {
2319 ast_log(LOG_ERROR, "ast_callid_threadassoc_add(C-%08x) on thread "
2320 "already associated with callid [C-%08x].\n", callid, *pointing);
2321 return 1;
2322 }
2323
2324 *pointing = callid;
2325 return 0;
2326}
2327
2329{
2330 ast_callid *pointing;
2331
2332 pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
2333 if (!pointing) {
2334 return -1;
2335 }
2336
2337 if (*pointing) {
2338 *pointing = 0;
2339 return 0;
2340 }
2341
2342 return -1;
2343}
2344
2346{
2347 ast_callid tmp;
2348
2349 /* Start by trying to see if a callid is available from thread storage */
2351 if (tmp) {
2352 *callid = tmp;
2353 return 0;
2354 }
2355
2356 /* If that failed, try to create a new one and bind it. */
2357 *callid = ast_create_callid();
2358 if (*callid) {
2360 return 1;
2361 }
2362
2363 /* If neither worked, then something must have gone wrong. */
2364 return -1;
2365}
2366
2367void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created)
2368{
2369 if (callid && callid_created) {
2370 /* If the callid was created rather than simply grabbed from the thread storage, we need to unbind here. */
2372 }
2373}
2374
2375/*!
2376 * \internal
2377 * \brief Flush the oldest non-warning/error log messages out of the queue
2378 *
2379 * \pre The log messages list is locked
2380 *
2381 * \param start A pointer to the logmsg to start at
2382 * \param amount The number of messages to flush
2383 *
2384 * \retval A pointer to the last WARNING / ERROR message checked (NULL otherwise)
2385 */
2386static struct logmsg *flush_logger_queue_messages(struct logmsg *start, int amount)
2387{
2388 struct logmsg *current, *previous;
2389 int flushed = 0;
2390
2391 previous = NULL;
2392 current = start;
2393
2394 while (current) {
2395 struct logmsg *next;
2396
2397 if (current->level == __LOG_WARNING || current->level == __LOG_ERROR) {
2398 previous = current;
2400 continue;
2401 }
2402
2403 next = AST_DLLIST_NEXT(current, list);
2406 current = next;
2408 flushed++;
2409
2410 if (flushed >= amount) {
2411 break;
2412 }
2413 }
2414
2415 return previous;
2416}
2417
2418/*!
2419 * \brief send log messages to syslog and/or the console
2420 */
2421static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel,
2422 const char *file, int line, const char *function, ast_callid callid,
2423 const char *fmt, va_list ap)
2424{
2425 int hidecli = 0;
2426 struct logmsg *logmsg = NULL;
2427
2429 return;
2430 }
2431
2433 switch (level) {
2434 case __LOG_VERBOSE:
2435 case __LOG_DEBUG:
2436 case __LOG_TRACE:
2437 case __LOG_DTMF:
2438 hidecli = 1; /* Hide the message from the CLI, but still log to any log files */
2439 default: /* Always show NOTICE, WARNING, ERROR, etc. */
2440 break;
2441 }
2442 return;
2443 }
2444
2448 logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
2449 "Log queue threshold (%d) exceeded. Discarding non-warning/error messages.\n", logger_queue_limit);
2451 high_water_alert = 1;
2453 }
2454
2458 return;
2459 }
2460
2462 int size_before = logger_queue_size;
2463 struct logmsg *msg_ptr;
2464
2467
2470
2471 if (size_before == logger_queue_size) {
2472 /* We didn't flush anything, so we have to discard the message */
2475 logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
2476 "Log queue does not have any non-WARNING/ERROR messages left to discard. "
2477 "Discarding all new messages.");
2481 return;
2482 }
2483 else {
2484 /* We flushed some non-WARNING/ERROR messages */
2485 logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
2486 "Log queue WARNING / ERROR threshold (%d) exceeded. Discarded %d oldest non-"
2487 "WARNING/ERROR messages.\n", logger_queue_over_threshold_limit, size_before - logger_queue_size);
2490 }
2491 }
2492 }
2494
2496 if (!logmsg) {
2497 return;
2498 }
2499
2501
2502 /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */
2505 if (close_logger_thread) {
2506 /* Logger is either closing or closed. We cannot log this message. */
2508 } else {
2512 }
2514 } else {
2517 }
2518}
2519
2520void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
2521{
2522 va_list ap;
2523
2524 va_start(ap, fmt);
2525 ast_log_ap(level, file, line, function, fmt, ap);
2526 va_end(ap);
2527}
2528
2529void ast_log_ap(int level, const char *file, int line, const char *function, const char *fmt, va_list ap)
2530{
2532
2534
2535 if (level == __LOG_VERBOSE) {
2536 __ast_verbose_ap(file, line, function, 0, callid, fmt, ap);
2537 } else {
2538 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2539 }
2540}
2541
2542void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt, ...)
2543{
2544 va_list ap;
2545 void *recursed = ast_threadstorage_get_ptr(&in_safe_log);
2547
2548 if (recursed) {
2549 return;
2550 }
2551
2552 if (ast_threadstorage_set_ptr(&in_safe_log, &(int) { 1 })) {
2553 /* We've failed to set the flag that protects against
2554 * recursion, so bail. */
2555 return;
2556 }
2557
2559
2560 va_start(ap, fmt);
2561 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2562 va_end(ap);
2563
2564 /* Clear flag so the next allocation failure can be logged. */
2565 ast_threadstorage_set_ptr(&in_safe_log, NULL);
2566}
2567
2568void ast_log_callid(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt, ...)
2569{
2570 va_list ap;
2571 va_start(ap, fmt);
2572 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2573 va_end(ap);
2574}
2575
2576
2578{
2579#ifdef HAVE_BKTR
2580 struct ast_bt *bt;
2581 int i = 0;
2582 struct ast_vector_string *strings;
2583
2584 if (!(bt = ast_bt_create())) {
2585 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
2586 return;
2587 }
2588
2589 if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
2590 int count = AST_VECTOR_SIZE(strings);
2591 struct ast_str *buf = ast_str_create(bt->num_frames * 64);
2592
2593 if (buf) {
2594 ast_str_append(&buf, 0, "Got %d backtrace record%c\n", count - 3, count - 3 != 1 ? 's' : ' ');
2595 for (i = 3; i < AST_VECTOR_SIZE(strings); i++) {
2596 ast_str_append(&buf, 0, "#%2d: %s\n", i - 3, AST_VECTOR_GET(strings, i));
2597 }
2599 ast_free(buf);
2600 }
2601
2602 ast_bt_free_symbols(strings);
2603 } else {
2604 ast_log(LOG_ERROR, "Could not allocate memory for backtrace\n");
2605 }
2606 ast_bt_destroy(bt);
2607#else
2608 ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
2609#endif /* defined(HAVE_BKTR) */
2610}
2611
2612void __ast_verbose_ap(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, va_list ap)
2613{
2614 ast_log_full(__LOG_VERBOSE, level, file, line, func, callid, fmt, ap);
2615}
2616
2617void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
2618{
2619 ast_callid callid;
2620 va_list ap;
2621
2623
2624 va_start(ap, fmt);
2625 __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
2626 va_end(ap);
2627}
2628
2629void __ast_verbose_callid(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, ...)
2630{
2631 va_list ap;
2632 va_start(ap, fmt);
2633 __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
2634 va_end(ap);
2635}
2636
2637/*! Console verbosity level node. */
2639 /*! List node link */
2641 /*! Console verbosity level. */
2642 int *level;
2643};
2644
2645/*! Registered console verbosity levels */
2647
2648/*! ast_verb_update() reentrancy protection lock. */
2650
2652{
2653 struct logchannel *log;
2654 struct verb_console *console;
2655 int verb_level;
2656
2658
2660
2661 /* Default to the root console verbosity. */
2662 verb_level = option_verbose;
2663
2664 /* Determine max remote console level. */
2666 if (verb_level < *console->level) {
2667 verb_level = *console->level;
2668 }
2669 }
2671
2672 /* Determine max logger channel level. */
2674 AST_RWLIST_TRAVERSE(&logchannels, log, list) {
2675 if (verb_level < log->verbosity) {
2676 verb_level = log->verbosity;
2677 }
2678 }
2680
2681 ast_verb_sys_level = verb_level;
2682
2684}
2685
2686/*!
2687 * \internal
2688 * \brief Unregister a console verbose level.
2689 *
2690 * \param console Which console to unregister.
2691 */
2701
2702static void verb_console_free(void *v_console)
2703{
2704 struct verb_console *console = v_console;
2705
2708}
2709
2710/*! Thread specific console verbosity level node. */
2712
2714{
2715 struct verb_console *console;
2716
2717 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2718 if (!console || !level) {
2719 return;
2720 }
2721 console->level = level;
2722
2727}
2728
2730{
2731 struct verb_console *console;
2732
2733 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2734 if (!console) {
2735 return;
2736 }
2738}
2739
2741{
2742 struct verb_console *console;
2743 int verb_level;
2744
2745 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2747 if (!console) {
2748 verb_level = 0;
2749 } else if (console->level) {
2750 verb_level = *console->level;
2751 } else {
2752 verb_level = option_verbose;
2753 }
2755 return verb_level;
2756}
2757
2758void ast_verb_console_set(int verb_level)
2759{
2760 struct verb_console *console;
2761
2762 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2763 if (!console) {
2764 return;
2765 }
2766
2768 if (console->level) {
2769 *console->level = verb_level;
2770 } else {
2771 option_verbose = verb_level;
2772 }
2775}
2776
2777static void update_logchannels(void)
2778{
2779 struct logchannel *cur;
2780
2781 global_logmask = 0;
2782
2784 make_components(cur);
2785 global_logmask |= cur->logmask;
2786 }
2787}
2788
2789#ifdef AST_DEVMODE
2790
2791AST_THREADSTORAGE_RAW(trace_indent);
2792#define LOTS_O_SPACES " "
2793
2794unsigned long _ast_trace_get_indent(void)
2795{
2796 return (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2797}
2798
2799void _ast_trace_set_indent(unsigned long indent)
2800{
2801 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2802}
2803
2804unsigned long _ast_trace_inc_indent(void)
2805{
2806 unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2807 indent++;
2808 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2809
2810 return indent;
2811}
2812
2813unsigned long _ast_trace_dec_indent(void)
2814{
2815 unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2816 indent--;
2817 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2818
2819 return indent;
2820}
2821
2822void __ast_trace(const char *file, int line, const char *func, enum ast_trace_indent_type indent_type,
2823 unsigned long new_indent, const char* format, ...)
2824{
2825 va_list ap;
2826 unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2827 struct ast_str *fmt = ast_str_create(128);
2828 const char *direction = "";
2829
2830 if (!fmt) {
2831 return;
2832 }
2833
2834 if (indent_type == AST_TRACE_INDENT_PROVIDED) {
2835 indent = new_indent;
2836 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2837 } else if (indent_type == AST_TRACE_INDENT_INC_BEFORE) {
2838 indent++;
2839 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2840 } else if (indent_type == AST_TRACE_INDENT_DEC_BEFORE) {
2841 indent--;
2842 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2843 }
2844
2845 switch(indent_type) {
2848 direction = "";
2849 break;
2853 direction = "--> ";
2854 break;
2857 direction = "<-- ";
2858 break;
2859 }
2860
2861 ast_str_set(&fmt, 0, "%2d %-.*s%s%s:%d %s: %s", (int)indent, (indent_type == AST_TRACE_INDENT_NONE ? 0 : (int)(indent * 4)),
2862 LOTS_O_SPACES, direction, file, line, func, S_OR(ast_skip_blanks(format), "\n"));
2863
2864 if (indent_type == AST_TRACE_INDENT_INC_AFTER || indent_type == AST_TRACE_INDENT_PROVIDED) {
2865 indent++;
2866 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2867 }
2868 if (indent_type == AST_TRACE_INDENT_DEC_AFTER) {
2869 indent--;
2870 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2871 }
2872
2873 va_start(ap, format);
2874 ast_log_full(__LOG_TRACE, -1, NULL, 0, NULL, 0, ast_str_buffer(fmt), ap);
2875 va_end(ap);
2876 ast_free(fmt);
2877}
2878#endif
2879
2880/* Lock should be held before calling this function */
2881static int logger_register_level(const char *name)
2882{
2883 unsigned int level;
2884 unsigned int available = 0;
2885
2886 for (level = 0; level < ARRAY_LEN(levels); level++) {
2887 if ((level >= 16) && !available && !levels[level]) {
2888 available = level;
2889 continue;
2890 }
2891
2892 if (levels[level] && !strcasecmp(levels[level], name)) {
2894 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
2895 name);
2896
2897 return -1;
2898 }
2899 }
2900
2901 if (!available) {
2903 "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
2904 name);
2905
2906 return -1;
2907 }
2908
2910
2911 ast_debug(1, "Registered dynamic logger level '%s' with index %u.\n", name, available);
2912
2914
2915 return available;
2916}
2917
2919{
2920 int available = 0;
2921
2925
2926 return available;
2927}
2928
2929static int logger_get_dynamic_level(const char *name)
2930{
2931 int level = -1;
2932 unsigned int x;
2933
2934 for (x = 16; x < ARRAY_LEN(levels); x++) {
2935 if (!levels[x]) {
2936 continue;
2937 }
2938 if (!strcasecmp(levels[x], name)) {
2939 level = x;
2940 break;
2941 }
2942 }
2943
2944 return level;
2945}
2946
2948{
2949 int level = -1;
2950
2952
2954
2956
2957 return level;
2958}
2959
2960static int logger_unregister_level(const char *name) {
2961 unsigned int x;
2962
2964 if (x == -1) {
2965 return 0;
2966 }
2967 /* take this level out of the global_logmask, to ensure that no new log messages
2968 * will be queued for it
2969 */
2970 global_logmask &= ~(1 << x);
2971 ast_free(levels[x]);
2972 levels[x] = NULL;
2973 return x;
2974}
2975
2977{
2978 int x;
2979
2982
2983 if (x) {
2985 }
2986
2988
2989 if (x) {
2990 ast_debug(1, "Unregistered dynamic logger level '%s' with index %u.\n", name, x);
2991 }
2992}
2993
2995{
2996 return dateformat;
2997}
2998
2999void ast_logger_set_queue_limit(int queue_limit)
3000{
3001 logger_queue_limit = queue_limit;
3002}
3003
3005{
3006 return logger_queue_limit;
3007}
3008
3013
3018
3019static int reload_module(void)
3020{
3021 return reload_logger(0, NULL);
3022}
3023
3024static int unload_module(void)
3025{
3026 return 0;
3027}
3028
3029static int load_module(void)
3030{
3032}
3033
3034/* Logger is initialized separate from the module loader, only reload_module does anything. */
3036 .support_level = AST_MODULE_SUPPORT_CORE,
3037 .load = load_module,
3038 .unload = unload_module,
3039 /* This reload does not support realtime so it does not require "extconfig". */
3041 .load_pri = 0,
Prototypes for public functions only of internal interest,.
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
jack_status_t status
Definition app_jack.c:149
const char * str
Definition app_jack.c:150
#define var
Definition ast_expr2f.c:605
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define PATH_MAX
Definition asterisk.h:40
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
Asterisk backtrace generation.
#define ast_bt_free_symbols(string_vector)
Definition backtrace.h:42
#define ast_bt_get_symbols(addresses, num_frames)
Definition backtrace.h:41
#define ast_bt_create()
Definition backtrace.h:39
#define ast_bt_destroy(bt)
Definition backtrace.h:40
const char * ast_build_os
Definition buildinfo.c:32
const char * ast_build_machine
Definition buildinfo.c:31
const char * ast_build_hostname
Definition buildinfo.c:29
const char * ast_build_user
Definition buildinfo.c:34
const char * ast_build_date
Definition buildinfo.c:33
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
static const char type[]
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3019
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition channel.h:1328
size_t current
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
#define ESS(x)
Definition cli.h:59
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
#define SENTINEL
Definition compiler.h:87
A set of macros to manage doubly-linked lists.
#define AST_DLLIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_DLLIST_ENTRY(type)
Declare previous/forward links inside a list entry.
#define AST_DLLIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
#define AST_DLLIST_LOCK(head)
Locks a list.
#define AST_DLLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_DLLIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
#define AST_DLLIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_DLLIST_UNLOCK(head)
Attempts to unlock a list.
#define AST_DLLIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_DLLIST_FIRST(head)
Returns the first entry contained in a list.
static int enabled
Definition dnsmgr.c:91
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static const char name[]
Definition format_mp3.c:68
direction
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_init_logger_for_socket_console(void)
load logger.conf configuration for console socket connections
Definition logger.c:726
ast_trace_indent_type
Controls if and when indenting is applied.
@ AST_TRACE_INDENT_INC_BEFORE
@ AST_TRACE_INDENT_SAME
@ AST_TRACE_INDENT_PROVIDED
@ AST_TRACE_INDENT_NONE
@ AST_TRACE_INDENT_INC_AFTER
@ AST_TRACE_INDENT_DEC_BEFORE
@ AST_TRACE_INDENT_DEC_AFTER
int ast_verb_sys_level
Definition options.c:65
int option_verbose
Definition options.c:68
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition extconf.c:827
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
Configuration File Parser.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
#define CONFIG_STATUS_FILEINVALID
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
Support for logging to various files, console and syslog Configuration in file logger....
#define __LOG_ERROR
#define VERBOSE_PREFIX_3
#define NUMLOGLEVELS
#define ast_debug(level,...)
Log a DEBUG message.
#define VERBOSE_PREFIX_10
#define VERBOSE_PREFIX_6
#define __LOG_TRACE
void ast_console_toggle_loglevel(int fd, int level, int state)
enables or disables logging of a specified level to the console
Definition asterisk.c:1264
#define VERBOSE_PREFIX_2
void ast_console_puts_mutable(const char *string, int level)
log the string to the console, and all attached console clients
Definition asterisk.c:1329
unsigned int ast_callid
#define VERBOSE_PREFIX_8
#define __LOG_DTMF
#define VERBOSE_PREFIX_7
#define QUEUELOG
#define VERBOSE_PREFIX_4
#define __LOG_VERBOSE
@ AST_LOGGER_DECLINE
@ AST_LOGGER_FAILURE
@ AST_LOGGER_SUCCESS
@ AST_LOGGER_ALLOC_ERROR
#define VERBOSE_PREFIX_5
#define VERBOSE_PREFIX_1
#define __LOG_DEBUG
#define __LOG_WARNING
#define LOG_ERROR
#define VERBOSE_PREFIX_9
#define ast_verb(level,...)
#define LOG_WARNING
void ast_console_puts_mutable_full(const char *message, int level, int sublevel)
log the string to the console, and all attached console clients
Definition asterisk.c:1336
Asterisk JSON abstraction layer.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition json.c:52
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition json.h:810
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
#define AST_RWLIST_EMPTY
#define AST_RWLIST_REMOVE_CURRENT
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition linkedlists.h:78
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_RWLIST_REMOVE_HEAD
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_RWLIST_REMOVE
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_TRAVERSE
#define AST_RWLIST_INSERT_HEAD
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_RWLIST_ENTRY
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition localtime.c:2524
Asterisk locking-related definitions:
#define ast_cond_destroy(cond)
Definition lock.h:209
#define ast_cond_wait(cond, mutex)
Definition lock.h:212
#define AST_PTHREADT_NULL
Definition lock.h:73
#define ast_cond_init(cond, attr)
Definition lock.h:208
#define ast_mutex_init(pmutex)
Definition lock.h:193
#define ast_mutex_unlock(a)
Definition lock.h:197
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
pthread_cond_t ast_cond_t
Definition lock.h:185
#define ast_mutex_destroy(a)
Definition lock.h:195
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define ast_cond_signal(cond)
Definition lock.h:210
unsigned int queue_log_to_file
Definition logger.c:119
int ast_logger_get_dynamic_level(const char *name)
Retrieve dynamic logging level id.
Definition logger.c:2947
static void make_filename(const char *channel, char *filename, size_t size)
create the filename that will be used for a logger channel.
Definition logger.c:602
static int format_log_json(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
Definition logger.c:289
static int init_logger_chain(const char *altconf)
Read config, setup channels.
Definition logger.c:772
int ast_logger_get_queue_limit(void)
Get the maximum number of messages allowed in the processing queue.
Definition logger.c:3004
static unsigned int global_logmask
Definition logger.c:85
void __ast_verbose_ap(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, va_list ap)
Definition logger.c:2612
static struct @395 logfiles
static int format_log_plain(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
Definition logger.c:471
int ast_logger_rotate_channel(const char *log_channel)
Rotate the specified log channel.
Definition logger.c:1328
static char * handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1608
void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid)
copy a string representation of the callid into a target string
Definition logger.c:2277
static char * handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command to show logging system configuration.
Definition logger.c:1448
static char * handle_logger_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI command to show logging levels.
Definition logger.c:1489
static void verb_console_free(void *v_console)
Definition logger.c:2702
static int callid_group_remove_filters(void)
Definition logger.c:1710
static char dateformat[256]
Definition logger.c:79
static int queuelog_init
Definition logger.c:86
void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created)
Use in conjunction with ast_callid_threadstorage_auto. Cleans up the references and if the callid was...
Definition logger.c:2367
void logger_queue_start(void)
Start the ast_queue_log() logger.
Definition logger.c:2175
void ast_verb_console_unregister(void)
Unregister this thread's console verbosity level.
Definition logger.c:2729
logmsgtypes
Definition logger.c:172
@ LOGMSG_NORMAL
Definition logger.c:173
@ LOGMSG_VERBOSE
Definition logger.c:174
static char * levels[NUMLOGLEVELS]
Logging channels used in the Asterisk logging system.
Definition logger.c:227
static int callid_filtering
Definition logger.c:1669
static int filesize_reload_needed
Definition logger.c:84
static int custom_level_still_exists(char **levels, char *level, size_t len)
Checks if level exists in array of level names.
Definition logger.c:752
static struct ast_custom_function log_group_function
Definition logger.c:1797
int ast_logger_create_channel(const char *log_channel, const char *components)
Create a log channel.
Definition logger.c:1517
static void _handle_SIGXFSZ(int sig)
Definition logger.c:1900
void ast_verb_console_register(int *level)
Register this thread's console verbosity level pointer.
Definition logger.c:2713
static int log_group_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition logger.c:1787
static char * handle_logger_chanloggroup_filter(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1802
#define FORMATL
static void ast_log_full(int level, int sublevel, const char *file, int line, const char *function, ast_callid callid, const char *fmt, va_list ap)
send log messages to syslog and/or the console
Definition logger.c:2421
int ast_callid_threadassoc_change(ast_callid callid)
Sets what is stored in the thread storage to the given callid if it does not match what is already th...
Definition logger.c:2296
static int close_logger_thread
Definition logger.c:212
rotatestrategy
Definition logger.c:110
@ ROTATE
Definition logger.c:113
@ TIMESTAMP
Definition logger.c:114
@ SEQUENTIAL
Definition logger.c:112
@ NONE
Definition logger.c:111
void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message with protection against recursion.
Definition logger.c:2542
static char * custom_dynamic_levels[NUMLOGLEVELS]
Custom dynamic logging levels added by the user.
Definition logger.c:244
int ast_logger_rotate()
Reload logger while rotating log files.
Definition logger.c:1323
int ast_logger_remove_channel(const char *log_channel)
Delete the specified log channel.
Definition logger.c:1583
static struct logchannel * make_logchannel(const char *channel, const char *components, int lineno, int dynamic)
Definition logger.c:659
#define FORMATL2
static int logger_queue_rt_start(void)
Definition logger.c:1157
void close_logger(void)
Definition logger.c:2234
static struct logmsg * flush_logger_queue_messages(struct logmsg *start, int amount)
Definition logger.c:2386
int ast_logger_get_channels(int(*logentry)(const char *channel, const char *type, const char *status, const char *configuration, void *data), void *data)
Retrieve the existing log channels.
Definition logger.c:1405
static int reload_logger(int rotate, const char *altconf)
Definition logger.c:1220
int ast_is_logger_initialized(void)
Test if logger is initialized.
Definition logger.c:2164
static char * handle_logger_filter_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1834
static FILE * qlog
Definition logger.c:214
static void update_logchannels(void)
Definition logger.c:2777
ast_callid ast_read_threadstorage_callid(void)
extracts the callid from the thread
Definition logger.c:2287
static int display_callids
Definition logger.c:89
static int logger_initialized
Definition logger.c:87
static char exec_after_rotate[256]
Definition logger.c:82
static pthread_t logthread
Definition logger.c:210
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition logger.c:2309
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition logger.c:2282
static int logger_queue_over_threshold_limit
Definition logger.c:95
static int logger_queue_limit
Definition logger.c:94
static struct logformatter logformatter_json
Definition logger.c:344
static int callid_group_set_filter(const char *group, int enabled)
Definition logger.c:1725
static int logger_queue_size
Definition logger.c:93
static struct logformatter logformatter_default
Definition logger.c:466
unsigned int queue_log_realtime_use_gmt
Definition logger.c:121
static int reload_module(void)
Definition logger.c:3019
static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size)
Definition logger.c:349
logtypes
Definition logger.c:137
@ LOGTYPE_CONSOLE
Definition logger.c:140
@ LOGTYPE_FILE
Definition logger.c:139
@ LOGTYPE_SYSLOG
Definition logger.c:138
void __ast_verbose_callid(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt,...)
Send a verbose message (based on verbose level) with deliberately specified callid.
Definition logger.c:2629
static unsigned int high_water_alert
Definition logger.c:97
static char queue_log_name[256]
Definition logger.c:81
static int logger_register_level(const char *name)
Definition logger.c:2881
#define LOG_BUF_INIT_SIZE
Definition logger.c:287
static ast_mutex_t verb_update_lock
Definition logger.c:2649
static struct logmsg * last_logmsg_checked_for_discard
Definition logger.c:209
static void make_components(struct logchannel *chan)
Definition logger.c:521
void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt,...)
Send a verbose message (based on verbose level)
Definition logger.c:2617
void ast_log_ap(int level, const char *file, int line, const char *function, const char *fmt, va_list ap)
Definition logger.c:2529
#define LOGMSG_SIZE
Definition logger.c:108
static char * handle_logger_filter_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1864
static const int colors[NUMLOGLEVELS]
Colors used in the console for logging.
Definition logger.c:247
static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
Definition logger.c:407
static unsigned int discard_all_new_msgs
Definition logger.c:103
static struct sigaction handle_SIGXFSZ
Definition logger.c:1906
unsigned int queue_log
Definition logger.c:118
int ast_callid_threadassoc_remove(void)
Removes callid from thread storage of the calling thread.
Definition logger.c:2328
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition logger.c:973
int ast_callid_threadstorage_auto(ast_callid *callid)
Checks thread storage for a callid and stores a reference if it exists. If not, then a new one will b...
Definition logger.c:2345
int ast_logger_register_level(const char *name)
Register a new logger level.
Definition logger.c:2918
static void * logger_thread(void *data)
Actual logging thread.
Definition logger.c:2083
int init_logger(void)
Definition logger.c:2191
void ast_logger_set_queue_limit(int queue_limit)
Set the maximum number of messages allowed in the processing queue.
Definition logger.c:2999
void ast_verb_update(void)
Re-evaluate the system max verbosity level (ast_verb_sys_level).
Definition logger.c:2651
static char * handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1363
int ast_logger_get_over_threshold_queue_limit(void)
Get the over threshold maximum number of messages allowed in the processing queue.
Definition logger.c:3014
static struct logformatter logformatter_plain
Definition logger.c:516
static int callid_set_chanloggroup(const char *group)
Definition logger.c:1678
static ast_cond_t logcond
Definition logger.c:211
#define VERBOSE_BUF_INIT_SIZE
Definition logger.c:284
void ast_child_verbose(int level, const char *fmt,...)
Definition logger.c:929
static int logger_unregister_level(const char *name)
Definition logger.c:2960
static void logger_print_normal(struct logmsg *logmsg)
Print a normal log message to the channels.
Definition logger.c:1912
static int load_module(void)
Definition logger.c:3029
void ast_log_callid(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt,...)
Used for sending a log message with a known call_id This is a modified logger function which is funct...
Definition logger.c:2568
static struct logchannel * find_logchannel(const char *channel)
Find a particular logger channel by name.
Definition logger.c:643
static int unload_module(void)
Definition logger.c:3024
static char * handle_logger_add_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1547
static void logger_queue_init(void)
Definition logger.c:2140
static int callid_logging_enabled(void)
Definition logger.c:1763
void ast_logger_set_over_threshold_queue_limit(int limit)
Set the threshold for the maximum number of WARNING/ERROR messages allowed in the processing queue th...
Definition logger.c:3009
static struct logmsg * 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)
Definition logger.c:2004
static char * handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1285
static struct ast_cli_entry cli_logger[]
Definition logger.c:1887
static int logger_queue_restart(int queue_rotate)
Definition logger.c:1192
int ast_verb_console_get(void)
Get this thread's console verbosity level.
Definition logger.c:2740
static char * handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition logger.c:1304
const char * ast_logger_get_dateformat(void)
Get the logger configured date format.
Definition logger.c:2994
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
Definition logger.c:2976
unsigned int queue_adaptive_realtime
Definition logger.c:120
static int logger_messages_discarded
Definition logger.c:96
static int rotate_file(const char *filename)
Definition logger.c:1053
static const char * get_callid_group(void)
Definition logger.c:1671
static volatile int next_unique_callid
Definition logger.c:88
static char hostname[MAXHOSTNAMELEN]
Definition logger.c:124
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
Definition logger.c:2577
void ast_verb_console_set(int verb_level)
Set this thread's console verbosity level.
Definition logger.c:2758
static void verb_console_unregister(struct verb_console *console)
Definition logger.c:2692
static int logger_get_dynamic_level(const char *name)
Definition logger.c:2929
static struct logmsg * format_log_message(int level, int sublevel, const char *file, int line, const char *function, ast_callid callid, const char *fmt,...)
Definition logger.c:2068
static void logmsg_free(struct logmsg *msg)
Definition logger.c:195
int ast_logger_category_load(void)
Load/Initialize system wide logger category functionality.
int ast_logger_category_unload(void)
Unload system wide logger category functionality.
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition manager.h:255
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODULE_SUPPORT_CORE
Definition module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
#define MAXHOSTNAMELEN
Definition network.h:69
#define ast_opt_remote
Definition options.h:124
#define ast_opt_exec
Definition options.h:125
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_SYSTEM_NAME
Definition options.c:171
const char * ast_config_AST_LOG_DIR
Definition options.c:160
Core PBX routines and definitions.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define ast_custom_function_register(acf)
Register a custom function.
Definition pbx.h:1563
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
static int reload(void)
static struct @522 args
#define NULL
Definition resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
#define AST_STRING_FIELD(name)
Declare a string field.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition strings.h:1030
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
static int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
Checks whether a string ends with another.
Definition strings.h:116
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition strings.h:1062
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition strings.h:1113
@ AST_DYNSTR_BUILD_FAILED
Definition strings.h:943
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
char *attribute_pure ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition strings.h:161
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition strings.h:909
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Definition backtrace.h:50
void * addresses[AST_MAX_BT_FRAMES]
Definition backtrace.h:52
int num_frames
Definition backtrace.h:54
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Data structure associated with a custom dialplan function.
Definition pbx.h:118
const char * name
Definition pbx.h:119
Structure used to handle boolean flags.
Definition utils.h:220
Abstract JSON element (object, array, string, int, ...).
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
String vector definitions.
Definition vector.h:55
map call ID to group
Definition logger.c:1662
struct chan_group_lock::@398 entry
char name[0]
Definition logger.c:1664
int verbosity
Definition logger.c:153
int facility
Definition logger.c:151
struct logformatter formatter
Definition logger.c:145
int dynamic
Definition logger.c:165
int lineno
Definition logger.c:163
enum logtypes type
Definition logger.c:155
unsigned int logmask
Definition logger.c:147
char filename[PATH_MAX]
Definition logger.c:159
struct logchannel::@396 list
FILE * fileptr
Definition logger.c:157
int disabled
Definition logger.c:149
char components[0]
Definition logger.c:167
const char * name
Definition logger.c:132
int(*const format_log)(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
Definition logger.c:134
const ast_string_field level_name
Definition logger.c:191
int lwp
Definition logger.c:182
const ast_string_field message
Definition logger.c:191
int line
Definition logger.c:181
ast_callid callid
Definition logger.c:183
int sublevel
Definition logger.c:180
struct logmsg::@397 list
const ast_string_field file
Definition logger.c:191
const ast_string_field function
Definition logger.c:191
enum logmsgtypes type
Definition logger.c:178
int level
Definition logger.c:179
unsigned int hidecli
Definition logger.c:184
const ast_string_field date
Definition logger.c:191
ast_mutex_t lock
Definition logger.c:201
struct verb_console::@399 node
int * level
Definition logger.c:2642
int value
Definition syslog.c:37
Syslog support functions for Asterisk logging.
int ast_syslog_priority_from_loglevel(int level)
Maps an Asterisk log level (i.e. LOG_ERROR) to a syslog priority constant.
Definition syslog.c:162
int ast_syslog_facility(const char *facility)
Maps a syslog facility name from a string to a syslog facility constant.
Definition syslog.c:85
Handy terminal functions for vt* terms.
#define COLOR_BRGREEN
Definition term.h:55
#define COLOR_BRRED
Definition term.h:53
#define COLOR_YELLOW
Definition term.h:57
#define COLOR_BRWHITE
Definition term.h:65
#define COLOR_RED
Definition term.h:52
char * term_strip(char *outbuf, const char *inbuf, int maxout)
Remove colorings from a specified string.
Definition term.c:362
#define COLORIZE(fg, bg, str)
Definition term.h:72
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition term.h:71
#define COLOR_GREEN
Definition term.h:54
#define COLOR_BRBLUE
Definition term.h:59
static struct test_val a
static struct test_val c
Definitions to aid in the use of thread local storage.
int ast_threadstorage_set_ptr(struct ast_threadstorage *ts, void *ptr)
Set a raw pointer from threadstorage.
void * ast_threadstorage_get_ptr(struct ast_threadstorage *ts)
Retrieve a raw pointer from threadstorage.
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
#define AST_THREADSTORAGE_RAW(name)
Time-related functions and macros.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
Utility functions.
#define ast_assert(a)
Definition utils.h:779
#define ast_pthread_create(a, b, c, d)
Definition utils.h:624
int ast_get_tid(void)
Get current thread ID.
Definition utils.c:2786
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513
#define ARRAY_LEN(a)
Definition utils.h:706
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:637
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:708