summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2014-01-14 18:14:02 +0000
committerRichard Mudgett <rmudgett@digium.com>2014-01-14 18:14:02 +0000
commit828f339a9cb52cdcb62c28962d87a5187dc7c5bc (patch)
tree0081ea00504678b5bc432cbdad91ba77493b4dab /main
parentaced8bdd2e5d210f024be602bf5a1e70555ecec4 (diff)
verbosity: Fix performance of console verbose messages.
The per console verbose level feature as previously implemented caused a large performance penalty. The fix required some minor incompatibilities if the new rasterisk is used to connect to an earlier version. If the new rasterisk connects to an older Asterisk version then the root console verbose level is always affected by the "core set verbose" command of the remote console even though it may appear to only affect the current console. If an older version of rasterisk connects to the new version then the "core set verbose" command will have no effect. * Fixed the verbose performance by not generating a verbose message if nothing is going to use it and then filtered any generated verbose messages before actually sending them to the remote consoles. * Split the "core set debug" and "core set verbose" CLI commands to remove the per module verbose support that cannot work with the per console verbose level. * Added a silent option to the "core set verbose" command. * Fixed "core set debug off" tab completion. * Made "core show settings" list the current console verbosity in addition to the root console verbosity. * Changed the default verbose level of the 'verbose' setting in the logger.conf [logfiles] section. The default is now to once again follow the current root console level. As a result, using the AMI Command action with "core set verbose" could again set the root console verbose level and affect the verbose level logged. (closes issue AST-1252) Reported by: Guenther Kelleter Review: https://reviewboard.asterisk.org/r/3114/ ........ Merged revisions 405431 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 405432 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@405436 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c190
-rw-r--r--main/cli.c359
-rw-r--r--main/logger.c210
-rw-r--r--main/manager.c8
-rw-r--r--main/pbx.c2
5 files changed, 550 insertions, 219 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index 86667e061..e2e01a51f 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -319,6 +319,9 @@ int daemon(int, int); /* defined in libresolv of all places */
struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
struct ast_flags ast_compat = { 0 };
+/*! Maximum active system verbosity level. */
+int ast_verb_sys_level;
+
int option_verbose; /*!< Verbosity level */
int option_debug; /*!< Debug level */
double ast_option_maxload; /*!< Max load avg on system */
@@ -347,6 +350,8 @@ struct console {
int uid; /*!< Remote user ID. */
int gid; /*!< Remote group ID. */
int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
+ /*! Verbosity level of this console. */
+ int option_verbose;
};
struct ast_atexit {
@@ -609,7 +614,8 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, " Maximum open file handles: %d\n", ast_option_maxfiles);
else
ast_cli(a->fd, " Maximum open file handles: Not set\n");
- ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
+ ast_cli(a->fd, " Root console verbosity: %d\n", option_verbose);
+ ast_cli(a->fd, " Current console verbosity: %d\n", ast_verb_console_get());
ast_cli(a->fd, " Debug level: %d\n", option_debug);
ast_cli(a->fd, " Maximum load average: %lf\n", ast_option_maxload);
#if defined(HAVE_SYSINFO)
@@ -1331,29 +1337,33 @@ void ast_console_toggle_mute(int fd, int silent)
}
/*!
- * \brief log the string to all attached console clients
+ * \brief log the string to all attached network console clients
*/
static void ast_network_puts_mutable(const char *string, int level)
{
int x;
- for (x = 0;x < AST_MAX_CONNECTS; x++) {
- if (consoles[x].mute)
+
+ for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+ if (consoles[x].fd < 0
+ || consoles[x].mute
+ || consoles[x].levels[level]) {
continue;
- if (consoles[x].fd > -1) {
- if (!consoles[x].levels[level])
- fdprint(consoles[x].p[1], string);
}
+ fdprint(consoles[x].p[1], string);
}
}
/*!
- * \brief log the string to the console, and all attached
- * console clients
+ * \brief log the string to the root console, and all attached
+ * network console clients
*/
void ast_console_puts_mutable(const char *string, int level)
{
+ /* Send to the root console */
fputs(string, stdout);
fflush(stdout);
+
+ /* Send to any network console clients */
ast_network_puts_mutable(string, level);
}
@@ -1363,26 +1373,45 @@ void ast_console_puts_mutable(const char *string, int level)
static void ast_network_puts(const char *string)
{
int x;
- for (x = 0; x < AST_MAX_CONNECTS; x++) {
- if (consoles[x].fd > -1)
- fdprint(consoles[x].p[1], string);
+
+ for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+ if (consoles[x].fd < 0) {
+ continue;
+ }
+ fdprint(consoles[x].p[1], string);
}
}
/*!
- * \brief write the string to the console, and all attached
- * console clients
+ * \brief write the string to the root console, and all attached
+ * network console clients
*/
void ast_console_puts(const char *string)
{
+ /* Send to the root console */
fputs(string, stdout);
fflush(stdout);
+
+ /* Send to any network console clients */
ast_network_puts(string);
}
-static void network_verboser(const char *s)
+static void network_verboser(const char *string)
{
- ast_network_puts_mutable(s, __LOG_VERBOSE);
+ int x;
+ int verb_level;
+
+ /* Send to any network console clients if client verbocity allows. */
+ verb_level = VERBOSE_MAGIC2LEVEL(string);
+ for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+ if (consoles[x].fd < 0
+ || consoles[x].mute
+ || consoles[x].levels[__LOG_VERBOSE]
+ || consoles[x].option_verbose < verb_level) {
+ continue;
+ }
+ fdprint(consoles[x].p[1], string);
+ }
}
static pthread_t lthread;
@@ -1446,6 +1475,7 @@ static int read_credentials(int fd, char *buffer, size_t size, struct console *c
return result;
}
+/* This is the thread running the remote console on the main process. */
static void *netconsole(void *vconsole)
{
struct console *con = vconsole;
@@ -1461,6 +1491,7 @@ static void *netconsole(void *vconsole)
ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
fdprint(con->fd, outbuf);
+ ast_verb_console_register(&con->option_verbose);
for (;;) {
fds[0].fd = con->fd;
fds[0].events = POLLIN;
@@ -1523,6 +1554,7 @@ static void *netconsole(void *vconsole)
break;
}
}
+ ast_verb_console_unregister();
if (!ast_opt_hide_connect) {
ast_verb(3, "Remote UNIX connection disconnected\n");
}
@@ -1575,24 +1607,25 @@ static void *listener(void *unused)
}
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
- consoles[x].fd = -1;
fdprint(s, "Server failed to create pipe\n");
close(s);
break;
}
flags = fcntl(consoles[x].p[1], F_GETFL);
fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
- consoles[x].fd = s;
consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
/* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
to know if the user didn't send the credentials. */
consoles[x].uid = -2;
consoles[x].gid = -2;
+ /* Server default of remote console verbosity level is OFF. */
+ consoles[x].option_verbose = 0;
+ consoles[x].fd = s;
if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
+ consoles[x].fd = -1;
ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
close(consoles[x].p[0]);
close(consoles[x].p[1]);
- consoles[x].fd = -1;
fdprint(s, "Server failed to spawn thread\n");
close(s);
}
@@ -2074,12 +2107,6 @@ static int console_state_init(void *ptr)
AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
-/* These gymnastics are due to platforms which designate char as unsigned by
- * default. Level is the negative character -- offset by 1, because \0 is the
- * EOS delimiter. */
-#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
-#define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
-
static int console_print(const char *s, int local)
{
struct console_state_data *state =
@@ -2174,6 +2201,7 @@ static int ast_all_zeros(char *s)
return 1;
}
+/* This is the main console CLI command handler. Run by the main() thread. */
static void consolehandler(char *s)
{
printf("%s", term_end());
@@ -2211,38 +2239,56 @@ static int remoteconsolehandler(char *s)
else
ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
ret = 1;
- } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
- int old_verbose = option_verbose;
- if (strncasecmp(s + 17, "atleast ", 8) == 0) {
- int tmp;
- if (sscanf(s + 25, "%d", &tmp) != 1) {
- fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
- } else {
- if (tmp > option_verbose) {
- option_verbose = tmp;
- }
- if (old_verbose != option_verbose) {
- fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
- } else {
- fprintf(stdout, "Verbosity level unchanged.\n");
- }
+ } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
+ (s[4] == '\0' || isspace(s[4]))) {
+ quit_handler(0, SHUTDOWN_FAST, 0);
+ ret = 1;
+ } else if (s[0]) {
+ char *shrunk = ast_strdupa(s);
+ char *cur;
+ char *prev;
+
+ /*
+ * Remove duplicate spaces from shrunk for matching purposes.
+ *
+ * shrunk has at least one character in it to start with or we
+ * couldn't get here.
+ */
+ for (prev = shrunk, cur = shrunk + 1; *cur; ++cur) {
+ if (*prev == ' ' && *cur == ' ') {
+ /* Skip repeated space delimiter. */
+ continue;
}
- } else {
- if (sscanf(s + 17, "%d", &option_verbose) != 1) {
- fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
+ *++prev = *cur;
+ }
+ *++prev = '\0';
+
+ if (strncasecmp(shrunk, "core set verbose ", 17) == 0) {
+ /*
+ * We need to still set the rasterisk option_verbose in case we are
+ * talking to an earlier version which doesn't prefilter verbose
+ * levels. This is really a compromise as we should always take
+ * whatever the server sends.
+ */
+
+ if (!strncasecmp(shrunk + 17, "off", 3)) {
+ ast_verb_console_set(0);
} else {
- if (old_verbose != option_verbose) {
- fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
- } else {
- fprintf(stdout, "Verbosity level unchanged.\n");
+ int verbose_new;
+ int atleast;
+
+ atleast = 8;
+ if (strncasecmp(shrunk + 17, "atleast ", atleast)) {
+ atleast = 0;
+ }
+
+ if (sscanf(shrunk + 17 + atleast, "%30d", &verbose_new) == 1) {
+ if (!atleast || ast_verb_console_get() < verbose_new) {
+ ast_verb_console_set(verbose_new);
+ }
}
}
}
- ret = 1;
- } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
- (s[4] == '\0' || isspace(s[4]))) {
- quit_handler(0, SHUTDOWN_FAST, 0);
- ret = 1;
}
return ret;
@@ -2564,6 +2610,31 @@ static struct ast_cli_entry cli_asterisk[] = {
#endif /* ! LOW_MEMORY */
};
+static void send_rasterisk_connect_commands(void)
+{
+ char buf[80];
+
+ /*
+ * Tell the server asterisk instance about the verbose level
+ * initially desired.
+ */
+ if (option_verbose) {
+ snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
+ fdsend(ast_consock, buf);
+ }
+
+ if (option_debug) {
+ snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
+ fdsend(ast_consock, buf);
+ }
+
+ if (!ast_opt_mute) {
+ fdsend(ast_consock, "logger mute silent");
+ } else {
+ printf("log and verbose output currently muted ('logger mute' to unmute)\n");
+ }
+}
+
static int ast_el_read_char(EditLine *editline, char *cp)
{
int num_read = 0;
@@ -2617,10 +2688,7 @@ static int ast_el_read_char(EditLine *editline, char *cp)
fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
printf("%s", term_quit());
WELCOME_MESSAGE;
- if (!ast_opt_mute)
- fdsend(ast_consock, "logger mute silent");
- else
- printf("log and verbose output currently muted ('logger mute' to unmute)\n");
+ send_rasterisk_connect_commands();
break;
} else
usleep(1000000 / reconnects_per_second);
@@ -3171,11 +3239,7 @@ static void ast_remotecontrol(char *data)
else
pid = -1;
if (!data) {
- if (!ast_opt_mute) {
- fdsend(ast_consock, "logger mute silent");
- } else {
- printf("log and verbose output currently muted ('logger mute' to unmute)\n");
- }
+ send_rasterisk_connect_commands();
}
if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
@@ -3652,6 +3716,7 @@ static void canary_exit(void)
kill(canary_pid, SIGKILL);
}
+/* Execute CLI commands on startup. Run by main() thread. */
static void run_startup_commands(void)
{
int fd;
@@ -4082,6 +4147,9 @@ int main(int argc, char *argv[])
}
}
+ /* Initial value of the maximum active system verbosity level. */
+ ast_verb_sys_level = option_verbose;
+
if (ast_tryconnect()) {
/* One is already running */
if (ast_opt_remote) {
diff --git a/main/cli.c b/main/cli.c
index a9f466499..fa5cc987a 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -106,8 +106,6 @@ AST_RWLIST_HEAD(module_level_list, module_level);
/*! list of module names and their debug levels */
static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
-/*! list of module names and their verbose levels */
-static struct module_level_list verbose_modules = AST_RWLIST_HEAD_INIT_VALUE;
AST_THREADSTORAGE(ast_cli_buf);
@@ -151,19 +149,7 @@ unsigned int ast_debug_get_by_module(const char *module)
unsigned int ast_verbose_get_by_module(const char *module)
{
- struct module_level *ml;
- unsigned int res = 0;
-
- AST_RWLIST_RDLOCK(&verbose_modules);
- AST_LIST_TRAVERSE(&verbose_modules, ml, entry) {
- if (!strcasecmp(ml->module, module)) {
- res = ml->level;
- break;
- }
- }
- AST_RWLIST_UNLOCK(&verbose_modules);
-
- return res;
+ return 0;
}
/*! \internal
@@ -357,14 +343,19 @@ static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli
return CLI_SUCCESS;
}
+
/*!
- * \brief Find the debug or verbose file setting
- * \arg debug 1 for debug, 0 for verbose
+ * \brief Find the module level setting
+ *
+ * \param module Module name to look for.
+ * \param mll List to search.
+ *
+ * \retval level struct found on success.
+ * \retval NULL not found.
*/
-static struct module_level *find_module_level(const char *module, unsigned int debug)
+static struct module_level *find_module_level(const char *module, struct module_level_list *mll)
{
struct module_level *ml;
- struct module_level_list *mll = debug ? &debug_modules : &verbose_modules;
AST_LIST_TRAVERSE(mll, ml, entry) {
if (!strcasecmp(ml->module, module))
@@ -414,52 +405,77 @@ static char *complete_number(const char *partial, unsigned int min, unsigned int
return NULL;
}
-static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static void status_debug_verbose(struct ast_cli_args *a, const char *what, int old_val, int cur_val)
+{
+ char was_buf[30];
+ const char *was;
+
+ if (old_val) {
+ snprintf(was_buf, sizeof(was_buf), "%d", old_val);
+ was = was_buf;
+ } else {
+ was = "OFF";
+ }
+
+ if (old_val == cur_val) {
+ ast_cli(a->fd, "%s is still %s.\n", what, was);
+ } else {
+ char now_buf[30];
+ const char *now;
+
+ if (cur_val) {
+ snprintf(now_buf, sizeof(now_buf), "%d", cur_val);
+ now = now_buf;
+ } else {
+ now = "OFF";
+ }
+
+ ast_cli(a->fd, "%s was %s and is now %s.\n", what, was, now);
+ }
+}
+
+static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int oldval;
int newlevel;
- unsigned int is_debug;
int atleast = 0;
- int fd = a->fd;
- int argc = a->argc;
- const char * const *argv = a->argv;
const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
- int *dst;
- char *what;
- struct module_level_list *mll;
struct module_level *ml;
switch (cmd) {
case CLI_INIT:
- e->command = "core set {debug|verbose}";
+ e->command = "core set debug";
e->usage =
#if !defined(LOW_MEMORY)
- "Usage: core set {debug|verbose} [atleast] <level> [module]\n"
+ "Usage: core set debug [atleast] <level> [module]\n"
#else
- "Usage: core set {debug|verbose} [atleast] <level>\n"
+ "Usage: core set debug [atleast] <level>\n"
#endif
- " core set {debug|verbose} off\n"
+ " core set debug off\n"
+ "\n"
#if !defined(LOW_MEMORY)
- " Sets level of debug or verbose messages to be displayed or\n"
+ " Sets level of debug messages to be displayed or\n"
" sets a module name to display debug messages from.\n"
#else
- " Sets level of debug or verbose messages to be displayed.\n"
+ " Sets level of debug messages to be displayed.\n"
#endif
- " 0 or off means no messages should be displayed.\n"
- " Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
+ " 0 or off means no messages should be displayed.\n"
+ " Equivalent to -d[d[...]] on startup\n";
return NULL;
case CLI_GENERATE:
- if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
+ if (!strcasecmp(argv3, "atleast")) {
+ atleast = 1;
+ }
+ if (a->pos == 3 || (a->pos == 4 && atleast)) {
const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
+
if (a->n < 21 && numbermatch == 0) {
return complete_number(pos, 0, 0x7fffffff, a->n);
} else if (pos[0] == '0') {
if (a->n == 0) {
return ast_strdup("0");
- } else {
- return NULL;
}
} else if (a->n == (21 - numbermatch)) {
if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
@@ -471,8 +487,11 @@ static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
return ast_strdup("atleast");
}
#if !defined(LOW_MEMORY)
- } else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
- return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
+ } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+ || (a->pos == 5 && atleast)) {
+ const char *pos = S_OR(a->argv[a->pos], "");
+
+ return ast_complete_source_filename(pos, a->n);
#endif
}
return NULL;
@@ -481,117 +500,200 @@ static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
* we are guaranteed to be called with argc >= e->args;
*/
- if (argc <= e->args)
+ if (a->argc <= e->args) {
return CLI_SHOWUSAGE;
- if (!strcasecmp(argv[e->args - 1], "debug")) {
- dst = &option_debug;
- oldval = option_debug;
- what = "Core debug";
- is_debug = 1;
- } else {
- dst = &option_verbose;
- oldval = option_verbose;
- what = "Verbosity";
- is_debug = 0;
}
- if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
+
+ if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
newlevel = 0;
+ } else {
+ if (!strcasecmp(a->argv[e->args], "atleast")) {
+ atleast = 1;
+ }
+ if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {
+ return CLI_SHOWUSAGE;
+ }
+ if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
+ return CLI_SHOWUSAGE;
+ }
- mll = is_debug ? &debug_modules : &verbose_modules;
+ if (a->argc == e->args + atleast + 2) {
+ /* We have specified a module name. */
+ char *mod = ast_strdupa(a->argv[e->args + atleast + 1]);
+ int mod_len = strlen(mod);
- AST_RWLIST_WRLOCK(mll);
- while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
- ast_free(ml);
- }
- ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
- AST_RWLIST_UNLOCK(mll);
+ if (3 < mod_len && !strcasecmp(mod + mod_len - 3, ".so")) {
+ mod[mod_len - 3] = '\0';
+ }
- goto done;
+ AST_RWLIST_WRLOCK(&debug_modules);
+
+ ml = find_module_level(mod, &debug_modules);
+ if (!newlevel) {
+ if (!ml) {
+ /* Specified off for a nonexistent entry. */
+ AST_RWLIST_UNLOCK(&debug_modules);
+ ast_cli(a->fd, "Core debug is still 0 for '%s'.\n", mod);
+ return CLI_SUCCESS;
+ }
+ AST_RWLIST_REMOVE(&debug_modules, ml, entry);
+ if (AST_RWLIST_EMPTY(&debug_modules)) {
+ ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+ }
+ AST_RWLIST_UNLOCK(&debug_modules);
+ ast_cli(a->fd, "Core debug was %d and has been set to 0 for '%s'.\n",
+ ml->level, mod);
+ ast_free(ml);
+ return CLI_SUCCESS;
+ }
+
+ if (ml) {
+ if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
+ ast_cli(a->fd, "Core debug is still %d for '%s'.\n", ml->level, mod);
+ AST_RWLIST_UNLOCK(&debug_modules);
+ return CLI_SUCCESS;
+ }
+ oldval = ml->level;
+ ml->level = newlevel;
+ } else {
+ ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
+ if (!ml) {
+ AST_RWLIST_UNLOCK(&debug_modules);
+ return CLI_FAILURE;
+ }
+ oldval = ml->level;
+ ml->level = newlevel;
+ strcpy(ml->module, mod);
+ AST_RWLIST_INSERT_TAIL(&debug_modules, ml, entry);
+ }
+ ast_set_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+
+ ast_cli(a->fd, "Core debug was %d and has been set to %d for '%s'.\n",
+ oldval, ml->level, ml->module);
+
+ AST_RWLIST_UNLOCK(&debug_modules);
+
+ return CLI_SUCCESS;
+ }
}
- if (!strcasecmp(argv[e->args], "atleast"))
- atleast = 1;
- if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
- return CLI_SHOWUSAGE;
- if (sscanf(argv[e->args + atleast], "%30d", &newlevel) != 1)
- return CLI_SHOWUSAGE;
- if (argc == e->args + atleast + 2) {
- /* We have specified a module name. */
- char *mod = ast_strdupa(argv[e->args + atleast + 1]);
- if ((strlen(mod) > 3) && !strcasecmp(mod + strlen(mod) - 3, ".so")) {
- mod[strlen(mod) - 3] = '\0';
+ /* Update global debug level */
+ if (!newlevel) {
+ /* Specified level was 0 or off. */
+ AST_RWLIST_WRLOCK(&debug_modules);
+ while ((ml = AST_RWLIST_REMOVE_HEAD(&debug_modules, entry))) {
+ ast_free(ml);
}
+ ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+ AST_RWLIST_UNLOCK(&debug_modules);
+ }
+ oldval = option_debug;
+ if (!atleast || newlevel > option_debug) {
+ option_debug = newlevel;
+ }
- mll = is_debug ? &debug_modules : &verbose_modules;
+ /* Report debug level status */
+ status_debug_verbose(a, "Core debug", oldval, option_debug);
- AST_RWLIST_WRLOCK(mll);
+ return CLI_SUCCESS;
+}
- ml = find_module_level(mod, is_debug);
- if (!newlevel) {
- if (!ml) {
- /* Specified off for a nonexistent entry. */
- AST_RWLIST_UNLOCK(mll);
- return CLI_SUCCESS;
- }
- AST_RWLIST_REMOVE(mll, ml, entry);
- if (AST_RWLIST_EMPTY(mll))
- ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
- AST_RWLIST_UNLOCK(mll);
- ast_cli(fd, "%s was %d and has been set to 0 for '%s'\n", what, ml->level, mod);
- ast_free(ml);
- return CLI_SUCCESS;
+static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int oldval;
+ int newlevel;
+ int atleast = 0;
+ int silent = 0;
+ const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core set verbose";
+ e->usage =
+ "Usage: core set verbose [atleast] <level> [silent]\n"
+ " core set verbose off\n"
+ "\n"
+ " Sets level of verbose messages to be displayed.\n"
+ " 0 or off means no verbose messages should be displayed.\n"
+ " The silent option means the command does not report what\n"
+ " happened to the verbose level.\n"
+ " Equivalent to -v[v[...]] on startup\n";
+ return NULL;
+
+ case CLI_GENERATE:
+ if (!strcasecmp(argv3, "atleast")) {
+ atleast = 1;
}
+ if (a->pos == 3 || (a->pos == 4 && atleast)) {
+ const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
+ int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
- if (ml) {
- if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
- ast_cli(fd, "%s is %d for '%s'\n", what, ml->level, mod);
- AST_RWLIST_UNLOCK(mll);
- return CLI_SUCCESS;
+ if (a->n < 21 && numbermatch == 0) {
+ return complete_number(pos, 0, 0x7fffffff, a->n);
+ } else if (pos[0] == '0') {
+ if (a->n == 0) {
+ return ast_strdup("0");
+ }
+ } else if (a->n == (21 - numbermatch)) {
+ if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
+ return ast_strdup("off");
+ } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
+ return ast_strdup("atleast");
+ }
+ } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
+ return ast_strdup("atleast");
}
- oldval = ml->level;
- ml->level = newlevel;
- } else {
- ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
- if (!ml) {
- AST_RWLIST_UNLOCK(mll);
- return CLI_FAILURE;
+ } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+ || (a->pos == 5 && atleast)) {
+ const char *pos = S_OR(a->argv[a->pos], "");
+
+ if (a->n == 0 && !strncasecmp(pos, "silent", strlen(pos))) {
+ return ast_strdup("silent");
}
- oldval = ml->level;
- ml->level = newlevel;
- strcpy(ml->module, mod);
- AST_RWLIST_INSERT_TAIL(mll, ml, entry);
}
+ return NULL;
+ }
+ /* all the above return, so we proceed with the handler.
+ * we are guaranteed to be called with argc >= e->args;
+ */
- ast_set_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
+ if (a->argc <= e->args) {
+ return CLI_SHOWUSAGE;
+ }
- AST_RWLIST_UNLOCK(mll);
+ if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
+ newlevel = 0;
+ } else {
+ if (!strcasecmp(a->argv[e->args], "atleast")) {
+ atleast = 1;
+ }
+ if (a->argc == e->args + atleast + 2
+ && !strcasecmp(a->argv[e->args + atleast + 1], "silent")) {
+ silent = 1;
+ }
+ if (a->argc != e->args + atleast + silent + 1) {
+ return CLI_SHOWUSAGE;
+ }
+ if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
+ return CLI_SHOWUSAGE;
+ }
+ }
- ast_cli(fd, "%s was %d and has been set to %d for '%s'\n", what, oldval, ml->level, ml->module);
+ /* Update verbose level */
+ oldval = ast_verb_console_get();
+ if (!atleast || newlevel > oldval) {
+ ast_verb_console_set(newlevel);
+ } else {
+ newlevel = oldval;
+ }
+ if (silent) {
+ /* Be silent after setting the level. */
return CLI_SUCCESS;
- } else if (!newlevel) {
- /* Specified level as 0 instead of off. */
- mll = is_debug ? &debug_modules : &verbose_modules;
-
- AST_RWLIST_WRLOCK(mll);
- while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
- ast_free(ml);
- }
- ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
- AST_RWLIST_UNLOCK(mll);
}
-done:
- if (!atleast || newlevel > *dst)
- *dst = newlevel;
- if (oldval > 0 && *dst == 0)
- ast_cli(fd, "%s is now OFF\n", what);
- else if (*dst > 0) {
- if (oldval == *dst)
- ast_cli(fd, "%s is at least %d\n", what, *dst);
- else
- ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
- }
+ /* Report verbose level status */
+ status_debug_verbose(a, "Console verbose", oldval, newlevel);
return CLI_SUCCESS;
}
@@ -1684,7 +1786,8 @@ static struct ast_cli_entry cli_cli[] = {
AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
- AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
+ AST_CLI_DEFINE(handle_debug, "Set level of debug chattiness"),
+ AST_CLI_DEFINE(handle_verbose, "Set level of verbose chattiness"),
AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
diff --git a/main/logger.c b/main/logger.c
index 52bb5c021..3ecf2fcef 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -121,7 +121,7 @@ struct logchannel {
int disabled;
/*! syslog facility */
int facility;
- /*! Verbosity level */
+ /*! Verbosity level. (-1 if use option_verbose for the level.) */
int verbosity;
/*! Type of log channel */
enum logtypes type;
@@ -240,32 +240,48 @@ AST_THREADSTORAGE(log_buf);
static void logger_queue_init(void);
-static unsigned int make_components(const char *s, int lineno, int *verbosity)
+static void make_components(struct logchannel *chan)
{
char *w;
- unsigned int res = 0;
- char *stringp = ast_strdupa(s);
+ unsigned int logmask = 0;
+ char *stringp = ast_strdupa(chan->components);
unsigned int x;
+ int verb_level;
- *verbosity = 3;
+ /* Default to using option_verbose as the verbosity level of the logging channel. */
+ verb_level = -1;
while ((w = strsep(&stringp, ","))) {
- w = ast_skip_blanks(w);
-
+ w = ast_strip(w);
+ if (ast_strlen_zero(w)) {
+ continue;
+ }
if (!strcmp(w, "*")) {
- res = 0xFFFFFFFF;
- break;
- } else if (!strncasecmp(w, "verbose(", 8) && sscanf(w + 8, "%d)", verbosity) == 1) {
- res |= (1 << __LOG_VERBOSE);
- } else for (x = 0; x < ARRAY_LEN(levels); x++) {
- if (levels[x] && !strcasecmp(w, levels[x])) {
- res |= (1 << x);
- break;
+ logmask = 0xFFFFFFFF;
+ } else if (!strncasecmp(w, "verbose(", 8)) {
+ if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
+ logmask |= (1 << __LOG_VERBOSE);
+ }
+ } else {
+ for (x = 0; x < ARRAY_LEN(levels); ++x) {
+ if (levels[x] && !strcasecmp(w, levels[x])) {
+ logmask |= (1 << x);
+ break;
+ }
}
}
}
-
- return res;
+ if (chan->type == LOGTYPE_CONSOLE) {
+ /*
+ * Force to use the root console verbose level so if the
+ * user specified any verbose level then it does not interfere
+ * with calculating the ast_verb_sys_level value.
+ */
+ chan->verbosity = -1;
+ } else {
+ chan->verbosity = verb_level;
+ }
+ chan->logmask = logmask;
}
static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
@@ -335,7 +351,7 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo
}
chan->type = LOGTYPE_FILE;
}
- chan->logmask = make_components(chan->components, lineno, &chan->verbosity);
+ make_components(chan);
return chan;
}
@@ -840,10 +856,12 @@ static int reload_logger(int rotate, const char *altconf)
if (logfiles.queue_log) {
res = logger_queue_restart(queue_rotate);
AST_RWLIST_UNLOCK(&logchannels);
+ ast_verb_update();
ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
ast_verb(1, "Asterisk Queue Logger restarted\n");
} else {
AST_RWLIST_UNLOCK(&logchannels);
+ ast_verb_update();
}
return res;
@@ -1028,12 +1046,6 @@ static void ast_log_vsyslog(struct logmsg *msg)
syslog(syslog_level, "%s", buf);
}
-/* These gymnastics are due to platforms which designate char as unsigned by
- * default. Level is the negative character -- offset by 1, because \0 is the
- * EOS delimiter. */
-#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
-#define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
-
/*! \brief Print a normal log message to the channels */
static void logger_print_normal(struct logmsg *logmsg)
{
@@ -1044,7 +1056,9 @@ static void logger_print_normal(struct logmsg *logmsg)
if (logmsg->level == __LOG_VERBOSE) {
char *tmpmsg = ast_strdupa(logmsg->message + 1);
+
level = VERBOSE_MAGIC2LEVEL(logmsg->message);
+
/* Iterate through the list of verbosers and pass them the log message string */
AST_RWLIST_RDLOCK(&verbosers);
AST_RWLIST_TRAVERSE(&verbosers, v, list)
@@ -1070,7 +1084,8 @@ static void logger_print_normal(struct logmsg *logmsg)
if (chan->disabled) {
continue;
}
- if (logmsg->level == __LOG_VERBOSE && level > chan->verbosity) {
+ if (logmsg->level == __LOG_VERBOSE
+ && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
continue;
}
@@ -1246,6 +1261,7 @@ int init_logger(void)
/* create log channels */
init_logger_chain(0 /* locked */, NULL);
+ ast_verb_update();
logger_initialized = 1;
return 0;
@@ -1707,6 +1723,148 @@ void ast_verbose(const char *fmt, ...)
}
}
+/*! Console verbosity level node. */
+struct verb_console {
+ /*! List node link */
+ AST_LIST_ENTRY(verb_console) node;
+ /*! Console verbosity level. */
+ int *level;
+};
+
+/*! Registered console verbosity levels */
+static AST_RWLIST_HEAD_STATIC(verb_consoles, verb_console);
+
+/*! ast_verb_update() reentrancy protection lock. */
+AST_MUTEX_DEFINE_STATIC(verb_update_lock);
+
+void ast_verb_update(void)
+{
+ struct logchannel *log;
+ struct verb_console *console;
+ int verb_level;
+
+ ast_mutex_lock(&verb_update_lock);
+
+ AST_RWLIST_RDLOCK(&verb_consoles);
+
+ /* Default to the root console verbosity. */
+ verb_level = option_verbose;
+
+ /* Determine max remote console level. */
+ AST_LIST_TRAVERSE(&verb_consoles, console, node) {
+ if (verb_level < *console->level) {
+ verb_level = *console->level;
+ }
+ }
+ AST_RWLIST_UNLOCK(&verb_consoles);
+
+ /* Determine max logger channel level. */
+ AST_RWLIST_RDLOCK(&logchannels);
+ AST_RWLIST_TRAVERSE(&logchannels, log, list) {
+ if (verb_level < log->verbosity) {
+ verb_level = log->verbosity;
+ }
+ }
+ AST_RWLIST_UNLOCK(&logchannels);
+
+ ast_verb_sys_level = verb_level;
+
+ ast_mutex_unlock(&verb_update_lock);
+}
+
+/*!
+ * \internal
+ * \brief Unregister a console verbose level.
+ *
+ * \param console Which console to unregister.
+ *
+ * \return Nothing
+ */
+static void verb_console_unregister(struct verb_console *console)
+{
+ AST_RWLIST_WRLOCK(&verb_consoles);
+ console = AST_RWLIST_REMOVE(&verb_consoles, console, node);
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ if (console) {
+ ast_verb_update();
+ }
+}
+
+static void verb_console_free(void *v_console)
+{
+ struct verb_console *console = v_console;
+
+ verb_console_unregister(console);
+ ast_free(console);
+}
+
+/*! Thread specific console verbosity level node. */
+AST_THREADSTORAGE_CUSTOM(my_verb_console, NULL, verb_console_free);
+
+void ast_verb_console_register(int *level)
+{
+ struct verb_console *console;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ if (!console || !level) {
+ return;
+ }
+ console->level = level;
+
+ AST_RWLIST_WRLOCK(&verb_consoles);
+ AST_RWLIST_INSERT_HEAD(&verb_consoles, console, node);
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ ast_verb_update();
+}
+
+void ast_verb_console_unregister(void)
+{
+ struct verb_console *console;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ if (!console) {
+ return;
+ }
+ verb_console_unregister(console);
+}
+
+int ast_verb_console_get(void)
+{
+ struct verb_console *console;
+ int verb_level;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ AST_RWLIST_RDLOCK(&verb_consoles);
+ if (!console) {
+ verb_level = 0;
+ } else if (console->level) {
+ verb_level = *console->level;
+ } else {
+ verb_level = option_verbose;
+ }
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ return verb_level;
+}
+
+void ast_verb_console_set(int verb_level)
+{
+ struct verb_console *console;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ if (!console) {
+ return;
+ }
+
+ AST_RWLIST_WRLOCK(&verb_consoles);
+ if (console->level) {
+ *console->level = verb_level;
+ } else {
+ option_verbose = verb_level;
+ }
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ ast_verb_update();
+}
+
int ast_register_verbose(void (*v)(const char *string))
{
struct verb *verb;
@@ -1750,7 +1908,7 @@ static void update_logchannels(void)
global_logmask = 0;
AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
- cur->logmask = make_components(cur->components, cur->lineno, &cur->verbosity);
+ make_components(cur);
global_logmask |= cur->logmask;
}
diff --git a/main/manager.c b/main/manager.c
index 15f10f7ed..0b6cffee5 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -1860,13 +1860,13 @@ static struct ast_manager_user *get_manager_by_name_locked(const char *name)
* \param session manager session to get parameter from.
* \return displayconnects config option value.
*/
-static int manager_displayconnects (struct mansession_session *session)
+static int manager_displayconnects(struct mansession_session *session)
{
struct ast_manager_user *user = NULL;
int ret = 0;
AST_RWLIST_RDLOCK(&users);
- if ((user = get_manager_by_name_locked (session->username))) {
+ if ((user = get_manager_by_name_locked(session->username))) {
ret = user->displayconnects;
}
AST_RWLIST_UNLOCK(&users);
@@ -5888,7 +5888,9 @@ static void purge_sessions(int n_max)
while ((session = ao2_iterator_next(&i)) && n_max > 0) {
ao2_lock(session);
if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
- if (session->authenticated && manager_displayconnects(session)) {
+ if (session->authenticated
+ && VERBOSITY_ATLEAST(2)
+ && manager_displayconnects(session)) {
ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
session->username, ast_sockaddr_stringify_addr(&session->addr));
}
diff --git a/main/pbx.c b/main/pbx.c
index c5eb5f116..ae857e9b3 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -4886,7 +4886,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
}
ast_debug(1, "Launching '%s'\n", app->name);
- {
+ if (VERBOSITY_ATLEAST(3)) {
ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
exten, context, priority,
COLORIZE(COLOR_BRCYAN, 0, app->name),