Asterisk - The Open Source Telephony Project GIT-master-a358458
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"
73
74/*** DOCUMENTATION
75 ***/
76
77static int logger_register_level(const char *name);
78static int logger_unregister_level(const char *name);
79static int logger_get_dynamic_level(const char *name);
80
81static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
82
83static char queue_log_name[256] = QUEUELOG;
84static char exec_after_rotate[256] = "";
85
87static unsigned int global_logmask = 0xFFFF;
88static int queuelog_init;
90static volatile int next_unique_callid = 1; /* Used to assign unique call_ids to calls */
91static int display_callids;
92
94
96static int logger_queue_limit = 1000;
98static unsigned int high_water_alert;
99
100/* On some platforms, like those with MUSL as the runtime, BUFSIZ is
101 * unreasonably small (1024). Use a larger value in those environments.
102 */
103#define LOGMSG_SIZE MAX(BUFSIZ, 8192)
104
105static enum rotatestrategy {
106 NONE = 0, /* Do not rotate log files at all, instead rely on external mechanisms */
107 SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */
108 ROTATE = 1 << 1, /* Rotate all files, such that the oldest file has the highest suffix */
109 TIMESTAMP = 1 << 2, /* Append the epoch timestamp onto the end of the archived file */
111
112static struct {
113 unsigned int queue_log:1;
114 unsigned int queue_log_to_file:1;
117} logfiles = { 1 };
118
121
122struct logchannel;
123struct logmsg;
124
126 /* The name of the log formatter */
127 const char *name;
128 /* Pointer to the function that will format the log */
129 int (* const format_log)(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size);
130};
131
136};
137
139 /*! How the logs sent to this channel will be formatted */
141 /*! What to log to this channel */
142 unsigned int logmask;
143 /*! If this channel is disabled or not */
145 /*! syslog facility */
147 /*! Verbosity level. (-1 if use option_verbose for the level.) */
149 /*! Type of log channel */
151 /*! logfile logging file pointer */
152 FILE *fileptr;
153 /*! Filename */
155 /*! field for linking to list */
157 /*! Line number from configuration file */
159 /*! Whether this log channel was created dynamically */
161 /*! Components (levels) from last config load */
162 char components[0];
163};
164
166
170};
171
172struct logmsg {
174 int level;
176 int line;
177 int lwp;
179 unsigned int hidecli:1; /*!< Whether to suppress log message from CLI output (but log normally to other log channels */
186 );
188};
189
190static void logmsg_free(struct logmsg *msg)
191{
193 ast_free(msg);
194}
195
197static pthread_t logthread = AST_PTHREADT_NULL;
199static int close_logger_thread = 0;
200
201static FILE *qlog;
202
203/*! \brief Logging channels used in the Asterisk logging system
204 *
205 * The first 16 levels are reserved for system usage, and the remaining
206 * levels are reserved for usage by dynamic levels registered via
207 * ast_logger_register_level.
208 */
209
210/* Modifications to this array are protected by the rwlock in the
211 * logchannels list.
212 */
213
214static char *levels[NUMLOGLEVELS] = {
215 "DEBUG",
216 "TRACE",
217 "NOTICE",
218 "WARNING",
219 "ERROR",
220 "VERBOSE",
221 "DTMF",
222};
223
224/*! \brief Custom dynamic logging levels added by the user
225 *
226 * The first 16 levels are reserved for system usage, and the remaining
227 * levels are reserved for usage by dynamic levels registered via
228 * ast_logger_register_level.
229 */
230
232
233/*! \brief Colors used in the console for logging */
234static const int colors[NUMLOGLEVELS] = {
236 COLOR_BRBLUE, /* no longer used */
239 COLOR_RED,
242 0,
243 0,
244 0,
245 0,
246 0,
247 0,
248 0,
249 0,
250 0,
267};
268
271#define VERBOSE_BUF_INIT_SIZE 256
272
274#define LOG_BUF_INIT_SIZE 256
275
276static int format_log_json(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
277{
278 struct ast_json *json;
279 char *str;
280 char call_identifier_str[13];
281 size_t json_str_len;
282
283 if (msg->callid) {
284 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
285 } else {
286 call_identifier_str[0] = '\0';
287 }
288
289 json = ast_json_pack("{s: s, s: s, "
290 "s: {s: i, s: s} "
291 "s: {s: {s: s, s: s, s: i}, "
292 "s: s, s: s} }",
293 "hostname", ast_config_AST_SYSTEM_NAME,
294 "timestamp", msg->date,
295 "identifiers",
296 "lwp", msg->lwp,
297 "callid", S_OR(call_identifier_str, ""),
298 "logmsg",
299 "location",
300 "filename", msg->file,
301 "function", msg->function,
302 "line", msg->line,
303 "level", msg->level_name,
304 "message", msg->message);
305 if (!json) {
306 return -1;
307 }
308
310 if (!str) {
311 ast_json_unref(json);
312 return -1;
313 }
314
315 ast_copy_string(buf, str, size);
316 json_str_len = strlen(str);
317 if (json_str_len > size - 1) {
318 json_str_len = size - 1;
319 }
320 buf[json_str_len] = '\n';
321 buf[json_str_len + 1] = '\0';
322
323 term_strip(buf, buf, size);
324
326 ast_json_unref(json);
327
328 return 0;
329}
330
332 .name = "json",
333 .format_log = format_log_json
334};
335
336static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size)
337{
338 const char *p;
339 const char *fmt;
340 struct ast_str *prefixed;
341 signed char magic = logmsg->sublevel > 9 ? -10 : -logmsg->sublevel - 1; /* 0 => -1, 1 => -2, etc. Can't pass NUL, as it is EOS-delimiter */
342
343 /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */
344 if (logmsg->sublevel < 0) {
345 if (!strncmp(logmsg->message, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) {
346 magic = -5;
347 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) {
348 magic = -4;
349 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) {
350 magic = -3;
351 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) {
352 magic = -2;
353 } else {
354 magic = -1;
355 }
356 }
357
359 return -1;
360 }
361
362 ast_str_reset(prefixed);
363
364 /* for every newline found in the buffer add verbose prefix data */
365 fmt = logmsg->message;
366 do {
367 if (!(p = strchr(fmt, '\n'))) {
368 p = strchr(fmt, '\0') - 1;
369 }
370 ++p;
371
372 ast_str_append(&prefixed, 0, "%c", (char)magic);
373 ast_str_append_substr(&prefixed, 0, fmt, p - fmt);
374 fmt = p;
375 } while (p && *p);
376
377 snprintf(buf, size, "%s", ast_str_buffer(prefixed));
378
379 return 0;
380}
381
382static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
383{
384 char call_identifier_str[13];
385
386 if (msg->callid) {
387 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
388 } else {
389 call_identifier_str[0] = '\0';
390 }
391
392 switch (chan->type) {
393 case LOGTYPE_SYSLOG:
394 snprintf(buf, size, "%s[%d]%s: %s:%d in %s: %s",
395 levels[msg->level], msg->lwp, call_identifier_str, msg->file,
396 msg->line, msg->function, msg->message);
397 term_strip(buf, buf, size);
398 break;
399 case LOGTYPE_FILE:
400 snprintf(buf, size, "[%s] %s[%d]%s %s: %s",
401 msg->date, msg->level_name, msg->lwp, call_identifier_str,
402 msg->file, msg->message);
403 term_strip(buf, buf, size);
404 break;
405 case LOGTYPE_CONSOLE:
406 {
407 char linestr[32];
408 int has_file = !ast_strlen_zero(msg->file);
409 int has_line = (msg->line > 0);
410 int has_func = !ast_strlen_zero(msg->function);
411
412 /*
413 * Verbose messages are interpreted by console channels in their own
414 * special way
415 */
416 if (msg->level == __LOG_VERBOSE) {
417 return logger_add_verbose_magic(msg, buf, size);
418 }
419
420 /* Turn the numerical line number into a string */
421 snprintf(linestr, sizeof(linestr), "%d", msg->line);
422 /* Build string to print out */
423 snprintf(buf, size, "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT "%s" COLORIZE_FMT " " COLORIZE_FMT "%s %s",
424 msg->date,
425 COLORIZE(colors[msg->level], 0, msg->level_name),
426 msg->lwp,
427 call_identifier_str,
428 COLORIZE(COLOR_BRWHITE, 0, has_file ? msg->file : ""),
429 has_file ? ":" : "",
430 COLORIZE(COLOR_BRWHITE, 0, has_line ? linestr : ""),
431 COLORIZE(COLOR_BRWHITE, 0, has_func ? msg->function : ""),
432 has_func ? ":" : "",
433 msg->message);
434 }
435 break;
436 }
437
438 return 0;
439}
440
442 .name = "default",
443 .format_log = format_log_default,
444};
445
446static int format_log_plain(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
447{
448 char call_identifier_str[13];
449 char linestr[32];
450 int has_file = !ast_strlen_zero(msg->file);
451 int has_line = (msg->line > 0);
452 int has_func = !ast_strlen_zero(msg->function);
453
454 if (msg->callid) {
455 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
456 } else {
457 call_identifier_str[0] = '\0';
458 }
459
460 switch (chan->type) {
461 case LOGTYPE_SYSLOG:
462 snprintf(buf, size, "%s[%d]%s: %s:%d in %s: %s",
463 levels[msg->level], msg->lwp, call_identifier_str, msg->file,
464 msg->line, msg->function, msg->message);
465 term_strip(buf, buf, size);
466 break;
467 case LOGTYPE_FILE:
468 case LOGTYPE_CONSOLE:
469 /* Turn the numerical line number into a string */
470 snprintf(linestr, sizeof(linestr), "%d", msg->line);
471 /* Build string to print out */
472 snprintf(buf, size, "[%s] %s[%d]%s: %s%s%s%s%s%s%s",
473 msg->date,
474 msg->level_name,
475 msg->lwp,
476 call_identifier_str,
477 has_file ? msg->file : "",
478 has_file ? ":" : "",
479 has_line ? linestr : "",
480 has_line ? " " : "",
481 has_func ? msg->function : "",
482 has_func ? ": " : "",
483 msg->message);
484 term_strip(buf, buf, size);
485 break;
486 }
487
488 return 0;
489}
490
492 .name = "plain",
493 .format_log = format_log_plain,
494};
495
496static void make_components(struct logchannel *chan)
497{
498 char *w;
499 unsigned int logmask = 0;
500 char *stringp = ast_strdupa(chan->components);
501 unsigned int x;
502 unsigned int verb_level;
503
504 /* Default to using option_verbose as the verbosity level of the logging channel. */
505 verb_level = -1;
506
507 w = strchr(stringp, '[');
508 if (w) {
509 char *end = strchr(w + 1, ']');
510 if (!end) {
511 fprintf(stderr, "Logger Warning: bad formatter definition for %s in logger.conf\n", chan->filename);
512 } else {
513 char *formatter_name = w + 1;
514
515 *end = '\0';
516 stringp = end + 1;
517
518 if (!strcasecmp(formatter_name, "json")) {
519 memcpy(&chan->formatter, &logformatter_json, sizeof(chan->formatter));
520 } else if (!strcasecmp(formatter_name, "default")) {
521 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
522 } else if (!strcasecmp(formatter_name, "plain")) {
523 memcpy(&chan->formatter, &logformatter_plain, sizeof(chan->formatter));
524 } else {
525 fprintf(stderr, "Logger Warning: Unknown formatter definition %s for %s in logger.conf; using 'default'\n",
526 formatter_name, chan->filename);
527 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
528 }
529 }
530 }
531
532 if (!chan->formatter.name) {
533 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
534 }
535
536 while ((w = strsep(&stringp, ","))) {
537 w = ast_strip(w);
538 if (ast_strlen_zero(w)) {
539 continue;
540 }
541 if (!strcmp(w, "*")) {
542 logmask = 0xFFFFFFFF;
543 } else if (!strncasecmp(w, "verbose(", 8)) {
544 if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
545 logmask |= (1 << __LOG_VERBOSE);
546 }
547 } else {
548 for (x = 0; x < ARRAY_LEN(levels); ++x) {
549 if (levels[x] && !strcasecmp(w, levels[x])) {
550 logmask |= (1 << x);
551 break;
552 }
553 }
554 }
555 }
556 if (chan->type == LOGTYPE_CONSOLE) {
557 /*
558 * Force to use the root console verbose level so if the
559 * user specified any verbose level then it does not interfere
560 * with calculating the ast_verb_sys_level value.
561 */
562 chan->verbosity = -1;
563 logmask |= (1 << __LOG_VERBOSE);
564 } else {
565 chan->verbosity = verb_level;
566 }
567 chan->logmask = logmask;
568}
569
570/*!
571 * \brief create the filename that will be used for a logger channel.
572 *
573 * \param channel The name of the logger channel
574 * \param[out] filename The filename for the logger channel
575 * \param size The size of the filename buffer
576 */
577static void make_filename(const char *channel, char *filename, size_t size)
578{
579 const char *log_dir_prefix = "";
580 const char *log_dir_separator = "";
581
582 *filename = '\0';
583
584 if (!strcasecmp(channel, "console")) {
585 return;
586 }
587
588 if (!strncasecmp(channel, "syslog", 6)) {
589 ast_copy_string(filename, channel, size);
590 return;
591 }
592
593 /* It's a filename */
594
595 if (channel[0] != '/') {
596 log_dir_prefix = ast_config_AST_LOG_DIR;
597 log_dir_separator = "/";
598 }
599
601 snprintf(filename, size, "%s%s%s.%s",
602 log_dir_prefix, log_dir_separator, channel, hostname);
603 } else {
604 snprintf(filename, size, "%s%s%s",
605 log_dir_prefix, log_dir_separator, channel);
606 }
607}
608
609/*!
610 * \brief Find a particular logger channel by name
611 *
612 * \pre logchannels list is locked
613 *
614 * \param channel The name of the logger channel to find
615 * \retval non-NULL The corresponding logger channel
616 * \retval NULL Unable to find a logger channel with that particular name
617 */
618static struct logchannel *find_logchannel(const char *channel)
619{
620 char filename[PATH_MAX];
621 struct logchannel *chan;
622
623 make_filename(channel, filename, sizeof(filename));
624
626 if (!strcmp(chan->filename, filename)) {
627 return chan;
628 }
629 }
630
631 return NULL;
632}
633
634static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno, int dynamic)
635{
636 struct logchannel *chan;
637 char *facility;
638 struct ast_tm tm;
639 struct timeval now = ast_tvnow();
640 char datestring[256];
641
642 if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
643 return NULL;
644
645 strcpy(chan->components, components);
646 chan->lineno = lineno;
647 chan->dynamic = dynamic;
648
649 make_filename(channel, chan->filename, sizeof(chan->filename));
650
651 if (!strcasecmp(channel, "console")) {
652 chan->type = LOGTYPE_CONSOLE;
653 } else if (!strncasecmp(channel, "syslog", 6)) {
654 /*
655 * syntax is:
656 * syslog.facility => level,level,level
657 */
658 facility = strchr(channel, '.');
659 if (!facility++ || !facility) {
660 facility = "local0";
661 }
662
663 chan->facility = ast_syslog_facility(facility);
664
665 if (chan->facility < 0) {
666 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
667 ast_free(chan);
668 return NULL;
669 }
670
671 chan->type = LOGTYPE_SYSLOG;
672 openlog("asterisk", LOG_PID, chan->facility);
673 } else {
674 if (!(chan->fileptr = fopen(chan->filename, "a"))) {
675 /* Can't do real logging here since we're called with a lock
676 * so log to any attached consoles */
677 ast_console_puts_mutable("ERROR: Unable to open log file '", __LOG_ERROR);
682 ast_free(chan);
683 return NULL;
684 } else {
685 /* Create our date/time */
686 ast_localtime(&now, &tm, NULL);
687 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
688
689 fprintf(chan->fileptr, "[%s] Asterisk %s built by %s @ %s on a %s running %s on %s\n",
692 fflush(chan->fileptr);
693 }
694 chan->type = LOGTYPE_FILE;
695 }
696 make_components(chan);
697
698 return chan;
699}
700
702{
703 struct ast_config *cfg;
704 const char *s;
705 struct ast_flags config_flags = { 0 };
706
707 if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
708 return;
709 }
710
711 if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
713 }
714
716}
717
718/*!
719 * \brief Checks if level exists in array of level names
720 * \param levels Array of level names
721 * \param level Name to search for
722 * \param len Size of levels
723 *
724 * \retval 1 Found
725 * \retval 0 Not Found
726 */
727static int custom_level_still_exists(char **levels, char *level, size_t len)
728{
729 int i;
730 for (i = 0; i < len; i++) {
731 if (!strcmp(levels[i], level)) {
732 return 1;
733 }
734 }
735 return 0;
736}
737
738/*!
739 * \brief Read config, setup channels.
740 * \param altconf Alternate configuration file to read.
741 *
742 * \pre logchannels list is write locked
743 *
744 * \retval 0 Success
745 * \retval -1 No config found or Failed
746 */
747static int init_logger_chain(const char *altconf)
748{
749 struct logchannel *chan;
750 struct ast_config *cfg;
751 struct ast_variable *var;
752 const char *s;
753 struct ast_flags config_flags = { 0 };
754
755 if (!(cfg = ast_config_load2(S_OR(altconf, "logger.conf"), "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
756 cfg = NULL;
757 }
758
759 /* Set defaults */
760 hostname[0] = '\0';
761 display_callids = 1;
762 memset(&logfiles, 0, sizeof(logfiles));
763 logfiles.queue_log = 1;
764 ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
766 exec_after_rotate[0] = '\0';
768
769 /* delete our list of log channels */
770 while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
771 ast_free(chan);
772 }
773 global_logmask = 0;
774
775 errno = 0;
776 /* close syslog */
777 closelog();
778
779 /* If no config file, we're fine, set default options. */
780 if (!cfg) {
781 chan = make_logchannel("console", "error,warning,notice,verbose", 0, 0);
782 if (!chan) {
783 fprintf(stderr, "ERROR: Failed to initialize default logging\n");
784 return -1;
785 }
786
788 global_logmask |= chan->logmask;
789
790 return -1;
791 }
792
793 if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
794 if (ast_true(s)) {
795 if (gethostname(hostname, sizeof(hostname) - 1)) {
796 ast_copy_string(hostname, "unknown", sizeof(hostname));
797 fprintf(stderr, "What box has no hostname???\n");
798 }
799 }
800 }
801 if ((s = ast_variable_retrieve(cfg, "general", "display_callids"))) {
803 }
804 if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
806 }
807 if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
808 logfiles.queue_log = ast_true(s);
809 }
810 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
811 logfiles.queue_log_to_file = ast_true(s);
812 }
813 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
815 }
816 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_realtime_use_gmt"))) {
817 logfiles.queue_log_realtime_use_gmt = ast_true(s);
818 }
819 if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
821 }
822 if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
823 if (strcasecmp(s, "timestamp") == 0) {
825 } else if (strcasecmp(s, "rotate") == 0) {
827 } else if (strcasecmp(s, "sequential") == 0) {
829 } else if (strcasecmp(s, "none") == 0) {
831 } else {
832 fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
833 }
834 } else {
835 if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
837 fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n");
838 }
839 }
840 if ((s = ast_variable_retrieve(cfg, "general", "logger_queue_limit"))) {
841 if (sscanf(s, "%30d", &logger_queue_limit) != 1) {
842 fprintf(stderr, "logger_queue_limit has an invalid value. Leaving at default of %d.\n",
844 }
845 if (logger_queue_limit < 10) {
846 fprintf(stderr, "logger_queue_limit must be >= 10. Setting to 10.\n");
848 }
849 }
850
851 /* Custom dynamic logging levels defined by user */
852 if ((s = ast_variable_retrieve(cfg, "general", "custom_levels"))) {
853 char *customlogs = ast_strdupa(s);
854 char *logfile;
855 char *new_custom_levels[16] = { };
856 unsigned int level, new_level = 0;
857
858 /* get the custom levels we need to register or reload */
859 while ((logfile = strsep(&customlogs, ","))) {
860 new_custom_levels[new_level++] = logfile;
861 }
862
863 /* unregister existing custom levels, if they're not still
864 specified in customlogs, to make room for new levels */
865 for (level = 16; level < ARRAY_LEN(levels); level++) {
866 if (levels[level] && custom_dynamic_levels[level] &&
867 !custom_level_still_exists(new_custom_levels, levels[level], ARRAY_LEN(new_custom_levels))) {
869 custom_dynamic_levels[level] = 0;
870 }
871 }
872
873 new_level = 0;
874 while ((logfile = new_custom_levels[new_level++])) {
875 /* Lock already held, so directly register the level,
876 unless it's already registered (as during reload) */
877 if (logger_get_dynamic_level(logfile) == -1) {
878 int custom_level = logger_register_level(logfile);
879 custom_dynamic_levels[custom_level] = logfile;
880 }
881 }
882 }
883
884 var = ast_variable_browse(cfg, "logfiles");
885 for (; var; var = var->next) {
886 chan = make_logchannel(var->name, var->value, var->lineno, 0);
887 if (!chan) {
888 /* Print error message directly to the consoles since the lock is held
889 * and we don't want to unlock with the list partially built */
890 ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
893 continue;
894 }
896 global_logmask |= chan->logmask;
897 }
898
899 if (qlog) {
900 fclose(qlog);
901 qlog = NULL;
902 }
903
905
906 return 0;
907}
908
909void ast_child_verbose(int level, const char *fmt, ...)
910{
911 char *msg = NULL, *emsg = NULL, *sptr, *eptr;
912 va_list ap, aq;
913 int size;
914
915 va_start(ap, fmt);
916 va_copy(aq, ap);
917 if ((size = vsnprintf(msg, 0, fmt, ap)) < 0) {
918 va_end(ap);
919 va_end(aq);
920 return;
921 }
922 va_end(ap);
923
924 if (!(msg = ast_malloc(size + 1))) {
925 va_end(aq);
926 return;
927 }
928
929 vsnprintf(msg, size + 1, fmt, aq);
930 va_end(aq);
931
932 if (!(emsg = ast_malloc(size * 2 + 1))) {
933 ast_free(msg);
934 return;
935 }
936
937 for (sptr = msg, eptr = emsg; ; sptr++) {
938 if (*sptr == '"') {
939 *eptr++ = '\\';
940 }
941 *eptr++ = *sptr;
942 if (*sptr == '\0') {
943 break;
944 }
945 }
946 ast_free(msg);
947
948 fprintf(stdout, "verbose \"%s\" %d\n", emsg, level);
949 fflush(stdout);
950 ast_free(emsg);
951}
952
953void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
954{
955 va_list ap;
956 struct timeval tv;
957 struct ast_tm tm;
958 char qlog_msg[8192];
959 int qlog_len;
960 char time_str[30];
961
962 if (!logger_initialized) {
963 /* You are too early. We are not open yet! */
964 return;
965 }
966 if (!queuelog_init) {
967 /* We must initialize now since someone is trying to log something. */
969 }
970
971 if (ast_check_realtime("queue_log")) {
972 tv = ast_tvnow();
973 ast_localtime(&tv, &tm, logfiles.queue_log_realtime_use_gmt ? "GMT" : NULL);
974 ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
975 va_start(ap, fmt);
976 vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
977 va_end(ap);
978 if (logfiles.queue_adaptive_realtime) {
980 AST_APP_ARG(data)[5];
981 );
982 AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
983 /* Ensure fields are large enough to receive data */
984 ast_realtime_require_field("queue_log",
985 "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
986 "data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
987 "data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
988 "data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
989 "data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
990 SENTINEL);
991
992 /* Store the log */
993 ast_store_realtime("queue_log", "time", time_str,
994 "callid", callid,
995 "queuename", queuename,
996 "agent", agent,
997 "event", event,
998 "data1", S_OR(args.data[0], ""),
999 "data2", S_OR(args.data[1], ""),
1000 "data3", S_OR(args.data[2], ""),
1001 "data4", S_OR(args.data[3], ""),
1002 "data5", S_OR(args.data[4], ""),
1003 SENTINEL);
1004 } else {
1005 ast_store_realtime("queue_log", "time", time_str,
1006 "callid", callid,
1007 "queuename", queuename,
1008 "agent", agent,
1009 "event", event,
1010 "data", qlog_msg,
1011 SENTINEL);
1012 }
1013
1014 if (!logfiles.queue_log_to_file) {
1015 return;
1016 }
1017 }
1018
1019 if (qlog) {
1020 va_start(ap, fmt);
1021 qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
1022 vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
1023 va_end(ap);
1025 if (qlog) {
1026 fprintf(qlog, "%s\n", qlog_msg);
1027 fflush(qlog);
1028 }
1030 }
1031}
1032
1033static int rotate_file(const char *filename)
1034{
1035 char old[PATH_MAX];
1036 char new[PATH_MAX];
1037 int x, y, which, found, res = 0, fd;
1038 char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
1039
1040 switch (rotatestrategy) {
1041 case NONE:
1042 /* No rotation */
1043 break;
1044 case SEQUENTIAL:
1045 for (x = 0; ; x++) {
1046 snprintf(new, sizeof(new), "%s.%d", filename, x);
1047 fd = open(new, O_RDONLY);
1048 if (fd > -1)
1049 close(fd);
1050 else
1051 break;
1052 }
1053 if (rename(filename, new)) {
1054 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
1055 res = -1;
1056 } else {
1057 filename = new;
1058 }
1059 break;
1060 case TIMESTAMP:
1061 snprintf(new, sizeof(new), "%s.%ld", filename, (long)time(NULL));
1062 if (rename(filename, new)) {
1063 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
1064 res = -1;
1065 } else {
1066 filename = new;
1067 }
1068 break;
1069 case ROTATE:
1070 /* Find the next empty slot, including a possible suffix */
1071 for (x = 0; ; x++) {
1072 found = 0;
1073 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
1074 snprintf(new, sizeof(new), "%s.%d%s", filename, x, suffixes[which]);
1075 fd = open(new, O_RDONLY);
1076 if (fd > -1) {
1077 close(fd);
1078 found = 1;
1079 break;
1080 }
1081 }
1082 if (!found) {
1083 break;
1084 }
1085 }
1086
1087 /* Found an empty slot */
1088 for (y = x; y > 0; y--) {
1089 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
1090 snprintf(old, sizeof(old), "%s.%d%s", filename, y - 1, suffixes[which]);
1091 fd = open(old, O_RDONLY);
1092 if (fd > -1) {
1093 /* Found the right suffix */
1094 close(fd);
1095 snprintf(new, sizeof(new), "%s.%d%s", filename, y, suffixes[which]);
1096 if (rename(old, new)) {
1097 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
1098 res = -1;
1099 }
1100 break;
1101 }
1102 }
1103 }
1104
1105 /* Finally, rename the current file */
1106 snprintf(new, sizeof(new), "%s.0", filename);
1107 if (rename(filename, new)) {
1108 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
1109 res = -1;
1110 } else {
1111 filename = new;
1112 }
1113 }
1114
1117 char buf[512];
1118
1119 pbx_builtin_setvar_helper(c, "filename", filename);
1121 if (c) {
1123 }
1124 if (ast_safe_system(buf) == -1) {
1125 ast_log(LOG_WARNING, "error executing '%s'\n", buf);
1126 }
1127 }
1128 return res;
1129}
1130
1131/*!
1132 * \internal
1133 * \brief Start the realtime queue logging if configured.
1134 *
1135 * \retval TRUE if not to open queue log file.
1136 */
1138{
1139 if (ast_check_realtime("queue_log")) {
1140 if (!ast_realtime_require_field("queue_log",
1141 "time", RQ_DATETIME, 26,
1142 "data1", RQ_CHAR, 20,
1143 "data2", RQ_CHAR, 20,
1144 "data3", RQ_CHAR, 20,
1145 "data4", RQ_CHAR, 20,
1146 "data5", RQ_CHAR, 20,
1147 SENTINEL)) {
1148 logfiles.queue_adaptive_realtime = 1;
1149 } else {
1150 logfiles.queue_adaptive_realtime = 0;
1151 }
1152
1153 if (!logfiles.queue_log_to_file) {
1154 /* Don't open the log file. */
1155 return 1;
1156 }
1157 }
1158 return 0;
1159}
1160
1161/*!
1162 * \internal
1163 * \brief Rotate the queue log file and restart.
1164 *
1165 * \param queue_rotate Log queue rotation mode.
1166 *
1167 * \note Assumes logchannels is write locked on entry.
1168 *
1169 * \retval 0 on success.
1170 * \retval -1 on error.
1171 */
1172static int logger_queue_restart(int queue_rotate)
1173{
1174 int res = 0;
1175 char qfname[PATH_MAX];
1176
1177 if (logger_queue_rt_start()) {
1178 return res;
1179 }
1180
1181 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
1182 if (qlog) {
1183 /* Just in case it was still open. */
1184 fclose(qlog);
1185 qlog = NULL;
1186 }
1187 if (queue_rotate) {
1188 rotate_file(qfname);
1189 }
1190
1191 /* Open the log file. */
1192 qlog = fopen(qfname, "a");
1193 if (!qlog) {
1194 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
1195 res = -1;
1196 }
1197 return res;
1198}
1199
1200static int reload_logger(int rotate, const char *altconf)
1201{
1202 int queue_rotate = rotate;
1203 struct logchannel *f;
1204 int res = 0;
1205
1207
1208 if (qlog) {
1209 if (rotate < 0) {
1210 /* Check filesize - this one typically doesn't need an auto-rotate */
1211 if (ftello(qlog) > 0x40000000) { /* Arbitrarily, 1 GB */
1212 fclose(qlog);
1213 qlog = NULL;
1214 } else {
1215 queue_rotate = 0;
1216 }
1217 } else {
1218 fclose(qlog);
1219 qlog = NULL;
1220 }
1221 } else {
1222 queue_rotate = 0;
1223 }
1224
1226
1228 if (f->disabled) {
1229 f->disabled = 0; /* Re-enable logging at reload */
1230 /*** DOCUMENTATION
1231 <managerEvent language="en_US" name="LogChannel">
1232 <managerEventInstance class="EVENT_FLAG_SYSTEM">
1233 <synopsis>Raised when a logging channel is re-enabled after a reload operation.</synopsis>
1234 <syntax>
1235 <parameter name="Channel">
1236 <para>The name of the logging channel.</para>
1237 </parameter>
1238 </syntax>
1239 </managerEventInstance>
1240 </managerEvent>
1241 ***/
1242 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
1243 }
1244 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1245 int rotate_this = 0;
1246 if (rotatestrategy != NONE && ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
1247 /* Be more proactive about rotating massive log files */
1248 rotate_this = 1;
1249 }
1250 fclose(f->fileptr); /* Close file */
1251 f->fileptr = NULL;
1252 if (rotate || rotate_this) {
1254 }
1255 }
1256 }
1257
1259
1260 init_logger_chain(altconf);
1261
1262 ast_unload_realtime("queue_log");
1263 if (logfiles.queue_log) {
1264 res = logger_queue_restart(queue_rotate);
1267 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
1268 ast_verb(1, "Asterisk Queue Logger restarted\n");
1269 } else {
1272 }
1273
1274 return res;
1275}
1276
1277static char *handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1278{
1279 switch (cmd) {
1280 case CLI_INIT:
1281 e->command = "logger reload";
1282 e->usage =
1283 "Usage: logger reload [<alt-conf>]\n"
1284 " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
1285 return NULL;
1286 case CLI_GENERATE:
1287 return NULL;
1288 }
1289 if (reload_logger(0, a->argc == 3 ? a->argv[2] : NULL)) {
1290 ast_cli(a->fd, "Failed to reload the logger\n");
1291 return CLI_FAILURE;
1292 }
1293 return CLI_SUCCESS;
1294}
1295
1296static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1297{
1298 switch (cmd) {
1299 case CLI_INIT:
1300 e->command = "logger rotate";
1301 e->usage =
1302 "Usage: logger rotate\n"
1303 " Rotates and Reopens the log files.\n";
1304 return NULL;
1305 case CLI_GENERATE:
1306 return NULL;
1307 }
1308 if (reload_logger(1, NULL)) {
1309 ast_cli(a->fd, "Failed to reload the logger and rotate log files\n");
1310 return CLI_FAILURE;
1311 }
1312 return CLI_SUCCESS;
1313}
1314
1316{
1317 return reload_logger(1, NULL);
1318}
1319
1320int ast_logger_rotate_channel(const char *log_channel)
1321{
1322 struct logchannel *f;
1323 int success = AST_LOGGER_FAILURE;
1324 char filename[PATH_MAX];
1325
1326 make_filename(log_channel, filename, sizeof(filename));
1327
1329
1331
1333 if (f->disabled) {
1334 f->disabled = 0; /* Re-enable logging at reload */
1335 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n",
1336 f->filename);
1337 }
1338 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1339 fclose(f->fileptr); /* Close file */
1340 f->fileptr = NULL;
1341 if (strcmp(filename, f->filename) == 0) {
1343 success = AST_LOGGER_SUCCESS;
1344 }
1345 }
1346 }
1347
1349
1351
1352 return success;
1353}
1354
1355static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1356{
1357 int x;
1358 int state;
1359 int level = -1;
1360
1361 switch (cmd) {
1362 case CLI_INIT:
1363 e->command = "logger set level {DEBUG|TRACE|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";
1364 e->usage =
1365 "Usage: logger set level {DEBUG|TRACE|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"
1366 " Set a specific log level to enabled/disabled for this console.\n";
1367 return NULL;
1368 case CLI_GENERATE:
1369 return NULL;
1370 }
1371
1372 if (a->argc < 5)
1373 return CLI_SHOWUSAGE;
1374
1376
1377 for (x = 0; x < ARRAY_LEN(levels); x++) {
1378 if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
1379 level = x;
1380 break;
1381 }
1382 }
1383
1385
1386 state = ast_true(a->argv[4]) ? 1 : 0;
1387
1388 if (level != -1) {
1389 ast_console_toggle_loglevel(a->fd, level, state);
1390 ast_cli(a->fd, "Logger status for '%s' has been set to '%s'.\n", levels[level], state ? "on" : "off");
1391 } else
1392 return CLI_SHOWUSAGE;
1393
1394 return CLI_SUCCESS;
1395}
1396
1397int ast_logger_get_channels(int (*logentry)(const char *channel, const char *type,
1398 const char *status, const char *configuration, void *data), void *data)
1399{
1400 struct logchannel *chan;
1401 struct ast_str *configs = ast_str_create(64);
1402 int res = AST_LOGGER_SUCCESS;
1403
1404 if (!configs) {
1406 }
1407
1409 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
1410 unsigned int level;
1411
1413
1414 for (level = 0; level < ARRAY_LEN(levels); level++) {
1415 if ((chan->logmask & (1 << level)) && levels[level]) {
1416 ast_str_append(&configs, 0, "%s ", levels[level]);
1417 }
1418 }
1419
1420 res = logentry(chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" :
1421 (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"), chan->disabled ?
1422 "Disabled" : "Enabled", ast_str_buffer(configs), data);
1423
1424 if (res) {
1427 configs = NULL;
1428 return AST_LOGGER_FAILURE;
1429 }
1430 }
1432
1434 configs = NULL;
1435
1436 return AST_LOGGER_SUCCESS;
1437}
1438
1439/*! \brief CLI command to show logging system configuration */
1440static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1441{
1442#define FORMATL "%-35.35s %-8.8s %-10.10s %-9.9s "
1443 struct logchannel *chan;
1444 switch (cmd) {
1445 case CLI_INIT:
1446 e->command = "logger show channels";
1447 e->usage =
1448 "Usage: logger show channels\n"
1449 " List configured logger channels.\n";
1450 return NULL;
1451 case CLI_GENERATE:
1452 return NULL;
1453 }
1454 ast_cli(a->fd, "Logger queue limit: %d\n\n", logger_queue_limit);
1455 ast_cli(a->fd, FORMATL, "Channel", "Type", "Formatter", "Status");
1456 ast_cli(a->fd, "Configuration\n");
1457 ast_cli(a->fd, FORMATL, "-------", "----", "---------", "------");
1458 ast_cli(a->fd, "-------------\n");
1461 unsigned int level;
1462
1463 ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
1464 chan->formatter.name,
1465 chan->disabled ? "Disabled" : "Enabled");
1466 ast_cli(a->fd, " - ");
1467 for (level = 0; level < ARRAY_LEN(levels); level++) {
1468 if ((chan->logmask & (1 << level)) && levels[level]) {
1469 ast_cli(a->fd, "%s ", levels[level]);
1470 }
1471 }
1472 ast_cli(a->fd, "\n");
1473 }
1475 ast_cli(a->fd, "\n");
1476
1477 return CLI_SUCCESS;
1478}
1479
1480/*! \brief CLI command to show logging levels */
1481static char *handle_logger_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1482{
1483#define FORMATL2 "%5s %s\n"
1484 unsigned int level;
1485 switch (cmd) {
1486 case CLI_INIT:
1487 e->command = "logger show levels";
1488 e->usage =
1489 "Usage: logger show levels\n"
1490 " List configured logger levels.\n";
1491 return NULL;
1492 case CLI_GENERATE:
1493 return NULL;
1494 }
1495 ast_cli(a->fd, FORMATL2, "Level", "Name");
1496 ast_cli(a->fd, FORMATL2, "-----", "----");
1498 for (level = 0; level < ARRAY_LEN(levels); level++) {
1499 if (levels[level]) {
1500 ast_cli(a->fd, "%5d %s\n", level, levels[level]);
1501 }
1502 }
1504 ast_cli(a->fd, "\n");
1505
1506 return CLI_SUCCESS;
1507}
1508
1509int ast_logger_create_channel(const char *log_channel, const char *components)
1510{
1511 struct logchannel *chan;
1512
1514 return AST_LOGGER_DECLINE;
1515 }
1516
1518
1519 chan = find_logchannel(log_channel);
1520 if (chan) {
1522 return AST_LOGGER_FAILURE;
1523 }
1524
1525 chan = make_logchannel(log_channel, components, 0, 1);
1526 if (!chan) {
1529 }
1530
1532 global_logmask |= chan->logmask;
1533
1535
1536 return AST_LOGGER_SUCCESS;
1537}
1538
1539static char *handle_logger_add_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1540{
1541 switch (cmd) {
1542 case CLI_INIT:
1543 e->command = "logger add channel";
1544 e->usage =
1545 "Usage: logger add channel <name> <levels>\n"
1546 " Adds a temporary logger channel. This logger channel\n"
1547 " will exist until removed or until Asterisk is restarted.\n"
1548 " <levels> is a comma-separated list of desired logger\n"
1549 " levels such as: verbose,warning,error\n"
1550 " An optional formatter may be specified with the levels;\n"
1551 " valid values are '[json]' and '[default]'.\n";
1552 return NULL;
1553 case CLI_GENERATE:
1554 return NULL;
1555 }
1556
1557 if (a->argc < 5) {
1558 return CLI_SHOWUSAGE;
1559 }
1560
1561 switch (ast_logger_create_channel(a->argv[3], a->argv[4])) {
1562 case AST_LOGGER_SUCCESS:
1563 return CLI_SUCCESS;
1564 case AST_LOGGER_FAILURE:
1565 ast_cli(a->fd, "Logger channel '%s' already exists\n", a->argv[3]);
1566 return CLI_SUCCESS;
1567 case AST_LOGGER_DECLINE:
1569 default:
1570 ast_cli(a->fd, "ERROR: Unable to create log channel '%s'\n", a->argv[3]);
1571 return CLI_FAILURE;
1572 }
1573}
1574
1575int ast_logger_remove_channel(const char *log_channel)
1576{
1577 struct logchannel *chan;
1578
1580
1581 chan = find_logchannel(log_channel);
1582 if (chan && chan->dynamic) {
1584 } else {
1586 return AST_LOGGER_FAILURE;
1587 }
1589
1590 if (chan->fileptr) {
1591 fclose(chan->fileptr);
1592 chan->fileptr = NULL;
1593 }
1594 ast_free(chan);
1595 chan = NULL;
1596
1597 return AST_LOGGER_SUCCESS;
1598}
1599
1600static char *handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1601{
1602 struct logchannel *chan;
1603 int gen_count = 0;
1604 char *gen_ret = NULL;
1605
1606 switch (cmd) {
1607 case CLI_INIT:
1608 e->command = "logger remove channel";
1609 e->usage =
1610 "Usage: logger remove channel <name>\n"
1611 " Removes a temporary logger channel.\n";
1612 return NULL;
1613 case CLI_GENERATE:
1614 if (a->argc > 4 || (a->argc == 4 && a->pos > 3)) {
1615 return NULL;
1616 }
1619 if (chan->dynamic && (ast_strlen_zero(a->argv[3])
1620 || !strncmp(a->argv[3], chan->filename, strlen(a->argv[3])))) {
1621 if (gen_count == a->n) {
1622 gen_ret = ast_strdup(chan->filename);
1623 break;
1624 }
1625 gen_count++;
1626 }
1627 }
1629 return gen_ret;
1630 }
1631
1632 if (a->argc < 4) {
1633 return CLI_SHOWUSAGE;
1634 }
1635
1636 switch (ast_logger_remove_channel(a->argv[3])) {
1637 case AST_LOGGER_SUCCESS:
1638 ast_cli(a->fd, "Removed dynamic logger channel '%s'\n", a->argv[3]);
1639 return CLI_SUCCESS;
1640 case AST_LOGGER_FAILURE:
1641 ast_cli(a->fd, "Unable to find dynamic logger channel '%s'\n", a->argv[3]);
1642 return CLI_SUCCESS;
1643 default:
1644 ast_cli(a->fd, "Internal failure attempting to delete dynamic logger channel '%s'\n", a->argv[3]);
1645 return CLI_FAILURE;
1646 }
1647}
1648
1649/* Call ID filtering */
1650
1652
1653/*! \brief map call ID to group */
1656 char name[0];
1657};
1658
1660
1661static int callid_filtering = 0;
1662
1663static const char *get_callid_group(void)
1664{
1665 char **callid_group;
1666 callid_group = ast_threadstorage_get(&callid_group_name, sizeof(*callid_group));
1667 return callid_group ? *callid_group : NULL;
1668}
1669
1670static int callid_set_chanloggroup(const char *group)
1671{
1672 /* Use threadstorage for constant time access, rather than a linked list */
1673 ast_callid callid;
1674 char **callid_group;
1675
1677 if (!callid) {
1678 /* Should never be called on non-PBX threads */
1679 ast_assert(0);
1680 return -1;
1681 }
1682
1683 callid_group = ast_threadstorage_get(&callid_group_name, sizeof(*callid_group));
1684
1685 if (!group) {
1686 /* Remove from list */
1687 if (!*callid_group) {
1688 return 0; /* Wasn't in any group to begin with */
1689 }
1690 ast_free(*callid_group);
1691 return 0; /* Set Call ID group for the first time */
1692 }
1693 /* Existing group */
1694 ast_free(*callid_group);
1695 *callid_group = ast_strdup(group);
1696 if (!*callid_group) {
1697 return -1;
1698 }
1699 return 0; /* Set Call ID group for the first time */
1700}
1701
1703{
1704 int i = 0;
1705 struct chan_group_lock *cgl;
1706
1709 ast_free(cgl);
1710 i++;
1711 }
1712 callid_filtering = 0;
1714 return i;
1715}
1716
1717static int callid_group_set_filter(const char *group, int enabled)
1718{
1719 struct chan_group_lock *cgl;
1720
1723 if (!strcmp(group, cgl->name)) {
1724 if (!enabled) {
1726 ast_free(cgl);
1727 }
1728 break;
1729 }
1730 }
1732
1733 if (!enabled) {
1735 callid_filtering = 0;
1736 }
1738 return 0;
1739 }
1740
1741 if (!cgl) {
1742 cgl = ast_calloc(1, sizeof(*cgl) + strlen(group) + 1);
1743 if (!cgl) {
1745 return -1;
1746 }
1747 strcpy(cgl->name, group); /* Safe */
1749 } /* else, already existed, and was already enabled, no change */
1750 callid_filtering = 1;
1752 return 0;
1753}
1754
1756{
1757 struct chan_group_lock *cgl;
1758 const char *callidgroup;
1759
1760 if (!callid_filtering) {
1761 return 1; /* Everything enabled by default, if no filtering */
1762 }
1763
1764 callidgroup = get_callid_group();
1765 if (!callidgroup) {
1766 return 0; /* Filtering, but no call group, not enabled */
1767 }
1768
1771 if (!strcmp(callidgroup, cgl->name)) {
1772 break;
1773 }
1774 }
1776 return cgl ? 1 : 0; /* If found, enabled, otherwise not */
1777}
1778
1779static int log_group_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1780{
1781 int res = callid_set_chanloggroup(value);
1782 if (res) {
1783 ast_log(LOG_ERROR, "Failed to set channel log group for %s\n", ast_channel_name(chan));
1784 return -1;
1785 }
1786 return 0;
1787}
1788
1790 .name = "LOG_GROUP",
1791 .write = log_group_write,
1792};
1793
1794static char *handle_logger_chanloggroup_filter(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1795{
1796 int enabled;
1797
1798 switch (cmd) {
1799 case CLI_INIT:
1800 e->command = "logger filter changroup";
1801 e->usage =
1802 "Usage: logger filter changroup <group> {on|off}\n"
1803 " Add or remove channel groups from log filtering.\n"
1804 " If filtering is active, only channels assigned\n"
1805 " to a group that has been enabled using this command\n"
1806 " will have execution shown in the CLI.\n";
1807 return NULL;
1808 case CLI_GENERATE:
1809 return NULL;
1810 }
1811
1812 if (a->argc < 5) {
1813 return CLI_SHOWUSAGE;
1814 }
1815
1816 enabled = ast_true(a->argv[4]) ? 1 : 0;
1817 if (callid_group_set_filter(a->argv[3], enabled)) {
1818 ast_cli(a->fd, "Failed to set channel group filter for group %s\n", a->argv[3]);
1819 return CLI_FAILURE;
1820 }
1821
1822 ast_cli(a->fd, "Logging of channel group '%s' is now %s\n", a->argv[3], enabled ? "enabled" : "disabled");
1823 return CLI_SUCCESS;
1824}
1825
1826static char *handle_logger_filter_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1827{
1828 int i = 0;
1829 struct chan_group_lock *cgl;
1830
1831 switch (cmd) {
1832 case CLI_INIT:
1833 e->command = "logger filter show";
1834 e->usage =
1835 "Usage: logger filter show\n"
1836 " Show current logger filtering settings.\n";
1837 return NULL;
1838 case CLI_GENERATE:
1839 return NULL;
1840 }
1841
1844 ast_cli(a->fd, "%3d %-32s\n", ++i, cgl->name);
1845 }
1847
1848 if (i) {
1849 ast_cli(a->fd, "%d channel group%s currently enabled\n", i, ESS(i));
1850 } else {
1851 ast_cli(a->fd, "No filtering currently active\n");
1852 }
1853 return CLI_SUCCESS;
1854}
1855
1856static char *handle_logger_filter_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1857{
1858 int removed;
1859
1860 switch (cmd) {
1861 case CLI_INIT:
1862 e->command = "logger filter reset";
1863 e->usage =
1864 "Usage: logger filter reset\n"
1865 " Reset the logger filter.\n"
1866 " This removes any channel groups from filtering\n"
1867 " (all channel execution will be shown)\n";
1868 return NULL;
1869 case CLI_GENERATE:
1870 return NULL;
1871 }
1872
1873 removed = callid_group_remove_filters();
1874
1875 ast_cli(a->fd, "Log filtering has been reset (%d filter%s removed)\n", removed, ESS(removed));
1876 return CLI_SUCCESS;
1877}
1878
1879static struct ast_cli_entry cli_logger[] = {
1880 AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),
1881 AST_CLI_DEFINE(handle_logger_show_levels, "List configured log levels"),
1882 AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
1883 AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
1884 AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),
1885 AST_CLI_DEFINE(handle_logger_add_channel, "Adds a new logging channel"),
1886 AST_CLI_DEFINE(handle_logger_remove_channel, "Removes a logging channel"),
1887 AST_CLI_DEFINE(handle_logger_chanloggroup_filter, "Filter PBX logs by channel log group"),
1888 AST_CLI_DEFINE(handle_logger_filter_show, "Show current PBX channel filtering"),
1889 AST_CLI_DEFINE(handle_logger_filter_reset, "Reset PBX channel filtering"),
1890};
1891
1892static void _handle_SIGXFSZ(int sig)
1893{
1894 /* Indicate need to reload */
1896}
1897
1898static struct sigaction handle_SIGXFSZ = {
1899 .sa_handler = _handle_SIGXFSZ,
1900 .sa_flags = SA_RESTART,
1901};
1902
1903/*! \brief Print a normal log message to the channels */
1905{
1906 struct logchannel *chan = NULL;
1907 char buf[LOGMSG_SIZE];
1908 int level = 0;
1909
1913
1914 /* If the channel is disabled, then move on to the next one */
1915 if (chan->disabled) {
1916 continue;
1917 }
1918 if (logmsg->level == __LOG_VERBOSE
1919 && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
1920 continue;
1921 }
1922
1923 if (!(chan->logmask & (1 << logmsg->level))) {
1924 continue;
1925 }
1926
1927 switch (chan->type) {
1928 case LOGTYPE_SYSLOG:
1929 {
1930 int syslog_level = ast_syslog_priority_from_loglevel(logmsg->level);
1931
1932 if (syslog_level < 0) {
1933 /* we are locked here, so cannot ast_log() */
1934 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", logmsg->level);
1935 continue;
1936 }
1937
1938 /* Don't use LOG_MAKEPRI because it's broken in glibc<2.17 */
1939 syslog_level = chan->facility | syslog_level; /* LOG_MAKEPRI(chan->facility, syslog_level); */
1940 if (!chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) {
1941 syslog(syslog_level, "%s", buf);
1942 }
1943 }
1944 break;
1945 case LOGTYPE_CONSOLE:
1946 if (!logmsg->hidecli && !chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) {
1948 }
1949 break;
1950 case LOGTYPE_FILE:
1951 {
1952 int res = 0;
1953
1954 if (!chan->fileptr) {
1955 continue;
1956 }
1957
1958 if (chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) {
1959 continue;
1960 }
1961
1962 /* Print out to the file */
1963 res = fprintf(chan->fileptr, "%s", buf);
1964 if (res > 0) {
1965 fflush(chan->fileptr);
1966 } else if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
1967 fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
1968 if (errno == ENOMEM || errno == ENOSPC) {
1969 fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
1970 } else {
1971 fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
1972 }
1973
1974 /*** DOCUMENTATION
1975 <managerEventInstance>
1976 <synopsis>Raised when a logging channel is disabled.</synopsis>
1977 <syntax>
1978 <parameter name="Channel">
1979 <para>The name of the logging channel.</para>
1980 </parameter>
1981 </syntax>
1982 </managerEventInstance>
1983 ***/
1984 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
1985 chan->disabled = 1;
1986 }
1987 }
1988 break;
1989 }
1990 }
1991 } else if (logmsg->level != __LOG_VERBOSE || option_verbose >= logmsg->sublevel) {
1992 fputs(logmsg->message, stdout);
1993 }
1994
1996
1997 /* If we need to reload because of the file size, then do so */
1999 reload_logger(-1, NULL);
2000 ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
2001 }
2002
2003 return;
2004}
2005
2006static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message_ap(int level,
2007 int sublevel, const char *file, int line, const char *function, ast_callid callid,
2008 const char *fmt, va_list ap)
2009{
2010 struct logmsg *logmsg = NULL;
2011 struct ast_str *buf = NULL;
2012 struct ast_tm tm;
2013 struct timeval now = ast_tvnow();
2014 int res = 0;
2015 char datestring[256];
2016
2018 return NULL;
2019 }
2020
2021 /* Build string */
2022 res = ast_str_set_va(&buf, LOGMSG_SIZE, fmt, ap);
2023
2024 /* If the build failed, then abort and free this structure */
2025 if (res == AST_DYNSTR_BUILD_FAILED) {
2026 return NULL;
2027 }
2028
2029 /* Automatically add a newline to format strings that don't have one */
2030 if (!ast_ends_with(ast_str_buffer(buf), "\n")) {
2031 ast_str_append(&buf, 0, "\n");
2032 }
2033
2034 /* Create a new logging message */
2035 if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) {
2036 return NULL;
2037 }
2038
2039 /* Copy string over */
2041
2042 /* Set type */
2043 if (level == __LOG_VERBOSE) {
2045 } else {
2047 }
2048
2049 if (display_callids && callid) {
2050 logmsg->callid = callid;
2051 }
2052
2053 /* Create our date/time */
2054 ast_localtime(&now, &tm, NULL);
2055 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
2056 ast_string_field_set(logmsg, date, datestring);
2057
2058 /* Copy over data */
2059 logmsg->level = level;
2060 logmsg->sublevel = sublevel;
2061 logmsg->line = line;
2062 ast_string_field_set(logmsg, level_name, levels[level]);
2064 ast_string_field_set(logmsg, function, function);
2065 logmsg->lwp = ast_get_tid();
2066
2067 return logmsg;
2068}
2069
2070static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message(int level,
2071 int sublevel, const char *file, int line, const char *function, ast_callid callid,
2072 const char *fmt, ...)
2073{
2074 struct logmsg *logmsg;
2075 va_list ap;
2076
2077 va_start(ap, fmt);
2079 va_end(ap);
2080
2081 return logmsg;
2082}
2083
2084/*! \brief Actual logging thread */
2085static void *logger_thread(void *data)
2086{
2087 struct logmsg *next = NULL, *msg = NULL;
2088
2089 for (;;) {
2090 /* We lock the message list, and see if any message exists... if not we wait on the condition to be signalled */
2092 if (AST_LIST_EMPTY(&logmsgs)) {
2093 if (close_logger_thread) {
2095 break;
2096 } else {
2098 }
2099 }
2100
2101 if (high_water_alert) {
2102 msg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
2103 "Logging resumed. %d message%s discarded.\n",
2105 if (msg) {
2107 }
2108 high_water_alert = 0;
2110 }
2111
2116
2117 /* Otherwise go through and process each message in the order added */
2118 while ((msg = next)) {
2119 /* Get the next entry now so that we can free our current structure later */
2120 next = AST_LIST_NEXT(msg, list);
2121
2122 /* Depending on the type, send it to the proper function */
2124
2125 /* Free the data since we are done */
2126 logmsg_free(msg);
2127 }
2128 }
2129
2130 return NULL;
2131}
2132
2133/*!
2134 * \internal
2135 * \brief Initialize the logger queue.
2136 *
2137 * \note Assumes logchannels is write locked on entry.
2138 */
2139static void logger_queue_init(void)
2140{
2141 ast_unload_realtime("queue_log");
2142 if (logfiles.queue_log) {
2143 char qfname[PATH_MAX];
2144
2145 if (logger_queue_rt_start()) {
2146 return;
2147 }
2148
2149 /* Open the log file. */
2150 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR,
2152 if (qlog) {
2153 /* Just in case it was already open. */
2154 fclose(qlog);
2155 }
2156 qlog = fopen(qfname, "a");
2157 if (!qlog) {
2158 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
2159 }
2160 }
2161}
2162
2164{
2165 return logger_initialized;
2166}
2167
2168/*!
2169 * \brief Start the ast_queue_log() logger.
2170 *
2171 * \note Called when the system is fully booted after startup
2172 * so preloaded realtime modules can get up.
2173 */
2175{
2176 /* Must not be called before the logger is initialized. */
2178
2180 if (!queuelog_init) {
2182 queuelog_init = 1;
2184 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
2185 } else {
2187 }
2188}
2189
2191{
2192 int res;
2193 /* auto rotate if sig SIGXFSZ comes a-knockin */
2194 sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
2195
2196 /* Re-initialize the logmsgs mutex. The recursive mutex can be accessed prior
2197 * to Asterisk being forked into the background, which can cause the thread
2198 * ID tracked by the underlying pthread mutex to be different than the ID of
2199 * the thread that unlocks the mutex. Since init_logger is called after the
2200 * fork, it is safe to initialize the mutex here for future accesses.
2201 */
2205
2206 /* start logger thread */
2209 return -1;
2210 }
2211
2212 /* register the logger cli commands */
2215
2217
2218 /* create log channels */
2220 res = init_logger_chain(NULL);
2224 if (res) {
2225 ast_log(LOG_ERROR, "Errors detected in logger.conf. Default console logging is being used.\n");
2226 }
2227
2229
2230 return 0;
2231}
2232
2234{
2235 struct logchannel *f = NULL;
2236
2238
2241
2243
2244 /* Stop logger thread */
2249
2251 pthread_join(logthread, NULL);
2252 }
2253
2255
2256 if (qlog) {
2257 fclose(qlog);
2258 qlog = NULL;
2259 }
2260
2261 while ((f = AST_LIST_REMOVE_HEAD(&logchannels, list))) {
2262 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
2263 fclose(f->fileptr);
2264 f->fileptr = NULL;
2265 }
2266 ast_free(f);
2267 }
2268
2270
2271 closelog(); /* syslog */
2272
2274}
2275
2276void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid)
2277{
2278 snprintf(buffer, buffer_size, "[C-%08x]", callid);
2279}
2280
2282{
2284}
2285
2287{
2288 ast_callid *callid;
2289
2290 callid = ast_threadstorage_get(&unique_callid, sizeof(*callid));
2291
2292 return callid ? *callid : 0;
2293}
2294
2296{
2297 ast_callid *id = ast_threadstorage_get(&unique_callid, sizeof(*id));
2298
2299 if (!id) {
2300 return -1;
2301 }
2302
2303 *id = callid;
2304
2305 return 0;
2306}
2307
2309{
2310 ast_callid *pointing;
2311
2312 pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
2313 if (!pointing) {
2314 return -1;
2315 }
2316
2317 if (*pointing) {
2318 ast_log(LOG_ERROR, "ast_callid_threadassoc_add(C-%08x) on thread "
2319 "already associated with callid [C-%08x].\n", callid, *pointing);
2320 return 1;
2321 }
2322
2323 *pointing = callid;
2324 return 0;
2325}
2326
2328{
2329 ast_callid *pointing;
2330
2331 pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
2332 if (!pointing) {
2333 return -1;
2334 }
2335
2336 if (*pointing) {
2337 *pointing = 0;
2338 return 0;
2339 }
2340
2341 return -1;
2342}
2343
2345{
2347
2348 /* Start by trying to see if a callid is available from thread storage */
2350 if (tmp) {
2351 *callid = tmp;
2352 return 0;
2353 }
2354
2355 /* If that failed, try to create a new one and bind it. */
2356 *callid = ast_create_callid();
2357 if (*callid) {
2359 return 1;
2360 }
2361
2362 /* If neither worked, then something must have gone wrong. */
2363 return -1;
2364}
2365
2366void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created)
2367{
2368 if (callid && callid_created) {
2369 /* If the callid was created rather than simply grabbed from the thread storage, we need to unbind here. */
2371 }
2372}
2373
2374/*!
2375 * \brief send log messages to syslog and/or the console
2376 */
2377static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel,
2378 const char *file, int line, const char *function, ast_callid callid,
2379 const char *fmt, va_list ap)
2380{
2381 int hidecli = 0;
2382 struct logmsg *logmsg = NULL;
2383
2385 return;
2386 }
2387
2389 switch (level) {
2390 case __LOG_VERBOSE:
2391 case __LOG_DEBUG:
2392 case __LOG_TRACE:
2393 case __LOG_DTMF:
2394 hidecli = 1; /* Hide the message from the CLI, but still log to any log files */
2395 default: /* Always show NOTICE, WARNING, ERROR, etc. */
2396 break;
2397 }
2398 return;
2399 }
2400
2405 logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
2406 "Log queue threshold (%d) exceeded. Discarding new messages.\n", logger_queue_limit);
2408 high_water_alert = 1;
2410 }
2412 return;
2413 }
2415
2417 if (!logmsg) {
2418 return;
2419 }
2420
2422
2423 /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */
2426 if (close_logger_thread) {
2427 /* Logger is either closing or closed. We cannot log this message. */
2429 } else {
2433 }
2435 } else {
2438 }
2439}
2440
2441void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
2442{
2443 va_list ap;
2444
2445 va_start(ap, fmt);
2446 ast_log_ap(level, file, line, function, fmt, ap);
2447 va_end(ap);
2448}
2449
2450void ast_log_ap(int level, const char *file, int line, const char *function, const char *fmt, va_list ap)
2451{
2453
2455
2456 if (level == __LOG_VERBOSE) {
2457 __ast_verbose_ap(file, line, function, 0, callid, fmt, ap);
2458 } else {
2459 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2460 }
2461}
2462
2463void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt, ...)
2464{
2465 va_list ap;
2466 void *recursed = ast_threadstorage_get_ptr(&in_safe_log);
2468
2469 if (recursed) {
2470 return;
2471 }
2472
2473 if (ast_threadstorage_set_ptr(&in_safe_log, &(int) { 1 })) {
2474 /* We've failed to set the flag that protects against
2475 * recursion, so bail. */
2476 return;
2477 }
2478
2480
2481 va_start(ap, fmt);
2482 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2483 va_end(ap);
2484
2485 /* Clear flag so the next allocation failure can be logged. */
2486 ast_threadstorage_set_ptr(&in_safe_log, NULL);
2487}
2488
2489void ast_log_callid(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt, ...)
2490{
2491 va_list ap;
2492 va_start(ap, fmt);
2493 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2494 va_end(ap);
2495}
2496
2497
2499{
2500#ifdef HAVE_BKTR
2501 struct ast_bt *bt;
2502 int i = 0;
2503 struct ast_vector_string *strings;
2504
2505 if (!(bt = ast_bt_create())) {
2506 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
2507 return;
2508 }
2509
2510 if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
2511 int count = AST_VECTOR_SIZE(strings);
2512 struct ast_str *buf = ast_str_create(bt->num_frames * 64);
2513
2514 if (buf) {
2515 ast_str_append(&buf, 0, "Got %d backtrace record%c\n", count - 3, count - 3 != 1 ? 's' : ' ');
2516 for (i = 3; i < AST_VECTOR_SIZE(strings); i++) {
2517 ast_str_append(&buf, 0, "#%2d: %s\n", i - 3, AST_VECTOR_GET(strings, i));
2518 }
2520 ast_free(buf);
2521 }
2522
2523 ast_bt_free_symbols(strings);
2524 } else {
2525 ast_log(LOG_ERROR, "Could not allocate memory for backtrace\n");
2526 }
2527 ast_bt_destroy(bt);
2528#else
2529 ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
2530#endif /* defined(HAVE_BKTR) */
2531}
2532
2533void __ast_verbose_ap(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, va_list ap)
2534{
2535 ast_log_full(__LOG_VERBOSE, level, file, line, func, callid, fmt, ap);
2536}
2537
2538void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
2539{
2540 ast_callid callid;
2541 va_list ap;
2542
2544
2545 va_start(ap, fmt);
2546 __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
2547 va_end(ap);
2548}
2549
2550void __ast_verbose_callid(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, ...)
2551{
2552 va_list ap;
2553 va_start(ap, fmt);
2554 __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
2555 va_end(ap);
2556}
2557
2558/*! Console verbosity level node. */
2560 /*! List node link */
2562 /*! Console verbosity level. */
2563 int *level;
2564};
2565
2566/*! Registered console verbosity levels */
2568
2569/*! ast_verb_update() reentrancy protection lock. */
2571
2573{
2574 struct logchannel *log;
2575 struct verb_console *console;
2576 int verb_level;
2577
2579
2581
2582 /* Default to the root console verbosity. */
2583 verb_level = option_verbose;
2584
2585 /* Determine max remote console level. */
2587 if (verb_level < *console->level) {
2588 verb_level = *console->level;
2589 }
2590 }
2592
2593 /* Determine max logger channel level. */
2595 AST_RWLIST_TRAVERSE(&logchannels, log, list) {
2596 if (verb_level < log->verbosity) {
2597 verb_level = log->verbosity;
2598 }
2599 }
2601
2602 ast_verb_sys_level = verb_level;
2603
2605}
2606
2607/*!
2608 * \internal
2609 * \brief Unregister a console verbose level.
2610 *
2611 * \param console Which console to unregister.
2612 */
2614{
2618 if (console) {
2620 }
2621}
2622
2623static void verb_console_free(void *v_console)
2624{
2625 struct verb_console *console = v_console;
2626
2629}
2630
2631/*! Thread specific console verbosity level node. */
2633
2635{
2636 struct verb_console *console;
2637
2639 if (!console || !level) {
2640 return;
2641 }
2642 console->level = level;
2643
2648}
2649
2651{
2652 struct verb_console *console;
2653
2655 if (!console) {
2656 return;
2657 }
2659}
2660
2662{
2663 struct verb_console *console;
2664 int verb_level;
2665
2668 if (!console) {
2669 verb_level = 0;
2670 } else if (console->level) {
2671 verb_level = *console->level;
2672 } else {
2673 verb_level = option_verbose;
2674 }
2676 return verb_level;
2677}
2678
2679void ast_verb_console_set(int verb_level)
2680{
2681 struct verb_console *console;
2682
2684 if (!console) {
2685 return;
2686 }
2687
2689 if (console->level) {
2690 *console->level = verb_level;
2691 } else {
2692 option_verbose = verb_level;
2693 }
2696}
2697
2698static void update_logchannels(void)
2699{
2700 struct logchannel *cur;
2701
2702 global_logmask = 0;
2703
2705 make_components(cur);
2706 global_logmask |= cur->logmask;
2707 }
2708}
2709
2710#ifdef AST_DEVMODE
2711
2712AST_THREADSTORAGE_RAW(trace_indent);
2713#define LOTS_O_SPACES " "
2714
2715unsigned long _ast_trace_get_indent(void)
2716{
2717 return (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2718}
2719
2720void _ast_trace_set_indent(unsigned long indent)
2721{
2722 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2723}
2724
2725unsigned long _ast_trace_inc_indent(void)
2726{
2727 unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2728 indent++;
2729 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2730
2731 return indent;
2732}
2733
2734unsigned long _ast_trace_dec_indent(void)
2735{
2736 unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2737 indent--;
2738 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2739
2740 return indent;
2741}
2742
2743void __ast_trace(const char *file, int line, const char *func, enum ast_trace_indent_type indent_type,
2744 unsigned long new_indent, const char* format, ...)
2745{
2746 va_list ap;
2747 unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);
2748 struct ast_str *fmt = ast_str_create(128);
2749 const char *direction = "";
2750
2751 if (!fmt) {
2752 return;
2753 }
2754
2755 if (indent_type == AST_TRACE_INDENT_PROVIDED) {
2756 indent = new_indent;
2757 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2758 } else if (indent_type == AST_TRACE_INDENT_INC_BEFORE) {
2759 indent++;
2760 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2761 } else if (indent_type == AST_TRACE_INDENT_DEC_BEFORE) {
2762 indent--;
2763 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2764 }
2765
2766 switch(indent_type) {
2769 direction = "";
2770 break;
2774 direction = "--> ";
2775 break;
2778 direction = "<-- ";
2779 break;
2780 }
2781
2782 ast_str_set(&fmt, 0, "%2d %-.*s%s%s:%d %s: %s", (int)indent, (indent_type == AST_TRACE_INDENT_NONE ? 0 : (int)(indent * 4)),
2783 LOTS_O_SPACES, direction, file, line, func, S_OR(ast_skip_blanks(format), "\n"));
2784
2785 if (indent_type == AST_TRACE_INDENT_INC_AFTER || indent_type == AST_TRACE_INDENT_PROVIDED) {
2786 indent++;
2787 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2788 }
2789 if (indent_type == AST_TRACE_INDENT_DEC_AFTER) {
2790 indent--;
2791 ast_threadstorage_set_ptr(&trace_indent, (void*)indent);
2792 }
2793
2794 va_start(ap, format);
2795 ast_log_full(__LOG_TRACE, -1, NULL, 0, NULL, 0, ast_str_buffer(fmt), ap);
2796 va_end(ap);
2797 ast_free(fmt);
2798}
2799#endif
2800
2801/* Lock should be held before calling this function */
2802static int logger_register_level(const char *name)
2803{
2804 unsigned int level;
2805 unsigned int available = 0;
2806
2807 for (level = 0; level < ARRAY_LEN(levels); level++) {
2808 if ((level >= 16) && !available && !levels[level]) {
2809 available = level;
2810 continue;
2811 }
2812
2813 if (levels[level] && !strcasecmp(levels[level], name)) {
2815 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
2816 name);
2817
2818 return -1;
2819 }
2820 }
2821
2822 if (!available) {
2824 "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
2825 name);
2826
2827 return -1;
2828 }
2829
2831
2832 ast_debug(1, "Registered dynamic logger level '%s' with index %u.\n", name, available);
2833
2835
2836 return available;
2837}
2838
2840{
2841 int available = 0;
2842
2846
2847 return available;
2848}
2849
2850static int logger_get_dynamic_level(const char *name)
2851{
2852 int level = -1;
2853 unsigned int x;
2854
2855 for (x = 16; x < ARRAY_LEN(levels); x++) {
2856 if (!levels[x]) {
2857 continue;
2858 }
2859 if (!strcasecmp(levels[x], name)) {
2860 level = x;
2861 break;
2862 }
2863 }
2864
2865 return level;
2866}
2867
2869{
2870 int level = -1;
2871
2873
2875
2877
2878 return level;
2879}
2880
2881static int logger_unregister_level(const char *name) {
2882 unsigned int x;
2883
2885 if (x == -1) {
2886 return 0;
2887 }
2888 /* take this level out of the global_logmask, to ensure that no new log messages
2889 * will be queued for it
2890 */
2891 global_logmask &= ~(1 << x);
2892 ast_free(levels[x]);
2893 levels[x] = NULL;
2894 return x;
2895}
2896
2898{
2899 int x;
2900
2903
2904 if (x) {
2906 }
2907
2909
2910 if (x) {
2911 ast_debug(1, "Unregistered dynamic logger level '%s' with index %u.\n", name, x);
2912 }
2913}
2914
2916{
2917 return dateformat;
2918}
2919
2920void ast_logger_set_queue_limit(int queue_limit)
2921{
2922 logger_queue_limit = queue_limit;
2923}
2924
2926{
2927 return logger_queue_limit;
2928}
2929
2930static int reload_module(void)
2931{
2932 return reload_logger(0, NULL);
2933}
2934
2935static int unload_module(void)
2936{
2937 return 0;
2938}
2939
2940static int load_module(void)
2941{
2943}
2944
2945/* Logger is initialized separate from the module loader, only reload_module does anything. */
2947 .support_level = AST_MODULE_SUPPORT_CORE,
2948 .load = load_module,
2949 .unload = unload_module,
2950 /* This reload does not support realtime so it does not require "extconfig". */
2952 .load_pri = 0,
Prototypes for public functions only of internal interest,.
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:605
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
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
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
static int tmp()
Definition: bt_open.c:389
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
enum cc_state state
Definition: ccss.c:393
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13460
static const char type[]
Definition: chan_ooh323.c:109
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:2958
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#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
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:701
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:64
int option_verbose
Definition: options.c:67
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:829
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
char * strsep(char **str, const char *delims)
Configuration File Parser.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3321
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3549
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3576
#define CONFIG_STATUS_FILEINVALID
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3530
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:783
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
Definition: main/config.c:3740
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
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 __LOG_TRACE
void ast_console_toggle_loglevel(int fd, int level, int state)
enables or disables logging of a specified level to the console fd specifies the index of the console...
Definition: asterisk.c:1247
#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:1312
unsigned int ast_callid
#define __LOG_DTMF
#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_1
#define __LOG_DEBUG
#define __LOG_WARNING
#define LOG_ERROR
#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:1319
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
Definition: linkedlists.h:452
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:291
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#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.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:844
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:885
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:415
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
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:202
#define ast_cond_wait(cond, mutex)
Definition: lock.h:205
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_cond_init(cond, attr)
Definition: lock.h:201
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
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:757
pthread_cond_t ast_cond_t
Definition: lock.h:178
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
#define ast_cond_signal(cond)
Definition: lock.h:203
unsigned int queue_log_to_file
Definition: logger.c:114
int ast_logger_get_dynamic_level(const char *name)
Retrieve dynamic logging level id.
Definition: logger.c:2868
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:577
static int format_log_json(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
Definition: logger.c:276
static int init_logger_chain(const char *altconf)
Read config, setup channels.
Definition: logger.c:747
int ast_logger_get_queue_limit(void)
Get the maximum number of messages allowed in the processing queue.
Definition: logger.c:2925
static unsigned int global_logmask
Definition: logger.c:87
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:2533
static int format_log_plain(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
Definition: logger.c:446
int ast_logger_rotate_channel(const char *log_channel)
Rotate the specified log channel.
Definition: logger.c:1320
static char * handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1600
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:2276
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:1440
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:1481
AST_THREADSTORAGE_RAW(in_safe_log)
static void verb_console_free(void *v_console)
Definition: logger.c:2623
static int callid_group_remove_filters(void)
Definition: logger.c:1702
static char dateformat[256]
Definition: logger.c:81
static int queuelog_init
Definition: logger.c:88
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:2366
void logger_queue_start(void)
Start the ast_queue_log() logger.
Definition: logger.c:2174
void ast_verb_console_unregister(void)
Unregister this thread's console verbosity level.
Definition: logger.c:2650
logmsgtypes
Definition: logger.c:167
@ LOGMSG_NORMAL
Definition: logger.c:168
@ LOGMSG_VERBOSE
Definition: logger.c:169
static char * levels[NUMLOGLEVELS]
Logging channels used in the Asterisk logging system.
Definition: logger.c:214
static int callid_filtering
Definition: logger.c:1661
static int filesize_reload_needed
Definition: logger.c:86
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:727
static struct ast_custom_function log_group_function
Definition: logger.c:1789
int ast_logger_create_channel(const char *log_channel, const char *components)
Create a log channel.
Definition: logger.c:1509
static void _handle_SIGXFSZ(int sig)
Definition: logger.c:1892
void ast_verb_console_register(int *level)
Register this thread's console verbosity level pointer.
Definition: logger.c:2634
static int log_group_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: logger.c:1779
static char * handle_logger_chanloggroup_filter(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1794
#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:2377
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:2295
static int close_logger_thread
Definition: logger.c:199
rotatestrategy
Definition: logger.c:105
@ ROTATE
Definition: logger.c:108
@ TIMESTAMP
Definition: logger.c:109
@ SEQUENTIAL
Definition: logger.c:107
@ NONE
Definition: logger.c:106
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:2463
static char * custom_dynamic_levels[NUMLOGLEVELS]
Custom dynamic logging levels added by the user.
Definition: logger.c:231
int ast_logger_rotate()
Reload logger while rotating log files.
Definition: logger.c:1315
int ast_logger_remove_channel(const char *log_channel)
Delete the specified log channel.
Definition: logger.c:1575
static struct logchannel * make_logchannel(const char *channel, const char *components, int lineno, int dynamic)
Definition: logger.c:634
#define FORMATL2
static int logger_queue_rt_start(void)
Definition: logger.c:1137
void close_logger(void)
Definition: logger.c:2233
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:1397
static int reload_logger(int rotate, const char *altconf)
Definition: logger.c:1200
int ast_is_logger_initialized(void)
Test if logger is initialized.
Definition: logger.c:2163
static char * handle_logger_filter_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1826
static FILE * qlog
Definition: logger.c:201
static struct ast_threadstorage verbose_buf
Definition: logger.c:269
static void update_logchannels(void)
Definition: logger.c:2698
ast_callid ast_read_threadstorage_callid(void)
extracts the callerid from the thread
Definition: logger.c:2286
static int display_callids
Definition: logger.c:91
static int logger_initialized
Definition: logger.c:89
static char exec_after_rotate[256]
Definition: logger.c:84
static pthread_t logthread
Definition: logger.c:197
int ast_callid_threadassoc_add(ast_callid callid)
Adds a known callid to thread storage of the calling thread.
Definition: logger.c:2308
ast_callid ast_create_callid(void)
factory function to create a new uniquely identifying callid.
Definition: logger.c:2281
static int logger_queue_limit
Definition: logger.c:96
static struct logformatter logformatter_json
Definition: logger.c:331
static int callid_group_set_filter(const char *group, int enabled)
Definition: logger.c:1717
static int logger_queue_size
Definition: logger.c:95
static struct logformatter logformatter_default
Definition: logger.c:441
unsigned int queue_log_realtime_use_gmt
Definition: logger.c:116
static int reload_module(void)
Definition: logger.c:2930
static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size)
Definition: logger.c:336
logtypes
Definition: logger.c:132
@ LOGTYPE_CONSOLE
Definition: logger.c:135
@ LOGTYPE_FILE
Definition: logger.c:134
@ LOGTYPE_SYSLOG
Definition: logger.c:133
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:2550
static unsigned int high_water_alert
Definition: logger.c:98
static char queue_log_name[256]
Definition: logger.c:83
static int logger_register_level(const char *name)
Definition: logger.c:2802
#define LOG_BUF_INIT_SIZE
Definition: logger.c:274
static ast_mutex_t verb_update_lock
Definition: logger.c:2570
static void make_components(struct logchannel *chan)
Definition: logger.c:496
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:2538
void ast_log_ap(int level, const char *file, int line, const char *function, const char *fmt, va_list ap)
Definition: logger.c:2450
#define LOGMSG_SIZE
Definition: logger.c:103
static char * handle_logger_filter_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1856
static const int colors[NUMLOGLEVELS]
Colors used in the console for logging.
Definition: logger.c:234
static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
Definition: logger.c:382
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:2441
static struct sigaction handle_SIGXFSZ
Definition: logger.c:1898
static struct ast_threadstorage unique_callid
Definition: logger.c:93
unsigned int queue_log
Definition: logger.c:113
int ast_callid_threadassoc_remove(void)
Removes callid from thread storage of the calling thread.
Definition: logger.c:2327
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:953
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:2344
int ast_logger_register_level(const char *name)
Register a new logger level.
Definition: logger.c:2839
static struct ast_threadstorage callid_group_name
Definition: logger.c:1651
static struct @367 logfiles
static void * logger_thread(void *data)
Actual logging thread.
Definition: logger.c:2085
int init_logger(void)
Definition: logger.c:2190
void ast_logger_set_queue_limit(int queue_limit)
Set the maximum number of messages allowed in the processing queue.
Definition: logger.c:2920
void ast_verb_update(void)
Re-evaluate the system max verbosity level (ast_verb_sys_level).
Definition: logger.c:2572
static char * handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1355
static struct logformatter logformatter_plain
Definition: logger.c:491
static int callid_set_chanloggroup(const char *group)
Definition: logger.c:1670
static ast_cond_t logcond
Definition: logger.c:198
#define VERBOSE_BUF_INIT_SIZE
Definition: logger.c:271
void ast_child_verbose(int level, const char *fmt,...)
Definition: logger.c:909
static int logger_unregister_level(const char *name)
Definition: logger.c:2881
static struct ast_threadstorage my_verb_console
Definition: logger.c:2632
static void logger_print_normal(struct logmsg *logmsg)
Print a normal log message to the channels.
Definition: logger.c:1904
static int load_module(void)
Definition: logger.c:2940
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:2489
static struct logchannel * find_logchannel(const char *channel)
Find a particular logger channel by name.
Definition: logger.c:618
static struct ast_threadstorage log_buf
Definition: logger.c:273
static int unload_module(void)
Definition: logger.c:2935
static char * handle_logger_add_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1539
static void logger_queue_init(void)
Definition: logger.c:2139
static int callid_logging_enabled(void)
Definition: logger.c:1755
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:2006
static char * handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1277
static struct ast_cli_entry cli_logger[]
Definition: logger.c:1879
static int logger_queue_restart(int queue_rotate)
Definition: logger.c:1172
int ast_verb_console_get(void)
Get this thread's console verbosity level.
Definition: logger.c:2661
static char * handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: logger.c:1296
const char * ast_logger_get_dateformat(void)
Get the logger configured date format.
Definition: logger.c:2915
void ast_logger_unregister_level(const char *name)
Unregister a previously registered logger level.
Definition: logger.c:2897
unsigned int queue_adaptive_realtime
Definition: logger.c:115
static int logger_messages_discarded
Definition: logger.c:97
static int rotate_file(const char *filename)
Definition: logger.c:1033
static const char * get_callid_group(void)
Definition: logger.c:1663
static volatile int next_unique_callid
Definition: logger.c:90
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:119
void ast_log_backtrace(void)
Log a backtrace of the current thread's execution stack to the Asterisk log.
Definition: logger.c:2498
void ast_verb_console_set(int verb_level)
Set this thread's console verbosity level.
Definition: logger.c:2679
static void verb_console_unregister(struct verb_console *console)
Definition: logger.c:2613
static int logger_get_dynamic_level(const char *name)
Definition: logger.c:2850
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:2070
static void logmsg_free(struct logmsg *msg)
Definition: logger.c:190
static struct ast_threadstorage verbose_build_buf
Definition: logger.c:270
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:253
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ 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:114
#define ast_opt_exec
Definition: options.h:115
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
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:1558
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)
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
@ AST_DYNSTR_BUILD_FAILED
Definition: strings.h:943
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
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
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:2199
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
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 * 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:199
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:1654
Definition: search.h:40
Definition: astman.c:222
int verbosity
Definition: logger.c:148
int facility
Definition: logger.c:146
struct logchannel::@368 list
struct logformatter formatter
Definition: logger.c:140
int dynamic
Definition: logger.c:160
int lineno
Definition: logger.c:158
enum logtypes type
Definition: logger.c:150
unsigned int logmask
Definition: logger.c:142
char filename[PATH_MAX]
Definition: logger.c:154
FILE * fileptr
Definition: logger.c:152
int disabled
Definition: logger.c:144
char components[0]
Definition: logger.c:162
const char * name
Definition: logger.c:127
int(*const format_log)(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
Definition: logger.c:129
Definition: logger.c:172
const ast_string_field level_name
Definition: logger.c:186
int lwp
Definition: logger.c:177
const ast_string_field message
Definition: logger.c:186
int line
Definition: logger.c:176
ast_callid callid
Definition: logger.c:178
int sublevel
Definition: logger.c:175
struct logmsg * next
Definition: logger.c:187
const ast_string_field file
Definition: logger.c:186
const ast_string_field function
Definition: logger.c:186
enum logmsgtypes type
Definition: logger.c:173
int level
Definition: logger.c:174
unsigned int hidecli
Definition: logger.c:179
struct logmsg::@369 list
const ast_string_field date
Definition: logger.c:186
ast_mutex_t lock
Definition: logger.c:196
Definition: test_heap.c:38
struct verb_console::@370 node
int * level
Definition: logger.c:2563
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
const char * args
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.
Definition: threadstorage.h:86
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:739
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:584
int ast_get_tid(void)
Get current thread ID.
Definition: utils.c:2752
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: utils.c:2479
#define ARRAY_LEN(a)
Definition: utils.h:666
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680