<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>