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