diff options
author | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-02-12 22:11:02 +0000 |
---|---|---|
committer | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-02-12 22:11:02 +0000 |
commit | 89201083ba81ee8249f1d852dd00ccc154a711a4 (patch) | |
tree | 9f87789697c383f0cdbe2689d5b57fe3cead0757 | |
parent | 8efd511a7e93e18a0c1945e63d0751571c8091e1 (diff) |
Add queue logging and fix indications buglet
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@2159 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-x | apps/app_queue.c | 47 | ||||
-rwxr-xr-x | doc/queuelog.txt | 62 | ||||
-rwxr-xr-x | include/asterisk/logger.h | 3 | ||||
-rwxr-xr-x | indications.c | 4 | ||||
-rwxr-xr-x | logger.c | 38 |
5 files changed, 147 insertions, 7 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c index e5e484149..1f28aa6da 100755 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -35,6 +35,8 @@ #include <sys/signal.h> #include <netinet/in.h> +#include "../astconf.h" + #include <pthread.h> #define QUEUE_STRATEGY_RINGALL 0 @@ -128,6 +130,8 @@ struct queue_ent { char announce[80]; /* Announcement to play */ char context[80]; /* Context when user exits queue */ int pos; /* Where we are in the queue */ + int opos; /* Where we started in the queue */ + int handled; /* Whether our call was handled */ time_t start; /* When we started holding */ struct ast_channel *chan; /* Our channel */ struct queue_ent *next; /* The next queue entry */ @@ -221,6 +225,7 @@ static int join_queue(char *queuename, struct queue_ent *qe) qe->next = NULL; qe->parent = q; qe->pos = ++pos; + qe->opos = pos; strncpy(qe->moh, q->moh, sizeof(qe->moh)); strncpy(qe->announce, q->announce, sizeof(qe->announce)); strncpy(qe->context, q->context, sizeof(qe->context)); @@ -699,6 +704,9 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri int allowredir_out=0; int allowdisconnect=0; char restofit[AST_MAX_EXTENSION]; + char oldexten[AST_MAX_EXTENSION]=""; + char oldcontext[AST_MAX_EXTENSION]=""; + char queuename[256]=""; char *newnum; struct ast_channel *peer; struct localuser *lpeer; @@ -707,8 +715,10 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri int x=0; char *announce = NULL; char digit = 0; + time_t callstart; /* Hold the lock while we setup the outgoing calls */ ast_mutex_lock(&qe->parent->lock); + strncpy(queuename, qe->parent->name, sizeof(queuename) - 1); cur = qe->parent->members; if (strlen(qe->announce)) announce = qe->announce; @@ -797,6 +807,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri /* Ah ha! Someone answered within the desired timeframe. Of course after this we will always return with -1 so that it is hung up properly after the conversation. */ + qe->handled++; if (!strcmp(qe->chan->type,"Zap")) { if (tmp->dataquality) zapx = 0; ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0); @@ -822,6 +833,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri if (res2) { /* Agent must have hung up */ ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name); + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", ""); ast_hangup(peer); return -1; } @@ -832,6 +844,7 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri /* Make sure channels are compatible */ res = ast_channel_make_compatible(qe->chan, peer); if (res < 0) { + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", ""); ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name); ast_hangup(peer); return -1; @@ -843,7 +856,18 @@ static int try_calling(struct queue_ent *qe, char *options, char *announceoverri ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); ast_channel_sendurl( peer, url ); } /* /JDG */ + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start); + strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1); + strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1); + time(&callstart); bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect); + if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context); + } else if (qe->chan->_softhangup) { + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); + } else { + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); + } if(bridge != AST_PBX_NO_HANGUP_PEER) ast_hangup(peer); @@ -1139,41 +1163,54 @@ static int queue_exec(struct ast_channel *chan, void *data) qe.chan = chan; qe.start = time(NULL); if (!join_queue(queuename, &qe)) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->callerid ? chan->callerid : ""); /* Start music on hold */ ast_moh_start(chan, qe.moh); for (;;) { res = wait_our_turn(&qe); /* If they hungup, return immediately */ if (res < 0) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "User disconnected while waiting their turn\n"); res = -1; } break; } - if (!res) + if (!res) break; - if (valid_exit(&qe, res)) + if (valid_exit(&qe, res)) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); break; + } } if (!res) { for (;;) { res = try_calling(&qe, options, announceoverride, url, &go_on); - if (res) + if (res) { + if (res < 0) { + if (!qe.handled) + ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); + } else if (res > 0) + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); break; + } res = wait_a_bit(&qe); if (res < 0) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start); if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n"); res = -1; } break; } - if (res && valid_exit(&qe, res)) + if (res && valid_exit(&qe, res)) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); break; - + } /* exit after a timeout if 'n' option enabled */ if (go_on) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); res = 0; break; } diff --git a/doc/queuelog.txt b/doc/queuelog.txt new file mode 100755 index 000000000..fc93d2490 --- /dev/null +++ b/doc/queuelog.txt @@ -0,0 +1,62 @@ +Queue Log Information +===================== + +In order to properly manage ACD queues, it is important to be able to +keep track of details of call setups and teardowns in much greater detail +than traditional call detail records provide. In order to support this, +extensive and detailed tracing of every queued call is stored in the +queue log, located (by default) in /var/log/asterisk/queue_log. + +These are the events (and associated information) in the queue log: + +ABANDON(position|origposition|waittime) +The caller abandoned their position in the queue. The position is the +caller's position in the queue when they hungup, the origposition is +the original position the caller was when they first entered the +queue, and the waittime is how long the call had been waiting in the +queue at the time of disconnect. + +AGENTDUMP +The agent dumped the caller while listening to the queue announcement. + +COMPLETEAGENT(holdtime|calltime|origposition) +The caller was connected to an agent, and the call was terminated normally +by the *agent*. The caller's hold time and the length of the call are both +recorded. The caller's original position in the queue is recorded in +origposition. + +COMPLETECALLER(holdtime|calltime|origposition) +The caller was connected to an agent, and the call was terminated normally +by the *caller*. The caller's hold time and the length of the call are both +recorded. The caller's original position in the queue is recorded in +origposition. + +CONFIGRELOAD +The configuration has been reloaded (e.g. with asterisk -rx reload) + +CONNECT(holdtime) +The caller was connected to an agent. Hold time represents the amount +of time the caller was on hold. + +ENTERQUEUE(url|callerid) +A call has entered the queue. URL (if specified) and Caller*ID are placed +in the log. + +EXITWITHKEY(key|position) +The caller elected to use a menu key to exit the queue. The key and +the caller's position in the queue are recorded. + +EXITWITHTIMEOUT(position) +The caller was on hold too long and the timeout expired. + +QUEUESTART +The queueing system has been started for the first time this session. + +SYSCOMPAT +A call was answered by an agent, but the call was dropped because the +channels were not compatible. + +TRANSFER(extension,context) +Caller was transferred to a different extension. Context and extension +are recorded. + diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index c2598b40d..e0d3f5a94 100755 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -40,6 +40,9 @@ extern "C" { extern void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf, 5, 6))); +extern void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...) + __attribute__ ((format (printf, 5, 6))); + //! Send a verbose message (based on verbose level) /*! * This works like ast_log, but prints verbose messages to the console depending on verbosity level set. diff --git a/indications.c b/indications.c index 4632f69ff..fefec9153 100755 --- a/indications.c +++ b/indications.c @@ -318,11 +318,11 @@ static inline void free_zone(struct tone_zone* zone) struct tone_zone_sound *tmp = zone->tones->next; free((void*)zone->tones->name); free((void*)zone->tones->data); - if (zone->ringcadance) - free((void*)zone->ringcadance); free(zone->tones); zone->tones = tmp; } + if (zone->ringcadance) + free((void*)zone->ringcadance); free(zone); } @@ -220,6 +220,43 @@ static void init_logger_chain(void) ast_mutex_unlock(&loglock); } +static FILE *qlog = NULL; +static ast_mutex_t qloglock = AST_MUTEX_INITIALIZER; + +void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...) +{ + va_list ap; + ast_mutex_lock(&qloglock); + if (qlog) { + va_start(ap, fmt); + fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event); + vfprintf(qlog, fmt, ap); + fprintf(qlog, "\n"); + va_end(ap); + fflush(qlog); + } + ast_mutex_unlock(&qloglock); +} + +static void queue_log_init(void) +{ + char filename[256]; + int reloaded = 0; + ast_mutex_lock(&qloglock); + if (qlog) { + reloaded = 1; + fclose(qlog); + qlog = NULL; + } + snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, "queue_log"); + qlog = fopen(filename, "a"); + ast_mutex_unlock(&qloglock); + if (reloaded) + ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", ""); + else + ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", ""); +} + int reload_logger(int rotate) { char old[AST_CONFIG_MAX_PATH]; @@ -294,6 +331,7 @@ int reload_logger(int rotate) return 0; } else ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno)); + queue_log_init(); init_logger_chain(); return -1; } |