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