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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Scope Tracing:  A new facility for tracing scope enter/exit<br><br>What's wrong with ast_debug?<br><br>  ast_debug is fine for general purpose debug output but it's not<br>  really geared for scope tracing since it doesn't present its<br>  output in a way that makes capturing and analyzing flow through<br>  Asterisk easy.<br><br>How is scope tracing better?<br><br>  Scope tracing uses the same "cleanup" attribute that RAII_VAR<br>  uses to print messages to a separate "trace" log level.  Even<br>  better, the messages are indented and unindented based on a<br>  thread-local call depth counter.  When output to a separate log<br>  file, the output is uncluttered and easy to follow.<br><br>  Here's an example of the output. The leading timestamps and<br>  thread ids are removed and the output cut off at 68 columns for<br>  commit message restrictions but you get the idea.<br><br>--> res_pjsip_session.c:3680 handle_incoming PJSIP/1173-00000001<br>      --> res_pjsip_session.c:3661 handle_incoming_response PJSIP/1173<br>           --> res_pjsip_session.c:3669 handle_incoming_response PJSIP/<br>                       --> chan_pjsip.c:3265 chan_pjsip_incoming_response_after<br>                           --> chan_pjsip.c:3194 chan_pjsip_incoming_response P<br>                                           chan_pjsip.c:3245 chan_pjsip_incoming_respon<br>                              <-- chan_pjsip.c:3194 chan_pjsip_incoming_response P<br>                       <-- chan_pjsip.c:3265 chan_pjsip_incoming_response_after<br>           <-- res_pjsip_session.c:3669 handle_incoming_response PJSIP/<br>       <-- res_pjsip_session.c:3661 handle_incoming_response PJSIP/1173<br><-- res_pjsip_session.c:3680 handle_incoming PJSIP/1173-00000001<br><br>  The messages with the "-->" or "<--" were produced by including<br>  the following at the top of each function:<br><br>  SCOPE_TRACE(1, "%s\n", ast_sip_session_get_name(session));<br><br>  Scope isn't limited to functions any more than RAII_VAR is.  You<br>  can also see entry and exit from "if", "for", "while", etc blocks.<br><br>  There is also an ast_trace() macro that doesn't track entry or<br>  exit but simply outputs a message to the trace log using the<br>  current indent level.  The deepest message in the sample<br>  (chan_pjsip.c:3245) was used to indicate which "case" in a<br>  "select" was executed.<br><br>How do you use it?<br><br>  More documentation is available in logger.h but here's an overview:<br><br>  * Configure with --enable-dev-mode.  Like debug, scope tracing<br>    is #ifdef'd out if devmode isn't enabled.<br><br>  * Add a SCOPE_TRACE() call to the top of your function.<br><br>  * Set a logger channel in logger.conf to output the "trace" level.<br><br>  * Use the CLI (or cli.conf) to set a trace level similar to setting<br>    debug level... CLI> core set trace 2 res_pjsip.so<br><br>Summary Of Changes:<br><br>  * Added LOG_TRACE logger level.  Actually it occupies the slot<br>    formerly occupied by the now defunct "event" level.<br><br>  * Added core asterisk option "trace" similar to debug.  Includes<br>   ability to specify global trace level in asterisk.conf and CLI<br>        commands to turn on/off and set levels.  Levels can be set<br>    globally (probably not a good idea), or by module/source file.<br><br>  * Updated sample asterisk.conf and logger.conf.  Tracing is<br>    disabled by default in both.<br><br>  * Added __ast_trace() to logger.c which keeps track of the indent<br>    level using TLS. It's #ifdef'd out if devmode isn't enabled.<br><br>  * Added ast_trace() and SCOPE_TRACE() macros to logger.h.<br>    These are all #ifdef'd out if devmode isn't enabled.<br><br>Why not use gcc's -finstrument-functions capability?<br><br>  gcc's facility doesn't allow access to local data and doesn't<br>  operate on non-function scopes.<br><br>Known Issues:<br><br>  The only know issue is that we currently don't know the line<br>  number where the scope exited.  It's reported as the same place<br>  the scope was entered.  There's probably a way to get around it<br>  but it might involve looking at the stack and doing an 'addr2line'<br>  to get the line number.  Kind of like ast_backtrace() does.<br>  Not sure if it's worth it.<br><br>Change-Id: Ic5ebb859883f9c10a08c5630802de33500cad027<br>(cherry picked from commit 6a0c47237480d750023561b004f2c4052bfab210)<br>---<br>M configs/samples/asterisk.conf.sample<br>M configs/samples/logger.conf.sample<br>M include/asterisk/logger.h<br>M include/asterisk/options.h<br>M main/asterisk.c<br>M main/asterisk.exports.in<br>M main/cli.c<br>M main/logger.c<br>M main/options.c<br>A tests/test_scope_trace.c<br>10 files changed, 605 insertions(+), 100 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/asterisk.conf.sample b/configs/samples/asterisk.conf.sample</span><br><span>index bf0bdba..3c1a403 100644</span><br><span>--- a/configs/samples/asterisk.conf.sample</span><br><span>+++ b/configs/samples/asterisk.conf.sample</span><br><span>@@ -14,6 +14,7 @@</span><br><span> [options]</span><br><span> ;verbose = 3</span><br><span> ;debug = 3</span><br><span style="color: hsl(120, 100%, 40%);">+;trace = 0              ; Set the trace level.</span><br><span> ;refdebug = yes                  ; Enable reference count debug logging.</span><br><span> ;alwaysfork = yes            ; Same as -F at startup.</span><br><span> ;nofork = yes                       ; Same as -f at startup.</span><br><span>diff --git a/configs/samples/logger.conf.sample b/configs/samples/logger.conf.sample</span><br><span>index e5f0c55..9c7dcca 100644</span><br><span>--- a/configs/samples/logger.conf.sample</span><br><span>+++ b/configs/samples/logger.conf.sample</span><br><span>@@ -118,6 +118,7 @@</span><br><span> ; Log levels include the following, and are specified in a comma delineated</span><br><span> ; list:</span><br><span> ;    debug</span><br><span style="color: hsl(120, 100%, 40%);">+;    trace</span><br><span> ;    notice</span><br><span> ;    warning</span><br><span> ;    error</span><br><span>@@ -146,12 +147,14 @@</span><br><span> ; the underlying code.  Do NOT report debug messages as code issues, unless</span><br><span> ; you have a specific issue that you are attempting to debug.  They are</span><br><span> ; messages for just that -- debugging -- and do not rise to the level of</span><br><span style="color: hsl(0, 100%, 40%);">-; something that merit your attention as an Asterisk administrator.  Debug</span><br><span style="color: hsl(0, 100%, 40%);">-; messages are also very verbose and can and do fill up logfiles quickly;</span><br><span style="color: hsl(0, 100%, 40%);">-; this is another reason not to have debug mode on a production system unless</span><br><span style="color: hsl(0, 100%, 40%);">-; you are in the process of debugging a specific issue.</span><br><span style="color: hsl(120, 100%, 40%);">+; something that merit your attention as an Asterisk administrator.  Both</span><br><span style="color: hsl(120, 100%, 40%);">+; debug and trace messages are also very verbose and can and do fill up</span><br><span style="color: hsl(120, 100%, 40%);">+; logfiles quickly.  This is another reason not to have debug or trace</span><br><span style="color: hsl(120, 100%, 40%);">+; modes on a production system unless you are in the process of debugging</span><br><span style="color: hsl(120, 100%, 40%);">+; a specific issue.</span><br><span> ;</span><br><span> ;debug => debug</span><br><span style="color: hsl(120, 100%, 40%);">+;trace => trace</span><br><span> ;security => security</span><br><span> console => notice,warning,error</span><br><span> ;console => notice,warning,error,debug</span><br><span>diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h</span><br><span>index 1d0c6bd..4392e5a 100644</span><br><span>--- a/include/asterisk/logger.h</span><br><span>+++ b/include/asterisk/logger.h</span><br><span>@@ -245,6 +245,17 @@</span><br><span> #endif</span><br><span> #define AST_LOG_DEBUG      __LOG_DEBUG, _A_</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef LOG_TRACE</span><br><span style="color: hsl(120, 100%, 40%);">+#undef LOG_TRACE</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+#define __LOG_TRACE   1</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_TRACE     __LOG_TRACE, _A_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef AST_LOG_TRACE</span><br><span style="color: hsl(120, 100%, 40%);">+#undef AST_LOG_TRACE</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_LOG_TRACE     __LOG_TRACE, _A_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef LOG_NOTICE</span><br><span> #undef LOG_NOTICE</span><br><span> #endif</span><br><span>@@ -517,6 +528,199 @@</span><br><span>  */</span><br><span> int ast_logger_get_queue_limit(void);</span><br><span> </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%);">+ \page Scope_Trace Scope Trace</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The Scope Trace facility allows you to instrument code and output scope entry</span><br><span style="color: hsl(120, 100%, 40%);">+and exit messages with associated data.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+To start using it:</span><br><span style="color: hsl(120, 100%, 40%);">+ * You must have used --enable-dev-mode.</span><br><span style="color: hsl(120, 100%, 40%);">+ * In logger.conf, set a logger channel to output the "trace" level.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Instrument your code as specified below.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Use the cli or cli.conf to enable tracing: CLI> core set trace <trace_level> [ module ]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Its simplest usage requires only 1 macro call that...</span><br><span style="color: hsl(120, 100%, 40%);">+ - Registers a descructor for a special variable that gets called when the</span><br><span style="color: hsl(120, 100%, 40%);">+       variable goes out of scope.  Uses the same principle as RAII_VAR.</span><br><span style="color: hsl(120, 100%, 40%);">+     The destructor prints the name of the function with an "exiting" indicator</span><br><span style="color: hsl(120, 100%, 40%);">+          along with an optional message.</span><br><span style="color: hsl(120, 100%, 40%);">+     - Prints the name of the function with an "entering" indicator along with</span><br><span style="color: hsl(120, 100%, 40%);">+     an optional message.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Simple Example:</span><br><span style="color: hsl(120, 100%, 40%);">+The following code...</span><br><span style="color: hsl(120, 100%, 40%);">+\code</span><br><span style="color: hsl(120, 100%, 40%);">+static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv,</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_sip_session *session, const pjmedia_sdp_session *offer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_TRACE(1, "%s\n", ast_sip_session_get_name(session));</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%);">+\endcode</span><br><span style="color: hsl(120, 100%, 40%);">+would produce...</span><br><span style="color: hsl(120, 100%, 40%);">+\b [2020-05-17 15:16:51 -0600] TRACE[953402] : --> res_pjsip_session.c:4283 create_local_sdp PJSIP/1173-00000001</span><br><span style="color: hsl(120, 100%, 40%);">+\b [2020-05-17 15:16:51 -0600] TRACE[953402] : <-- res_pjsip_session.c:4283 create_local_sdp PJSIP/1173-00000001</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+There is one odd bit.  There's no way to capture the line number of there the scope exited</span><br><span style="color: hsl(120, 100%, 40%);">+so it's always going to be the line where SCOPE_TRACE is located.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Similar to RAII_VAR, any block scope can be traced including "if", "for", "while", etc.</span><br><span style="color: hsl(120, 100%, 40%);">+\note "case" statements don't create a scope block by themselves but you can create</span><br><span style="color: hsl(120, 100%, 40%);">+a block for it, or use the generic trace functions mentioned below.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Scope Output and Level:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Rather than sending trace messages to the debug facility, a new facility "trace" has been</span><br><span style="color: hsl(120, 100%, 40%);">+added to logger.  A corresponding CLI command "core set trace", and a corresponding "trace"</span><br><span style="color: hsl(120, 100%, 40%);">+parameter in asterisk.conf were added.  This allows a separate log channel to be created</span><br><span style="color: hsl(120, 100%, 40%);">+just for storing trace messages.  The levels are the same as those for debug and verbose.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Scope Indenting:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Each time SCOPE_TRACE or SCOPE_TRACE is called, a thread-local indent value is</span><br><span style="color: hsl(120, 100%, 40%);">+incremented on scope enter, and decremented on scope exit.  This allows output</span><br><span style="color: hsl(120, 100%, 40%);">+like the following (timestamp omitted for brevity):</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] : --> res_pjsip_session.c:3940 session_inv_on_tsx_state_changed PJSIP/1173-00000001 TSX State: Proceeding  Inv State: CALLING</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :    --> res_pjsip_session.c:3680 handle_incoming PJSIP/1173-00000001</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :            --> res_pjsip_session.c:3661 handle_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                        --> res_pjsip_session.c:3669 handle_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100 Supplement: chan_pjsip</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                                 --> chan_pjsip.c:3265 chan_pjsip_incoming_response_after_media PJSIP/1173-00000001 Method: INVITE Status: 100  After Media</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                                  --> chan_pjsip.c:3194 chan_pjsip_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                                       chan_pjsip.c:3245 chan_pjsip_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100  Ignored</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                                     <-- chan_pjsip.c:3194 chan_pjsip_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                           <-- chan_pjsip.c:3265 chan_pjsip_incoming_response_after_media PJSIP/1173-00000001 Method: INVITE Status: 100  After Media</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                  <-- res_pjsip_session.c:3669 handle_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100 Supplement: chan_pjsip</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :                 <-- res_pjsip_session.c:3661 handle_incoming_response PJSIP/1173-00000001 Method: INVITE Status: 100</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] :        <-- res_pjsip_session.c:3680 handle_incoming PJSIP/1173-00000001</span><br><span style="color: hsl(120, 100%, 40%);">+TRACE[953402] : <-- res_pjsip_session.c:3940 session_inv_on_tsx_state_changed PJSIP/1173-00000001 TSX State: Proceeding  Inv State: CALLING</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+\note The trace level indicates which messages to print and has no effect on indent.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Generic Trace Messages:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Sometimes you may just want to print a message to the trace log with the appropriate indent</span><br><span style="color: hsl(120, 100%, 40%);">+such as when executing a "case" clause in a "switch" statement. For example, the deepest</span><br><span style="color: hsl(120, 100%, 40%);">+message in the sample output above (chan_pjsip.c:3245) is just a single message instead of</span><br><span style="color: hsl(120, 100%, 40%);">+an entry/exit message.  To do so, you can use the ast_trace macros...</span><br><span style="color: hsl(120, 100%, 40%);">+\code</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_trace(1, "%s Method: %.*s Status: %d  Ignored\n", ast_sip_session_get_name(session),</span><br><span style="color: hsl(120, 100%, 40%);">+            (int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);</span><br><span style="color: hsl(120, 100%, 40%);">+\endcode</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/note Final note:  The trace facility, like debug, is only available when AST_DEVMODE is defined.</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 style="color: hsl(120, 100%, 40%);">+ * \brief Get the trace level for a module</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param module the name of module</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return the trace level</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_trace_get_by_module(const char *module);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TRACE_ATLEAST(level) \</span><br><span style="color: hsl(120, 100%, 40%);">+     (option_trace >= (level) \</span><br><span style="color: hsl(120, 100%, 40%);">+         || (ast_opt_trace_module \</span><br><span style="color: hsl(120, 100%, 40%);">+                    && ((int)ast_trace_get_by_module(AST_MODULE) >= (level) \</span><br><span style="color: hsl(120, 100%, 40%);">+                          || (int)ast_trace_get_by_module(__FILE__) >= (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%);">+ * \brief Controls if and when indenting is applied.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_trace_indent_type {</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Use the existing indent level */</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_TRACE_INDENT_SAME = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! Increment the indent before printing the message */</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TRACE_INDENT_INC_BEFORE,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Increment the indent after printing the message */</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_TRACE_INDENT_INC_AFTER,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Decrement the indent before printing the message */</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TRACE_INDENT_DEC_BEFORE,</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Decrement the indent after printing the message */</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_TRACE_INDENT_DEC_AFTER,</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! Don't use or alter the level */</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TRACE_INDENT_NONE,</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%);">+#ifdef AST_DEVMODE</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void __attribute__((format (printf, 5, 6))) __ast_trace(const char *file, int line, const char *func,</span><br><span style="color: hsl(120, 100%, 40%);">+     enum ast_trace_indent_type indent_type, const char* format, ...);</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%);">+ * \brief Print a trace message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param level The trace level</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param indent_type One of the \ref ast_trace_indent_type values</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param (optional) A printf style format string</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param (optional) Arguments</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%);">+#define ast_trace_raw(level, indent_type, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+      if (TRACE_ATLEAST(level)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+         __ast_trace(__FILE__, __LINE__, __PRETTY_FUNCTION__, indent_type, " " __VA_ARGS__); \</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%);">+ * \brief Print a basic trace message</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param level The trace level</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param (optional) A printf style format string</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param (optional) Arguments</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This will print the file, line and function at the current indent level</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_trace(level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+        if (TRACE_ATLEAST(level)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+         __ast_trace(__FILE__, __LINE__, __PRETTY_FUNCTION__, AST_TRACE_INDENT_SAME, " " __VA_ARGS__); \</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%);">+ * \brief Print a trace message with details when a scope is entered or existed.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param level The trace level</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param (optional) A printf style format string</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param (optional) Arguments</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This will print the file, line and function plus details at the current indent level.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Like RAII_VAR, this macro must be called before any code in the scope.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The variables used to detect scope change will look like</span><br><span style="color: hsl(120, 100%, 40%);">+ * __scopevar1234__EXIT and __scopevar1234__ENTER.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The ENTER variable and function are needed to prevent mixed code and declaration issues.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If we simple called __ast_trace, then this macro would need to be the last line</span><br><span style="color: hsl(120, 100%, 40%);">+ * of scope variable declaration.  The following would fail.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *    SCOPE_TRACE(1, "Help!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ *        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCOPE_TRACE(level, ...) \</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *__trace_funcname = __PRETTY_FUNCTION__; \</span><br><span style="color: hsl(120, 100%, 40%);">+ auto void __scopevar ## __LINE__ ## __EXIT(void * v); \</span><br><span style="color: hsl(120, 100%, 40%);">+       void __scopevar ## __LINE__ ## __EXIT(void * v __attribute__((unused))) { \</span><br><span style="color: hsl(120, 100%, 40%);">+           if (TRACE_ATLEAST(level)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                 __ast_trace(__FILE__, __LINE__, __trace_funcname, AST_TRACE_INDENT_DEC_BEFORE, " " __VA_ARGS__); \</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 *__scopevar ## __LINE__ ## __TRACER __attribute__((cleanup(__scopevar ## __LINE__ ## __EXIT))) = (void *) __PRETTY_FUNCTION__ ; \</span><br><span style="color: hsl(120, 100%, 40%);">+        auto int __scopevar ## __LINE__ ## __ENTER(void); \</span><br><span style="color: hsl(120, 100%, 40%);">+   int __scopevar ## __LINE__ ## __ENTER(void) { \</span><br><span style="color: hsl(120, 100%, 40%);">+               if (TRACE_ATLEAST(level)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                 __ast_trace(__FILE__, __LINE__, __trace_funcname, AST_TRACE_INDENT_INC_AFTER, " " __VA_ARGS__); \</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%);">+   int __scopevar ## __LINE__ ## __RETURN __attribute__((unused)) = __scopevar ## __LINE__ ## __ENTER()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_trace_raw(__level, __indent_type, __fmt, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_trace(__level)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCOPE_TRACE(__level)</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #if defined(__cplusplus) || defined(c_plusplus)</span><br><span> }</span><br><span> #endif</span><br><span>diff --git a/include/asterisk/options.h b/include/asterisk/options.h</span><br><span>index f8c813f..570100b 100644</span><br><span>--- a/include/asterisk/options.h</span><br><span>+++ b/include/asterisk/options.h</span><br><span>@@ -82,6 +82,8 @@</span><br><span>      AST_OPT_FLAG_MUTE = (1 << 22),</span><br><span>         /*! There is a per-module debug setting */</span><br><span>   AST_OPT_FLAG_DEBUG_MODULE = (1 << 23),</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! There is a per-module trace setting */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_OPT_FLAG_TRACE_MODULE = (1 << 24),</span><br><span>         /*! Terminal colors should be adjusted for a light-colored background */</span><br><span>     AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),</span><br><span>     /*! Make the global Message channel an internal channel to suppress AMI events */</span><br><span>@@ -124,6 +126,7 @@</span><br><span> #define ast_opt_always_fork          ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)</span><br><span> #define ast_opt_mute                       ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)</span><br><span> #define ast_opt_dbg_module                ast_test_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ast_opt_trace_module                ast_test_flag(&ast_options, AST_OPT_FLAG_TRACE_MODULE)</span><br><span> #define ast_opt_light_background  ast_test_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND)</span><br><span> #define ast_opt_force_black_background        ast_test_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND)</span><br><span> #define ast_opt_hide_connect            ast_test_flag(&ast_options, AST_OPT_FLAG_HIDE_CONSOLE_CONNECT)</span><br><span>@@ -184,6 +187,7 @@</span><br><span> extern int option_verbose;</span><br><span> extern int ast_option_maxfiles;               /*!< Max number of open file handles (files, sockets) */</span><br><span> extern int option_debug;         /*!< Debugging */</span><br><span style="color: hsl(120, 100%, 40%);">+extern int option_trace;          /*!< Debugging */</span><br><span> extern int ast_option_maxcalls;         /*!< Maximum number of simultaneous channels */</span><br><span> extern unsigned int option_dtmfminduration;       /*!< Minimum duration of DTMF (channel.c) in ms */</span><br><span> extern double ast_option_maxload;</span><br><span>diff --git a/main/asterisk.c b/main/asterisk.c</span><br><span>index 037c7cd..ac0a1f7 100644</span><br><span>--- a/main/asterisk.c</span><br><span>+++ b/main/asterisk.c</span><br><span>@@ -482,6 +482,7 @@</span><br><span>    ast_cli(a->fd, "  Root console verbosity:      %d\n", option_verbose);</span><br><span>  ast_cli(a->fd, "  Current console verbosity:   %d\n", ast_verb_console_get());</span><br><span>  ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_cli(a->fd, "  Trace level:                 %d\n", option_trace);</span><br><span>    ast_cli(a->fd, "  Maximum load average:        %lf\n", ast_option_maxload);</span><br><span> #if defined(HAVE_SYSINFO)</span><br><span>        ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);</span><br><span>diff --git a/main/asterisk.exports.in b/main/asterisk.exports.in</span><br><span>index 0232855..dfa72a6 100644</span><br><span>--- a/main/asterisk.exports.in</span><br><span>+++ b/main/asterisk.exports.in</span><br><span>@@ -12,6 +12,7 @@</span><br><span>          LINKER_SYMBOL_PREFIXao2_*;</span><br><span>           LINKER_SYMBOL_PREFIX__ao2_*;</span><br><span>                 LINKER_SYMBOL_PREFIXoption_debug;</span><br><span style="color: hsl(120, 100%, 40%);">+             LINKER_SYMBOL_PREFIXoption_trace;</span><br><span>            LINKER_SYMBOL_PREFIXoption_verbose;</span><br><span>          LINKER_SYMBOL_PREFIXcallerid_*;</span><br><span>              LINKER_SYMBOL_PREFIXcid_di;</span><br><span>diff --git a/main/cli.c b/main/cli.c</span><br><span>index 11f4dd7..13ef7d5 100644</span><br><span>--- a/main/cli.c</span><br><span>+++ b/main/cli.c</span><br><span>@@ -102,8 +102,9 @@</span><br><span> </span><br><span> AST_RWLIST_HEAD(module_level_list, module_level);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! list of module names and their debug levels */</span><br><span style="color: hsl(120, 100%, 40%);">+/*! lists of module names and their debug/trace levels */</span><br><span> static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct module_level_list trace_modules = AST_RWLIST_HEAD_INIT_VALUE;</span><br><span> </span><br><span> AST_THREADSTORAGE(ast_cli_buf);</span><br><span> </span><br><span>@@ -148,6 +149,23 @@</span><br><span>       return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_trace_get_by_module(const char *module)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct module_level *ml;</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_RWLIST_RDLOCK(&trace_modules);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_LIST_TRAVERSE(&trace_modules, ml, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!strcasecmp(ml->module, module)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     res = ml->level;</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</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(&trace_modules);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \internal</span><br><span>  *  \brief Check if the user with 'uid' and 'gid' is allow to execute 'command',</span><br><span>  *        if command starts with '_' then not check permissions, just permit</span><br><span>@@ -381,10 +399,27 @@</span><br><span>        return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void status_debug_verbose(struct ast_cli_args *a, const char *what, int old_val, int cur_val)</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEBUG_HANDLER 0</span><br><span style="color: hsl(120, 100%, 40%);">+#define TRACE_HANDLER 1</span><br><span style="color: hsl(120, 100%, 40%);">+#define VERBOSE_HANDLER 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void status_debug_verbose(struct ast_cli_args *a, int handler, int old_val, int cur_val)</span><br><span> {</span><br><span>       char was_buf[30];</span><br><span>    const char *was;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *what;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch(handler) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case DEBUG_HANDLER:</span><br><span style="color: hsl(120, 100%, 40%);">+           what = "Core debug";</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case TRACE_HANDLER:</span><br><span style="color: hsl(120, 100%, 40%);">+           what = "Core trace";</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case VERBOSE_HANDLER:</span><br><span style="color: hsl(120, 100%, 40%);">+         what = "Console verbose";</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span> </span><br><span>        if (old_val) {</span><br><span>               snprintf(was_buf, sizeof(was_buf), "%d", old_val);</span><br><span>@@ -410,13 +445,131 @@</span><br><span>        }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *handle_debug_or_trace(int handler, struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span> {</span><br><span>        int oldval;</span><br><span>  int newlevel;</span><br><span>        int atleast = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-        const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";</span><br><span>   struct module_level *ml;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct module_level_list *modules;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int module_option;</span><br><span style="color: hsl(120, 100%, 40%);">+   int *core_option;</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *handler_name;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc <= e->args) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return CLI_SHOWUSAGE;</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%);">+   if (handler == DEBUG_HANDLER) {</span><br><span style="color: hsl(120, 100%, 40%);">+               modules = &debug_modules;</span><br><span style="color: hsl(120, 100%, 40%);">+         module_option = AST_OPT_FLAG_DEBUG_MODULE;</span><br><span style="color: hsl(120, 100%, 40%);">+            core_option = &option_debug;</span><br><span style="color: hsl(120, 100%, 40%);">+              handler_name = "debug";</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              modules = &trace_modules;</span><br><span style="color: hsl(120, 100%, 40%);">+         module_option = AST_OPT_FLAG_TRACE_MODULE;</span><br><span style="color: hsl(120, 100%, 40%);">+            core_option = &option_trace;</span><br><span style="color: hsl(120, 100%, 40%);">+              handler_name = "trace";</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%);">+   if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           newlevel = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!strcasecmp(a->argv[e->args], "atleast")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       atleast = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 return CLI_SHOWUSAGE;</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%);">+           if (a->argc == e->args + atleast + 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* We have specified a module name. */</span><br><span style="color: hsl(120, 100%, 40%);">+                        char *mod = ast_strdupa(a->argv[e->args + atleast + 1]);</span><br><span style="color: hsl(120, 100%, 40%);">+                        int mod_len = strlen(mod);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (3 < mod_len && !strcasecmp(mod + mod_len - 3, ".so")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              mod[mod_len - 3] = '\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%);">+                   AST_RWLIST_WRLOCK(modules);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 ml = find_module_level(mod, modules);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!newlevel) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (!ml) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    /* Specified off for a nonexistent entry. */</span><br><span style="color: hsl(120, 100%, 40%);">+                                  AST_RWLIST_UNLOCK(modules);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_cli(a->fd, "Core %s is still 0 for '%s'.\n", handler_name, mod);</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%);">+                             AST_RWLIST_REMOVE(modules, ml, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+                                if (AST_RWLIST_EMPTY(modules)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_clear_flag(&ast_options, module_option);</span><br><span style="color: hsl(120, 100%, 40%);">+                              }</span><br><span style="color: hsl(120, 100%, 40%);">+                             AST_RWLIST_UNLOCK(modules);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_cli(a->fd, "Core %s was %u and has been set to 0 for '%s'.\n", handler_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ml->level, mod);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_free(ml);</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 style="color: hsl(120, 100%, 40%);">+                   if (ml) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             if ((atleast && newlevel < ml->level) || ml->level == newlevel) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    ast_cli(a->fd, "Core %s is still %u for '%s'.\n", handler_name, ml->level, mod);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      AST_RWLIST_UNLOCK(modules);</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%);">+                             oldval = ml->level;</span><br><span style="color: hsl(120, 100%, 40%);">+                                ml->level = newlevel;</span><br><span style="color: hsl(120, 100%, 40%);">+                      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                            if (!ml) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    AST_RWLIST_UNLOCK(modules);</span><br><span style="color: hsl(120, 100%, 40%);">+                                   return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+                           }</span><br><span style="color: hsl(120, 100%, 40%);">+                             oldval = ml->level;</span><br><span style="color: hsl(120, 100%, 40%);">+                                ml->level = newlevel;</span><br><span style="color: hsl(120, 100%, 40%);">+                              strcpy(ml->module, mod);</span><br><span style="color: hsl(120, 100%, 40%);">+                           AST_RWLIST_INSERT_TAIL(modules, ml, entry);</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_set_flag(&ast_options, module_option);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_cli(a->fd, "Core %s was %d and has been set to %u for '%s'.\n", handler_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                                oldval, ml->level, ml->module);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       AST_RWLIST_UNLOCK(modules);</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 style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Update global debug level */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!newlevel) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Specified level was 0 or off. */</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_RWLIST_WRLOCK(modules);</span><br><span style="color: hsl(120, 100%, 40%);">+           while ((ml = AST_RWLIST_REMOVE_HEAD(modules, entry))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_free(ml);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);</span><br><span style="color: hsl(120, 100%, 40%);">+          AST_RWLIST_UNLOCK(modules);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     oldval = *core_option;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!atleast || newlevel > *core_option) {</span><br><span style="color: hsl(120, 100%, 40%);">+         *core_option = newlevel;</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%);">+   /* Report debug level status */</span><br><span style="color: hsl(120, 100%, 40%);">+       status_debug_verbose(a, handler, oldval, *core_option);</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 style="color: hsl(120, 100%, 40%);">+static char *handle_debug(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%);">+      int atleast = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";</span><br><span> </span><br><span>       switch (cmd) {</span><br><span>       case CLI_INIT:</span><br><span>@@ -464,102 +617,61 @@</span><br><span>       * we are guaranteed to be called with argc >= e->args;</span><br><span>         */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (a->argc <= e->args) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return CLI_SHOWUSAGE;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return handle_debug_or_trace(DEBUG_HANDLER, e, cmd, a);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {</span><br><span style="color: hsl(0, 100%, 40%);">-             newlevel = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!strcasecmp(a->argv[e->args], "atleast")) {</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 *handle_trace(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%);">+  int atleast = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";</span><br><span style="color: hsl(120, 100%, 40%);">+</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 = "core set trace";</span><br><span style="color: hsl(120, 100%, 40%);">+           e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: core set trace [atleast] <level> [module]\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                  "       core set trace off\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                        "       Sets level of trace messages to be displayed or\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                  "       sets a module name to display trace messages from.\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "       0 or off means no messages should be displayed.\n";</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%);">+        case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!strcasecmp(argv3, "atleast")) {</span><br><span>                       atleast = 1;</span><br><span>                 }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 return CLI_SHOWUSAGE;</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   return CLI_SHOWUSAGE;</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (a->pos == 3 || (a->pos == 4 && atleast)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");</span><br><span style="color: hsl(120, 100%, 40%);">+                 int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         if (a->argc == e->args + atleast + 2) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   /* We have specified a module name. */</span><br><span style="color: hsl(0, 100%, 40%);">-                  char *mod = ast_strdupa(a->argv[e->args + atleast + 1]);</span><br><span style="color: hsl(0, 100%, 40%);">-                  int mod_len = strlen(mod);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (3 < mod_len && !strcasecmp(mod + mod_len - 3, ".so")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                mod[mod_len - 3] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (a->n < 21 && numbermatch == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            return complete_number(pos, 0, 0x7fffffff, a->n);</span><br><span style="color: hsl(120, 100%, 40%);">+                  } else if (pos[0] == '0') {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (a->n == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                   return ast_strdup("0");</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (a->n == (21 - numbermatch)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                  return ast_strdup("off");</span><br><span style="color: hsl(120, 100%, 40%);">+                           } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       return ast_strdup("atleast");</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               return ast_strdup("atleast");</span><br><span>                      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       AST_RWLIST_WRLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  ml = find_module_level(mod, &debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (!newlevel) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                if (!ml) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                      /* Specified off for a nonexistent entry. */</span><br><span style="color: hsl(0, 100%, 40%);">-                                    AST_RWLIST_UNLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-                                  ast_cli(a->fd, "Core debug is still 0 for '%s'.\n", mod);</span><br><span style="color: hsl(0, 100%, 40%);">-                                  return CLI_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-                             }</span><br><span style="color: hsl(0, 100%, 40%);">-                               AST_RWLIST_REMOVE(&debug_modules, ml, entry);</span><br><span style="color: hsl(0, 100%, 40%);">-                               if (AST_RWLIST_EMPTY(&debug_modules)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                     ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);</span><br><span style="color: hsl(0, 100%, 40%);">-                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               AST_RWLIST_UNLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-                          ast_cli(a->fd, "Core debug was %u and has been set to 0 for '%s'.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                      ml->level, mod);</span><br><span style="color: hsl(0, 100%, 40%);">-                             ast_free(ml);</span><br><span style="color: hsl(0, 100%, 40%);">-                           return CLI_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (ml) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               if ((atleast && newlevel < ml->level) || ml->level == newlevel) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                      ast_cli(a->fd, "Core debug is still %u for '%s'.\n", ml->level, mod);</span><br><span style="color: hsl(0, 100%, 40%);">-                                   AST_RWLIST_UNLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-                                  return CLI_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-                             }</span><br><span style="color: hsl(0, 100%, 40%);">-                               oldval = ml->level;</span><br><span style="color: hsl(0, 100%, 40%);">-                          ml->level = newlevel;</span><br><span style="color: hsl(0, 100%, 40%);">-                        } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);</span><br><span style="color: hsl(0, 100%, 40%);">-                              if (!ml) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                      AST_RWLIST_UNLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-                                  return CLI_FAILURE;</span><br><span style="color: hsl(0, 100%, 40%);">-                             }</span><br><span style="color: hsl(0, 100%, 40%);">-                               oldval = ml->level;</span><br><span style="color: hsl(0, 100%, 40%);">-                          ml->level = newlevel;</span><br><span style="color: hsl(0, 100%, 40%);">-                                strcpy(ml->module, mod);</span><br><span style="color: hsl(0, 100%, 40%);">-                             AST_RWLIST_INSERT_TAIL(&debug_modules, ml, entry);</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_set_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_cli(a->fd, "Core debug was %d and has been set to %u for '%s'.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                             oldval, ml->level, ml->module);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   AST_RWLIST_UNLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                  return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+           } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off") && strcasecmp(argv3, "channel"))</span><br><span style="color: hsl(120, 100%, 40%);">+                       || (a->pos == 5 && atleast)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RUNNING);</span><br><span>          }</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span>         }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* all the above return, so we proceed with the handler.</span><br><span style="color: hsl(120, 100%, 40%);">+       * we are guaranteed to be called with argc >= e->args;</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Update global debug level */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!newlevel) {</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Specified level was 0 or off. */</span><br><span style="color: hsl(0, 100%, 40%);">-             AST_RWLIST_WRLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-          while ((ml = AST_RWLIST_REMOVE_HEAD(&debug_modules, entry))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_free(ml);</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);</span><br><span style="color: hsl(0, 100%, 40%);">-            AST_RWLIST_UNLOCK(&debug_modules);</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-       oldval = option_debug;</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!atleast || newlevel > option_debug) {</span><br><span style="color: hsl(0, 100%, 40%);">-           option_debug = newlevel;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Report debug level status */</span><br><span style="color: hsl(0, 100%, 40%);">- status_debug_verbose(a, "Core debug", oldval, option_debug);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   return handle_debug_or_trace(TRACE_HANDLER, e, cmd, a);</span><br><span> }</span><br><span> </span><br><span> static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span>@@ -657,7 +769,7 @@</span><br><span>      }</span><br><span> </span><br><span>        /* Report verbose level status */</span><br><span style="color: hsl(0, 100%, 40%);">-       status_debug_verbose(a, "Console verbose", oldval, newlevel);</span><br><span style="color: hsl(120, 100%, 40%);">+       status_debug_verbose(a, VERBOSE_HANDLER, oldval, newlevel);</span><br><span> </span><br><span>      return CLI_SUCCESS;</span><br><span> }</span><br><span>@@ -1845,6 +1957,7 @@</span><br><span>     AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),</span><br><span> </span><br><span>        AST_CLI_DEFINE(handle_debug, "Set level of debug chattiness"),</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_CLI_DEFINE(handle_trace, "Set level of trace chattiness"),</span><br><span>     AST_CLI_DEFINE(handle_verbose, "Set level of verbose chattiness"),</span><br><span> </span><br><span>     AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),</span><br><span>diff --git a/main/logger.c b/main/logger.c</span><br><span>index 5a4b3fe..cf9357e 100644</span><br><span>--- a/main/logger.c</span><br><span>+++ b/main/logger.c</span><br><span>@@ -202,7 +202,7 @@</span><br><span> </span><br><span> static char *levels[NUMLOGLEVELS] = {</span><br><span>  "DEBUG",</span><br><span style="color: hsl(0, 100%, 40%);">-      "---EVENT---",                /* no longer used */</span><br><span style="color: hsl(120, 100%, 40%);">+  "TRACE",</span><br><span>   "NOTICE",</span><br><span>  "WARNING",</span><br><span>         "ERROR",</span><br><span>@@ -1216,9 +1216,9 @@</span><br><span> </span><br><span>       switch (cmd) {</span><br><span>       case CLI_INIT:</span><br><span style="color: hsl(0, 100%, 40%);">-          e->command = "logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";</span><br><span style="color: hsl(120, 100%, 40%);">+              e->command = "logger set level {DEBUG|TRACE|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";</span><br><span>               e->usage =</span><br><span style="color: hsl(0, 100%, 40%);">-                   "Usage: logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Usage: logger set level {DEBUG|TRACE|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"</span><br><span>                       "       Set a specific log level to enabled/disabled for this console.\n";</span><br><span>                 return NULL;</span><br><span>         case CLI_GENERATE:</span><br><span>@@ -2281,6 +2281,68 @@</span><br><span>  AST_RWLIST_UNLOCK(&logchannels);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef AST_DEVMODE</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_THREADSTORAGE_RAW(trace_indent);</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOTS_O_SPACES "                                                                                            "</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_trace(const char *file, int line, const char *func, enum ast_trace_indent_type indent_type,</span><br><span style="color: hsl(120, 100%, 40%);">+       const char* format, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   va_list ap;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned long indent = (unsigned long)ast_threadstorage_get_ptr(&trace_indent);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_str *fmt = ast_str_create(128);</span><br><span style="color: hsl(120, 100%, 40%);">+    char *direction;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!fmt) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</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%);">+   if (indent_type == AST_TRACE_INDENT_INC_BEFORE) {</span><br><span style="color: hsl(120, 100%, 40%);">+             indent++;</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_threadstorage_set_ptr(&trace_indent, (void*)indent);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (indent_type == AST_TRACE_INDENT_DEC_BEFORE) {</span><br><span style="color: hsl(120, 100%, 40%);">+             indent--;</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_threadstorage_set_ptr(&trace_indent, (void*)indent);</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%);">+   switch(indent_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_TRACE_INDENT_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+   case AST_TRACE_INDENT_SAME:</span><br><span style="color: hsl(120, 100%, 40%);">+           direction = "";</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_TRACE_INDENT_INC_BEFORE:</span><br><span style="color: hsl(120, 100%, 40%);">+     case AST_TRACE_INDENT_INC_AFTER:</span><br><span style="color: hsl(120, 100%, 40%);">+              direction = "--> ";</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_TRACE_INDENT_DEC_BEFORE:</span><br><span style="color: hsl(120, 100%, 40%);">+     case AST_TRACE_INDENT_DEC_AFTER:</span><br><span style="color: hsl(120, 100%, 40%);">+              direction = "<-- ";</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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_str_set(&fmt, 0, "%2d %-.*s%s%s:%d %s: %s", (int)indent, (indent_type == AST_TRACE_INDENT_NONE ? 0 : (int)(indent * 4)),</span><br><span style="color: hsl(120, 100%, 40%);">+            LOTS_O_SPACES, direction, file, line, func, S_OR(ast_skip_blanks(format), "\n"));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (indent_type == AST_TRACE_INDENT_INC_AFTER) {</span><br><span style="color: hsl(120, 100%, 40%);">+              indent++;</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_threadstorage_set_ptr(&trace_indent, (void*)indent);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (indent_type == AST_TRACE_INDENT_DEC_AFTER) {</span><br><span style="color: hsl(120, 100%, 40%);">+              indent--;</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_threadstorage_set_ptr(&trace_indent, (void*)indent);</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%);">+   va_start(ap, format);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log_full(__LOG_TRACE, -1, NULL, 0, NULL, 0, ast_str_buffer(fmt), ap);</span><br><span style="color: hsl(120, 100%, 40%);">+     va_end(ap);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_free(fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int ast_logger_register_level(const char *name)</span><br><span> {</span><br><span>  unsigned int level;</span><br><span>diff --git a/main/options.c b/main/options.c</span><br><span>index d6b48db..fc68c6d 100644</span><br><span>--- a/main/options.c</span><br><span>+++ b/main/options.c</span><br><span>@@ -67,6 +67,8 @@</span><br><span> int option_verbose;</span><br><span> /*! Debug level */</span><br><span> int option_debug;</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Trace level */</span><br><span style="color: hsl(120, 100%, 40%);">+int option_trace;</span><br><span> /*! Default to -1 to know if we have read the level from pjproject yet. */</span><br><span> int ast_pjproject_max_log_level = -1;</span><br><span> int ast_option_pjproject_log_level;</span><br><span>@@ -215,6 +217,7 @@</span><br><span>    /* Default to false for security */</span><br><span>  int live_dangerously = 0;</span><br><span>    int option_debug_new = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     int option_trace_new = 0;</span><br><span>    int option_verbose_new = 0;</span><br><span> </span><br><span>      /* init with buildtime config */</span><br><span>@@ -307,6 +310,11 @@</span><br><span>                      if (sscanf(v->value, "%30d", &option_debug_new) != 1) {</span><br><span>                             option_debug_new = ast_true(v->value) ? 1 : 0;</span><br><span>                    }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (!strcasecmp(v->name, "trace")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      option_trace_new = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (sscanf(v->value, "%30d", &option_trace_new) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              option_trace_new = ast_true(v->value) ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span>            } else if (!strcasecmp(v->name, "refdebug")) {</span><br><span>                  ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_REF_DEBUG);</span><br><span> #if HAVE_WORKING_FORK</span><br><span>@@ -473,6 +481,7 @@</span><br><span>       }</span><br><span> </span><br><span>        option_debug += option_debug_new;</span><br><span style="color: hsl(120, 100%, 40%);">+     option_trace += option_trace_new;</span><br><span>    option_verbose += option_verbose_new;</span><br><span> </span><br><span>    ast_config_destroy(cfg);</span><br><span>diff --git a/tests/test_scope_trace.c b/tests/test_scope_trace.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6ab480a</span><br><span>--- /dev/null</span><br><span>+++ b/tests/test_scope_trace.c</span><br><span>@@ -0,0 +1,107 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2020, Sangoma Technologies Corp</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@digium.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</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%);">+ * \file</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Test for Scope Trace</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author\verbatim George Joseph <gjoseph@digium.com> \endverbatim</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * tests for Scope Trace</span><br><span style="color: hsl(120, 100%, 40%);">+ * \ingroup tests</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%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+      <depend>TEST_FRAMEWORK</depend></span><br><span style="color: hsl(120, 100%, 40%);">+   <support_level>core</support_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%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/logger.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_scope2(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  SCOPE_TRACE(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%);">+static void test_scope(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_TRACE(1, "nested function: %d * %d = %d\n", 6, 7, (6 * 7));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ test_scope2();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_trace(1, "test no variables\n");</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%);">+AST_TEST_DEFINE(scope_test)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_TRACE(1, "top %s function\n", "scope_test");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_trace(1, "%s\n", "test outer");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "scope_test";</span><br><span style="color: hsl(120, 100%, 40%);">+               info->category = "/main/logging/";</span><br><span style="color: hsl(120, 100%, 40%);">+               info->summary = "Scope Trace Tests";</span><br><span style="color: hsl(120, 100%, 40%);">+             info->description = "Scope Trace Tests";</span><br><span style="color: hsl(120, 100%, 40%);">+         return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            {</span><br><span style="color: hsl(120, 100%, 40%);">+                     SCOPE_TRACE(1, "CASE statement\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_trace(1, "%s\n", "test case");</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</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%);">+   if (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_TRACE(1, "IF block\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             test_scope();</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_trace(1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_trace(1, "test no variables\n");</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 style="color: hsl(120, 100%, 40%);">+        ast_trace(1, "%s\n", "test variable");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return AST_TEST_PASS;</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 unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_TEST_UNREGISTER(scope_test);</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%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_TEST_REGISTER(scope_test);</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_MODULE_LOAD_SUCCESS;</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_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scope Trace Test");</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14753">change 14753</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/+/14753"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: certified/16.8 </div>
<div style="display:none"> Gerrit-Change-Id: Ic5ebb859883f9c10a08c5630802de33500cad027 </div>
<div style="display:none"> Gerrit-Change-Number: 14753 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.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: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>