<p>Kevin Harwell <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16508">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, approved
  Kevin Harwell: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">logger: Add custom logging capabilities<br><br>Adds the ability for users to log to custom log levels<br>by providing custom log level names in logger.conf. Also<br>adds a logger show levels CLI command.<br><br>ASTERISK-29529<br><br>Change-Id: If082703cf81a436ae5a565c75225fa8c0554b702<br>---<br>M apps/app_verbose.c<br>M configs/samples/logger.conf.sample<br>A doc/CHANGES-staging/logger.txt<br>M include/asterisk/logger.h<br>M main/logger.c<br>5 files changed, 183 insertions(+), 34 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_verbose.c b/apps/app_verbose.c</span><br><span>index 5b78e18..a888ba0 100644</span><br><span>--- a/apps/app_verbose.c</span><br><span>+++ b/apps/app_verbose.c</span><br><span>@@ -33,6 +33,7 @@</span><br><span> #include "asterisk/module.h"</span><br><span> #include "asterisk/app.h"</span><br><span> #include "asterisk/channel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/logger.h"</span><br><span> </span><br><span> static char *app_verbose = "Verbose";</span><br><span> static char *app_log = "Log";</span><br><span>@@ -61,7 +62,8 @@</span><br><span>              <syntax></span><br><span>                       <parameter name="level" required="true"></span><br><span>                           <para>Level must be one of <literal>ERROR</literal>, <literal>WARNING</literal>, <literal>NOTICE</literal>,</span><br><span style="color: hsl(0, 100%, 40%);">-                           <literal>DEBUG</literal>, <literal>VERBOSE</literal> or <literal>DTMF</literal>.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                             <literal>DEBUG</literal>, <literal>VERBOSE</literal>, <literal>DTMF</literal>, or</span><br><span style="color: hsl(120, 100%, 40%);">+                         the name of a custom dynamic logging level.</para></span><br><span>                     </parameter></span><br><span>                   <parameter name="message" required="true"></span><br><span>                                 <para>Output text message.</para></span><br><span>@@ -135,7 +137,7 @@</span><br><span>  } else if (!strcasecmp(args.level, "DTMF")) {</span><br><span>              lnum = __LOG_DTMF;</span><br><span>   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_ERROR, "Unknown log level: '%s'\n", args.level);</span><br><span style="color: hsl(120, 100%, 40%);">+                lnum = ast_logger_get_dynamic_level(args.level);</span><br><span>     }</span><br><span> </span><br><span>        if (lnum > -1) {</span><br><span>@@ -143,6 +145,9 @@</span><br><span>            snprintf(extension, sizeof(extension), "Ext. %s", ast_channel_exten(chan));</span><br><span> </span><br><span>            ast_log(lnum, extension, ast_channel_priority(chan), context, "%s\n", args.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Unknown log level: '%s'\n", args.level);</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</span><br><span>    }</span><br><span> </span><br><span>        return 0;</span><br><span>diff --git a/configs/samples/logger.conf.sample b/configs/samples/logger.conf.sample</span><br><span>index 9e2fb35..777f803 100644</span><br><span>--- a/configs/samples/logger.conf.sample</span><br><span>+++ b/configs/samples/logger.conf.sample</span><br><span>@@ -85,6 +85,11 @@</span><br><span> ; The default is 1000</span><br><span> ;logger_queue_limit = 250</span><br><span> ;</span><br><span style="color: hsl(120, 100%, 40%);">+; Any custom logging levels you may want to use, which can then</span><br><span style="color: hsl(120, 100%, 40%);">+; be sent to logging channels. The maximum number of custom</span><br><span style="color: hsl(120, 100%, 40%);">+; levels is 16, but not all of these may be available if modules</span><br><span style="color: hsl(120, 100%, 40%);">+; in Asterisk define their own.</span><br><span style="color: hsl(120, 100%, 40%);">+;custom_levels = foobar,important,compliance</span><br><span> ;</span><br><span> [logfiles]</span><br><span> ;</span><br><span>@@ -130,6 +135,7 @@</span><br><span> ;    dtmf</span><br><span> ;    fax</span><br><span> ;    security</span><br><span style="color: hsl(120, 100%, 40%);">+;    <customlevel></span><br><span> ;</span><br><span> ; Verbose takes an optional argument, in the form of an integer level. The</span><br><span> ; verbose level can be set per logfile. Verbose messages with higher levels</span><br><span>@@ -176,3 +182,5 @@</span><br><span> ;</span><br><span> ;syslog.local0 => notice,warning,error</span><br><span> ;</span><br><span style="color: hsl(120, 100%, 40%);">+; A log level defined in 'custom_levels' above</span><br><span style="color: hsl(120, 100%, 40%);">+;important.log = important</span><br><span>diff --git a/doc/CHANGES-staging/logger.txt b/doc/CHANGES-staging/logger.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..d09ebcc</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/logger.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: logger</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Added the ability to define custom log levels in logger.conf</span><br><span style="color: hsl(120, 100%, 40%);">+and use them in the Log dialplan application. Also adds a</span><br><span style="color: hsl(120, 100%, 40%);">+logger show levels CLI command.</span><br><span>diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h</span><br><span>index d823ed4..4234262 100644</span><br><span>--- a/include/asterisk/logger.h</span><br><span>+++ b/include/asterisk/logger.h</span><br><span>@@ -330,6 +330,14 @@</span><br><span> int ast_logger_register_level(const char *name);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve dynamic logging level id</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name The name of the level</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval The unique integer id for the given level</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 if level name not found</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_logger_get_dynamic_level(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Unregister a previously registered logger level</span><br><span>  * \param name The name of the level to be unregistered</span><br><span>  * \return nothing</span><br><span>diff --git a/main/logger.c b/main/logger.c</span><br><span>index 457a6fb..6b0e76f 100644</span><br><span>--- a/main/logger.c</span><br><span>+++ b/main/logger.c</span><br><span>@@ -74,6 +74,10 @@</span><br><span> /*** DOCUMENTATION</span><br><span>  ***/</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int logger_register_level(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+static int logger_unregister_level(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+static int logger_get_dynamic_level(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static char dateformat[256] = "%b %e %T";             /* Original Asterisk Format */</span><br><span> </span><br><span> static char queue_log_name[256] = QUEUELOG;</span><br><span>@@ -211,6 +215,15 @@</span><br><span>     "DTMF",</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Custom dynamic logging levels added by the user</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The first 16 levels are reserved for system usage, and the remaining</span><br><span style="color: hsl(120, 100%, 40%);">+ * levels are reserved for usage by dynamic levels registered via</span><br><span style="color: hsl(120, 100%, 40%);">+ * ast_logger_register_level.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *custom_dynamic_levels[NUMLOGLEVELS];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Colors used in the console for logging */</span><br><span> static const int colors[NUMLOGLEVELS] = {</span><br><span>      COLOR_BRGREEN,</span><br><span>@@ -697,6 +710,26 @@</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Checks if level exists in array of level names</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param levels Array of level names</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param level Name to search for</span><br><span style="color: hsl(120, 100%, 40%);">+ * \len Size of levels</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 Found</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Not Found</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int custom_level_still_exists(char **levels, char *level, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!strcmp(levels[i], level)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Read config, setup channels.</span><br><span>  * \param altconf Alternate configuration file to read.</span><br><span>  *</span><br><span>@@ -809,6 +842,39 @@</span><br><span>                }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Custom dynamic logging levels defined by user */</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((s = ast_variable_retrieve(cfg, "general", "custom_levels"))) {</span><br><span style="color: hsl(120, 100%, 40%);">+               char *customlogs = ast_strdupa(s);</span><br><span style="color: hsl(120, 100%, 40%);">+            char *logfile;</span><br><span style="color: hsl(120, 100%, 40%);">+                char *new_custom_levels[16] = { };</span><br><span style="color: hsl(120, 100%, 40%);">+            unsigned int level, new_level = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* get the custom levels we need to register or reload */</span><br><span style="color: hsl(120, 100%, 40%);">+             while ((logfile = strsep(&customlogs, ","))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  new_custom_levels[new_level++] = logfile;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* unregister existing custom levels, if they're not still</span><br><span style="color: hsl(120, 100%, 40%);">+                        specified in customlogs, to make room for new levels */</span><br><span style="color: hsl(120, 100%, 40%);">+               for (level = 16; level < ARRAY_LEN(levels); level++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (levels[level] && custom_dynamic_levels[level] &&</span><br><span style="color: hsl(120, 100%, 40%);">+                          !custom_level_still_exists(new_custom_levels, levels[level], ARRAY_LEN(new_custom_levels))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         logger_unregister_level(levels[level]);</span><br><span style="color: hsl(120, 100%, 40%);">+                               custom_dynamic_levels[level] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           new_level = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                while ((logfile = new_custom_levels[new_level++])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* Lock already held, so directly register the level,</span><br><span style="color: hsl(120, 100%, 40%);">+                         unless it's already registered (as during reload) */</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (logger_get_dynamic_level(logfile) == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                int custom_level = logger_register_level(logfile);</span><br><span style="color: hsl(120, 100%, 40%);">+                            custom_dynamic_levels[custom_level] = logfile;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  var = ast_variable_browse(cfg, "logfiles");</span><br><span>        for (; var; var = var->next) {</span><br><span>            chan = make_logchannel(var->name, var->value, var->lineno, 0);</span><br><span>@@ -1403,6 +1469,35 @@</span><br><span>     return CLI_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief CLI command to show logging levels */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *handle_logger_show_levels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+#define FORMATL2   "%5s %s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int level;</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "logger show levels";</span><br><span style="color: hsl(120, 100%, 40%);">+               e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: logger show levels\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "       List configured logger levels.\n";</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_cli(a->fd, FORMATL2, "Level", "Name");</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_cli(a->fd, FORMATL2, "-----", "----");</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_RDLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+  for (level = 0; level < ARRAY_LEN(levels); level++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (levels[level]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_cli(a->fd, "%5d %s\n", level, levels[level]);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_cli(a->fd, "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int ast_logger_create_channel(const char *log_channel, const char *components)</span><br><span> {</span><br><span>      struct logchannel *chan;</span><br><span>@@ -1545,6 +1640,7 @@</span><br><span> </span><br><span> static struct ast_cli_entry cli_logger[] = {</span><br><span>         AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_CLI_DEFINE(handle_logger_show_levels, "List configured log levels"),</span><br><span>   AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),</span><br><span>     AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),</span><br><span>         AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),</span><br><span>@@ -2348,19 +2444,14 @@</span><br><span> {</span><br><span>      struct logchannel *cur;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     AST_RWLIST_WRLOCK(&logchannels);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         global_logmask = 0;</span><br><span> </span><br><span>      AST_RWLIST_TRAVERSE(&logchannels, cur, list) {</span><br><span>           make_components(cur);</span><br><span>                global_logmask |= cur->logmask;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       AST_RWLIST_UNLOCK(&logchannels);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> #ifdef AST_DEVMODE</span><br><span> </span><br><span> AST_THREADSTORAGE_RAW(trace_indent);</span><br><span>@@ -2452,13 +2543,12 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int ast_logger_register_level(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+/* Lock should be held before calling this function */</span><br><span style="color: hsl(120, 100%, 40%);">+static int logger_register_level(const char *name)</span><br><span> {</span><br><span>         unsigned int level;</span><br><span>  unsigned int available = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- AST_RWLIST_WRLOCK(&logchannels);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         for (level = 0; level < ARRAY_LEN(levels); level++) {</span><br><span>             if ((level >= 16) && !available && !levels[level]) {</span><br><span>                      available = level;</span><br><span>@@ -2469,7 +2559,6 @@</span><br><span>                   ast_log(LOG_WARNING,</span><br><span>                                 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",</span><br><span>                                 name);</span><br><span style="color: hsl(0, 100%, 40%);">-                  AST_RWLIST_UNLOCK(&logchannels);</span><br><span> </span><br><span>                     return -1;</span><br><span>           }</span><br><span>@@ -2479,15 +2568,12 @@</span><br><span>          ast_log(LOG_WARNING,</span><br><span>                         "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",</span><br><span>                    name);</span><br><span style="color: hsl(0, 100%, 40%);">-          AST_RWLIST_UNLOCK(&logchannels);</span><br><span> </span><br><span>             return -1;</span><br><span>   }</span><br><span> </span><br><span>        levels[available] = ast_strdup(name);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         ast_debug(1, "Registered dynamic logger level '%s' with index %u.\n", name, available);</span><br><span> </span><br><span>        update_logchannels();</span><br><span>@@ -2495,42 +2581,79 @@</span><br><span>      return available;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void ast_logger_unregister_level(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_logger_register_level(const char *name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      unsigned int found = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int x;</span><br><span style="color: hsl(120, 100%, 40%);">+       int available = 0;</span><br><span> </span><br><span>       AST_RWLIST_WRLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+  available = logger_register_level(name);</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return available;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int logger_get_dynamic_level(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int level = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int x;</span><br><span> </span><br><span>  for (x = 16; x < ARRAY_LEN(levels); x++) {</span><br><span>                if (!levels[x]) {</span><br><span>                    continue;</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (strcasecmp(levels[x], name)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!strcasecmp(levels[x], name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   level = x;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span>               }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               found = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-              break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (found) {</span><br><span style="color: hsl(0, 100%, 40%);">-            /* take this level out of the global_logmask, to ensure that no new log messages</span><br><span style="color: hsl(0, 100%, 40%);">-                 * will be queued for it</span><br><span style="color: hsl(0, 100%, 40%);">-                 */</span><br><span style="color: hsl(120, 100%, 40%);">+   return level;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            global_logmask &= ~(1 << x);</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_logger_get_dynamic_level(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int level = -1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-             ast_free(levels[x]);</span><br><span style="color: hsl(0, 100%, 40%);">-            levels[x] = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-               AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_RWLIST_RDLOCK(&logchannels);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                ast_debug(1, "Unregistered dynamic logger level '%s' with index %u.\n", name, x);</span><br><span style="color: hsl(120, 100%, 40%);">+   level = logger_get_dynamic_level(name);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return level;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int logger_unregister_level(const char *name) {</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int x;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     x = logger_get_dynamic_level(name);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (x == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* take this level out of the global_logmask, to ensure that no new log messages</span><br><span style="color: hsl(120, 100%, 40%);">+       * will be queued for it</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   global_logmask &= ~(1 << x);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_free(levels[x]);</span><br><span style="color: hsl(120, 100%, 40%);">+  levels[x] = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     return x;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_logger_unregister_level(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int x;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_RWLIST_WRLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+  x = logger_unregister_level(name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (x) {</span><br><span>             update_logchannels();</span><br><span style="color: hsl(0, 100%, 40%);">-   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_RWLIST_UNLOCK(&logchannels);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (x) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_debug(1, "Unregistered dynamic logger level '%s' with index %u.\n", name, x);</span><br><span>  }</span><br><span> }</span><br><span> </span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16508">change 16508</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/16508"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: If082703cf81a436ae5a565c75225fa8c0554b702 </div>
<div style="display:none"> Gerrit-Change-Number: 16508 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>