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