Context tracing for channels

(closes issue #11268)
 Reported by: moy
 Patches: 
       chantrace-datastored-encapsulated-rev94934.patch uploaded by moy (license 222)


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@103754 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.6.0
Tilghman Lesher 18 years ago
parent 62ac882f8c
commit 26755e3882

@ -513,3 +513,6 @@ Miscellaneous
do not come from the remote party. do not come from the remote party.
* Added the 'n' option to the SpeechBackground application to tell it to not * Added the 'n' option to the SpeechBackground application to tell it to not
answer the channel if it has not already been answered. answer the channel if it has not already been answered.
* Added a compiler flag, CHANNEL_TRACE, which permits channel tracing to be
turned on, via the CHANNEL(trace) dialplan function. Could be useful for
dialplan debugging.

@ -59,4 +59,6 @@
<member name="BUSYDETECT_DEBUG" displayname="Enable additional busy detection debugging"> <member name="BUSYDETECT_DEBUG" displayname="Enable additional busy detection debugging">
<defaultenabled>no</defaultenabled> <defaultenabled>no</defaultenabled>
</member> </member>
<member name="CHANNEL_TRACE" displayname="Enable CHANNEL(trace) function">
</member>
</category> </category>

@ -71,6 +71,13 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
ast_copy_string(buf, ast_getformatname(chan->readformat), len); ast_copy_string(buf, ast_getformatname(chan->readformat), len);
else if (!strcasecmp(data, "audiowriteformat")) else if (!strcasecmp(data, "audiowriteformat"))
ast_copy_string(buf, ast_getformatname(chan->writeformat), len); ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
#ifdef CHANNEL_TRACE
else if (!strcasecmp(data, "trace")) {
ast_channel_lock(chan);
ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
ast_channel_unlock(chan);
}
#endif
else if (!strcasecmp(data, "tonezone") && chan->zone) else if (!strcasecmp(data, "tonezone") && chan->zone)
locked_copy_string(chan, buf, chan->zone->country, len); locked_copy_string(chan, buf, chan->zone->country, len);
else if (!strcasecmp(data, "language")) else if (!strcasecmp(data, "language"))
@ -105,6 +112,20 @@ static int func_channel_write(struct ast_channel *chan, const char *function,
locked_string_field_set(chan, language, value); locked_string_field_set(chan, language, value);
else if (!strcasecmp(data, "musicclass")) else if (!strcasecmp(data, "musicclass"))
locked_string_field_set(chan, musicclass, value); locked_string_field_set(chan, musicclass, value);
#ifdef CHANNEL_TRACE
else if (!strcasecmp(data, "trace")) {
ast_channel_lock(chan);
if (ast_true(value))
ret = ast_channel_trace_enable(chan);
else if (ast_false(value))
ret = ast_channel_trace_disable(chan);
else {
ret = -1;
ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).");
}
ast_channel_unlock(chan);
}
#endif
else if (!strcasecmp(data, "tonezone")) { else if (!strcasecmp(data, "tonezone")) {
struct ind_tone_zone *new_zone; struct ind_tone_zone *new_zone;
if (!(new_zone = ast_get_indication_zone(value))) { if (!(new_zone = ast_get_indication_zone(value))) {
@ -156,6 +177,9 @@ static struct ast_custom_function channel_function = {
"R/W tonezone zone for indications played\n" "R/W tonezone zone for indications played\n"
"R/W txgain set txgain level on channel drivers that support it\n" "R/W txgain set txgain level on channel drivers that support it\n"
"R/O videonativeformat format used natively for video\n" "R/O videonativeformat format used natively for video\n"
#ifdef CHANNEL_TRACE
"R/W trace whether or not context tracing is enabled\n"
#endif
"\n" "\n"
"chan_sip provides the following additional options:\n" "chan_sip provides the following additional options:\n"
"R/O rtpqos Get QOS information about the RTP stream\n" "R/O rtpqos Get QOS information about the RTP stream\n"

@ -826,6 +826,34 @@ void ast_channel_unregister(const struct ast_channel_tech *tech);
*/ */
const struct ast_channel_tech *ast_get_channel_tech(const char *name); const struct ast_channel_tech *ast_get_channel_tech(const char *name);
#ifdef CHANNEL_TRACE
/*! \brief Update the context backtrace if tracing is enabled
* \return Returns 0 on success, -1 on failure
*/
int ast_channel_trace_update(struct ast_channel *chan);
/*! \brief Enable context tracing in the channel
* \return Returns 0 on success, -1 on failure
*/
int ast_channel_trace_enable(struct ast_channel *chan);
/*! \brief Disable context tracing in the channel.
* \note Does not remove current trace entries
* \return Returns 0 on success, -1 on failure
*/
int ast_channel_trace_disable(struct ast_channel *chan);
/*! \brief Whether or not context tracing is enabled
* \return Returns -1 when the trace is enabled. 0 if not.
*/
int ast_channel_trace_is_enabled(struct ast_channel *chan);
/*! \brief Put the channel backtrace in a string
* \return Returns the amount of lines in the backtrace. -1 on error.
*/
int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **out);
#endif
/*! \brief Hang up a channel /*! \brief Hang up a channel
* \note This function performs a hard hangup on a channel. Unlike the soft-hangup, this function * \note This function performs a hard hangup on a channel. Unlike the soft-hangup, this function
* performs all stream stopping, etc, on the channel that needs to end. * performs all stream stopping, etc, on the channel that needs to end.

@ -104,6 +104,22 @@ struct chanlist {
AST_LIST_ENTRY(chanlist) list; AST_LIST_ENTRY(chanlist) list;
}; };
#ifdef CHANNEL_TRACE
/*! \brief Structure to hold channel context backtrace data */
struct ast_chan_trace_data {
int enabled;
AST_LIST_HEAD_NOLOCK(, ast_chan_trace) trace;
};
/*! \brief Structure to save contexts where an ast_chan has been into */
struct ast_chan_trace {
char context[AST_MAX_CONTEXT];
char exten[AST_MAX_EXTENSION];
int priority;
AST_LIST_ENTRY(ast_chan_trace) entry;
};
#endif
/*! \brief the list of registered channel types */ /*! \brief the list of registered channel types */
static AST_LIST_HEAD_NOLOCK_STATIC(backends, chanlist); static AST_LIST_HEAD_NOLOCK_STATIC(backends, chanlist);
@ -314,6 +330,133 @@ static struct ast_cli_entry cli_channel[] = {
AST_CLI_DEFINE(handle_cli_core_show_channeltype, "Give more details on that channel type") AST_CLI_DEFINE(handle_cli_core_show_channeltype, "Give more details on that channel type")
}; };
#ifdef CHANNEL_TRACE
/*! \brief Destructor for the channel trace datastore */
static void ast_chan_trace_destroy_cb(void *data)
{
struct ast_chan_trace *trace;
struct ast_chan_trace_data *traced = data;
while ((trace = AST_LIST_REMOVE_HEAD(&traced->trace, entry))) {
ast_free(trace);
}
ast_free(traced);
}
/*! \brief Datastore to put the linked list of ast_chan_trace and trace status */
const struct ast_datastore_info ast_chan_trace_datastore_info = {
.type = "ChanTrace",
.destroy = ast_chan_trace_destroy_cb
};
/*! \brief Put the channel backtrace in a string */
int ast_channel_trace_serialize(struct ast_channel *chan, struct ast_str **buf)
{
int total = 0;
struct ast_chan_trace *trace;
struct ast_chan_trace_data *traced;
struct ast_datastore *store;
ast_channel_lock(chan);
store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
if (!store) {
ast_channel_unlock(chan);
return total;
}
traced = store->data;
(*buf)->used = 0;
(*buf)->str[0] = '\0';
AST_LIST_TRAVERSE(&traced->trace, trace, entry) {
if (ast_str_append(buf, 0, "[%d] => %s, %s, %d\n", total, trace->context, trace->exten, trace->priority) < 0) {
ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
total = -1;
break;
}
total++;
}
ast_channel_unlock(chan);
return total;
}
/* !\brief Whether or not context tracing is enabled */
int ast_channel_trace_is_enabled(struct ast_channel *chan)
{
struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
if (!store)
return 0;
return ((struct ast_chan_trace_data *)store->data)->enabled;
}
/*! \brief Update the context backtrace data if tracing is enabled */
static int ast_channel_trace_data_update(struct ast_channel *chan, struct ast_chan_trace_data *traced)
{
struct ast_chan_trace *trace;
if (!traced->enabled)
return 0;
/* If the last saved context does not match the current one
OR we have not saved any context so far, then save the current context */
if ((!AST_LIST_EMPTY(&traced->trace) && strcasecmp(AST_LIST_FIRST(&traced->trace)->context, chan->context)) ||
(AST_LIST_EMPTY(&traced->trace))) {
/* Just do some debug logging */
if (AST_LIST_EMPTY(&traced->trace))
ast_log(LOG_DEBUG, "Setting initial trace context to %s\n", chan->context);
else
ast_log(LOG_DEBUG, "Changing trace context from %s to %s\n", AST_LIST_FIRST(&traced->trace)->context, chan->context);
/* alloc or bail out */
trace = ast_malloc(sizeof(*trace));
if (!trace)
return -1;
/* save the current location and store it in the trace list */
ast_copy_string(trace->context, chan->context, sizeof(trace->context));
ast_copy_string(trace->exten, chan->exten, sizeof(trace->exten));
trace->priority = chan->priority;
AST_LIST_INSERT_HEAD(&traced->trace, trace, entry);
}
return 0;
}
/*! \brief Update the context backtrace if tracing is enabled */
int ast_channel_trace_update(struct ast_channel *chan)
{
struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
if (!store)
return 0;
return ast_channel_trace_data_update(chan, store->data);
}
/*! \brief Enable context tracing in the channel */
int ast_channel_trace_enable(struct ast_channel *chan)
{
struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
struct ast_chan_trace_data *traced;
if (!store) {
store = ast_channel_datastore_alloc(&ast_chan_trace_datastore_info, "ChanTrace");
if (!store)
return -1;
traced = ast_calloc(1, sizeof(*traced));
if (!traced) {
ast_channel_datastore_free(store);
return -1;
}
store->data = traced;
AST_LIST_HEAD_INIT_NOLOCK(&traced->trace);
ast_channel_datastore_add(chan, store);
}
((struct ast_chan_trace_data *)store->data)->enabled = 1;
ast_channel_trace_data_update(chan, store->data);
return 0;
}
/*! \brief Disable context tracing in the channel */
int ast_channel_trace_disable(struct ast_channel *chan)
{
struct ast_datastore *store = ast_channel_datastore_find(chan, &ast_chan_trace_datastore_info, NULL);
if (!store)
return 0;
((struct ast_chan_trace_data *)store->data)->enabled = 0;
return 0;
}
#endif /* CHANNEL_TRACE */
/*! \brief Checks to see if a channel is needing hang up */ /*! \brief Checks to see if a channel is needing hang up */
int ast_check_hangup(struct ast_channel *chan) int ast_check_hangup(struct ast_channel *chan)
{ {

@ -987,6 +987,9 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
char nf[256], wf[256], rf[256]; char nf[256], wf[256], rf[256];
long elapsed_seconds=0; long elapsed_seconds=0;
int hour=0, min=0, sec=0; int hour=0, min=0, sec=0;
#ifdef CHANNEL_TRACE
int trace_enabled;
#endif
switch (cmd) { switch (cmd) {
case CLI_INIT: case CLI_INIT:
@ -1071,7 +1074,12 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
ast_cli(a->fd," Variables:\n%s\n", out->str); ast_cli(a->fd," Variables:\n%s\n", out->str);
if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1)) if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1))
ast_cli(a->fd," CDR Variables:\n%s\n", out->str); ast_cli(a->fd," CDR Variables:\n%s\n", out->str);
#ifdef CHANNEL_TRACE
trace_enabled = ast_channel_trace_is_enabled(c);
ast_cli(a->fd, " Context Trace: %s\n", trace_enabled ? "Enabled" : "Disabled");
if (trace_enabled && ast_channel_trace_serialize(c, &out))
ast_cli(a->fd, " Trace:\n%s\n", out->str);
#endif
ast_channel_unlock(c); ast_channel_unlock(c);
return CLI_SUCCESS; return CLI_SUCCESS;
} }

@ -2673,6 +2673,9 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
ast_copy_string(c->exten, exten, sizeof(c->exten)); ast_copy_string(c->exten, exten, sizeof(c->exten));
c->priority = priority; c->priority = priority;
pbx_substitute_variables(passdata, sizeof(passdata), c, e); pbx_substitute_variables(passdata, sizeof(passdata), c, e);
#ifdef CHANNEL_TRACE
ast_channel_trace_update(c);
#endif
ast_debug(1, "Launching '%s'\n", app->name); ast_debug(1, "Launching '%s'\n", app->name);
if (VERBOSITY_ATLEAST(3)) { if (VERBOSITY_ATLEAST(3)) {
char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE]; char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];

Loading…
Cancel
Save