Frequently Asked Questions on QueueMetrics (FAQs)

Here is a list of solutions to common problems encountered when running QueueMetrics.
For complete information on how to set up QueueMetrics, please consult the User manuals.
You may also want to have a look at the Installing QueueMetrics metanode on AstRecipes or to our own official QueueMetrics forum.

QueueMetrics reports

QueueMetrics real-time page

Configuring Agents

QueueMetrics installation

MySQL storage and QLoaderd

QueueMetrics configuration

Running outbound campaigns

Common QueueMetrics errors

MySQL-related issues

XML-RPC issues

License-related issues

Advanced configuration

QueueMetrics Add-ons

How do I install or update a QueueMetrics license?

There a two ways to do that:
  • From the QueueMetrics interface log in as an ADMIN user, then go into the "License page" (key button, at top-right), in there you'll find an "Install new license" link newar your current license's information.
    If you don't see the link make sure that your Admin user has the KEYUPDATE security key.

    Insert your license, confirm and wait for confirmation, then you are ready to go.
  • You can also change your license manually: open the /path/to/queuemetrics/WEB-INF/ file and put your license code into the LICENZA_ARCHITETTURA variable (uncomment the line if necessary).
    After that restart QueueMetrics with '/etc/init.d/queuemetrics restart'

Permalink - Table of contents

Can i receive notifications for Qloader errors?

Qloaderd monitor

Yes, we provide a script (that can be run nightly) that will notify the sysadmin of the errors encountered in the Qloader's log file.This script will monitor the log produced by Qloaderd for disconnection errors and will send an email to the sysadmin in case any are found. This is useful because if you operate on a WAN, it is possible that you have long-term downtimes that risk losing data (for example if you do a logrotate while the network is down).

Permalink - Table of contents

Can i manage QueueMetrics Through JSON?

JSON PBX actions - Version 1.0

Yes, QueueMetrics also supports JSON requests. We provide a sample script that contains a set of functions and a set of examples. This enables an external robot to perform login/logout, pause/unpause, hangup, monitor calls and other PBX oriented actions by simply calling a set of JSON RPC.

Permalink - Table of contents

Where can i find a simple wallboard for QueueMetrics?

The Flantel qmon.php wallboard - Version 1.1

This is the original script, and a QM users' all-time favourite. Now patched to support QueueMetrics 15.02. It provides a simple wallboard to view you QM data in real-time.

Permalink - Table of contents

Can i Log IVR responses to QA forms in QueueMetrics?

Log Asterisk IVR to a QA form

Yes, we provide a sample script with a trivial example that shows how to log an IVR that
is run at the end of a call to a QA form in QueueMetrics.

Permalink - Table of contents

Is it possible to integrate QueueMetrics with Sugar CRM?

Sugar CRM Integration - Version 1.1

This script integrates the QueueMetrics agent page with SugarCRM. When properly configured, the QueueMetricsagent call history page opens an external URL for each taken call. This feature could be used to call the providedPHP script. The script searches between contacts in the SugarCRM, starting from the calling number, and opens thecall detail record, if present on SugarCRM database, or preloads a new contact page with the calling party number.

Permalink - Table of contents

Is there a way to remove all agents from a queue?

Remove all agents - Version 1.0

Yes, This bash script removes all agents from a queue. It comes in handy to run at night to make sure all agentsare logged off at the end of their shift. You may also run it manually to "reset" an Asterisk queue.

Permalink - Table of contents

Is it possible to integrate QueueMetrics with VTiger CRM?

VTiger CRM Integration - Version 1.0

This script integrates the QueueMetrics agent page with VTigerCRM. When properly configured, the QueueMetrics agent call history page opens an external URL for each taken call. This feature could be used to call the provided PHP script. The script searchesbetween contacts in the VTigerCRM, starting from the calling number, and opens the call detail record, if present on VTigerCRMdatabase, or preloads a new contact page with the calling party number.

Permalink - Table of contents

Is there a way to keep track of the number of active agents?

Count Agents - Version 1.0

We provide a Count Agent script: a PHP script that counts how many unique agents are running on a given set of queues during a chosen period of time.

Permalink - Table of contents

Can i manage QueueMetrics Trough XML-RPC?

XML-RPC Test Servlet - Version 1.0

Yes you can. We provide a simple Java Servlet for XML-RPC testing with QueueMetrics. It comes in handy when practicing with the XML-RPC library becaus it allows you to see the exact output from the various XML-RPC requests sent to QueueMetrics while writing your custom reports.

Permalink - Table of contents

How to search all calls excluding ones with a specific outcome

Let's say you want to see all calls that aren't marked with outcome 'sales'.

Outcome codes are evaluated as regular expressions so all you have to do is to define a new outcome code ("Edit call outcomes" page):
Status code: ^(?!.*sale).*$
Description: Not sale

In this way, running a custom report filtering the calls by the "Not sale" outcome you will exclude all the calls with "Sale" outcome.

All you have to do now is to set a security key to this new outcome so that it won't be visible to your agents.

Permalink - Table of contents

How to configure outgoing emails with Gmail

In order to use your Gmail account in order to send automated email reports, configure QueueMetrics as follows:
default.smtpssl = true

Permalink - Table of contents

What's the difference between Agents and Users in QueueMetrics?

In QueueMetrics you define agents, every agent represent a person in your call center.
You want to define a new agent:

  • Asterisk agent code: agent/321 (this has to follow the pattern: agent/somenumber)
  • Agent description: John Doe (this is the human-readable translation; in your report you'll get the real name, not the agent code)

As well you'll need to define a new user:

  • Login: agent/321 (the same of the agent)
  • Password: password
  • Real name: John Doe
Why we created an user and an agent with the same name?

Users and agents are different in QueueMetrics: a user is an access credential to QueueMetrics, it doesn't have to be an agent, it could be just someone that can run reports or an admin user.
An agent, instead, doesn't need to be necessarily an user; if your agents are static in the queues and always use the same phones, you'd want to define the agents in QueueMetrics just to translate phone codes (e.g. SIP/3321) in a readable name in reports.

Permalink - Table of contents

How do I make my agents know which queue is ringing their phone?

It's not possible for QueueMetrics to know which queue is ringing your agents' phones, since that depends also on internal Asterisk's decisions based on its configuration.

What you can do is to modify the caller id of the call, to show the queue's name before the caller's number.

Modify the queue's dialplan adding, before the Answer:
exten => queue-ext,n,Set(CALLERID(name)=queuename - ${CALLERID(num))

Permalink - Table of contents

How to make my agents set a new pause without unpausing first

When you send a new Pause event without Unpausing first QueueMetrics doesn't consider that a new pause but always the same pause. It consider as the correct pause code the last one issued.
In order to have two distinct pauses you'll have to unpause, then pause again with the new code.

If you don't like this behaviour (for example, you don't want your agents to be able to change a running pause code) add this line to the QueueMetrics dialplan, at extesion 22, before the "PauseQueueMember" line: exten => 22,n,System( echo "${EPOCH}|NONE|NONE|Agent/${AGENTCODE}|UNPAUSEALL|" >> /var/log/asterisk/queue_log )

Permalink - Table of contents

What happens when a call overlaps the report's time window?

The QueueMetrics database is built around the concept of a stream of events. Every event is bound to its timestamp (time when it happened).

When you run a report fro a specific time period, especially if it is very short because you are polling data via XML-RPC, QueueMetrics includes all the information that comes from events in the specified time-frame, and nothing more. So there are four scenarios:
  • Calls which its events are all in the time period: no problems; they are correctly reported.
  • Calls which started in the time period, but ended after it. You'll know when it started but not when it ended.
  • Calls which started before the time period but ended in it. Some information (notably the Caller-ID) is missing.
  • Calls which started before the time period and terminated after the time period without any event in-between. These calls didn't generate any event in that time period. So such calls might be skipped altogether.
The reason why QueueMetrics uses a bounded window is that when running a report for a specific period, a deeper problem looms: when is a call to be counted? when it started in the given period, or when it connected, or when it ended, or when it is completely within? this commonly happens when you make multiple consecutive short-time analyses - if a call starts in period A and ends in period B, where is it to be counted? the correct answer depends on what you need the data for, so our approach is to be agnostic on this and look at plain events.

A good real-life solution to the problem is to take your time period and add a margin before and after. How much is a good margin? it depends. We suggest at least twice the average duration of the calls in your call center. Then your script will examine those calls timings (answer, hang-up) and decide which ones to count and which are to be skipped.

Permalink - Table of contents

Why do I get a JSP compilation error (missing method)?

Sometimes, after an update, it could happen that you get an error in the JSP files compilation.
In that case you'll need to clean the Tomcat's cache:

/etc/init.d/queuemetrics stop
/etc/init.d/qm-tomcat6 cleancache
/etc/init.d/queuemetrics start

Permalink - Table of contents

I use FreePBX - why do agents on a call show up with a different name?

When setting up FreePBX, you can tell it to either use the default Extension mode or use the "User & Device" mode. While in Extension mode the user (agent) code and thir extension match, in U&D mode they are independent.

When running in this mode, agents are logged in one way when they join a queue (usually with their extension code) and in a different way (using their user name) when they receive a call. So QueueMetrics sees the equivalent of "Extension 203 logged on at 9:30 and John received a call at 9:31" and cannot natively make sense of it, as it is never logged that extension 203 goes under the name John. That's why you see agents logged under one name and handling calls under a different one.

In order to handle this, QueueMetrics has the concept of "Friendly name", that is a name that you configure on the agent configuration page that will be mapped to the same agent code. So, if you set up a friendly name of "John" for Agent/203, whenever QueueMetrics finds a "John" it will silently rewrite it as Agent/203. This way, calls are attribuited correctly and agent sessions are counted correctly.

You can have multiple friendly names for the same extensions. Just enter them separated by a pipe character. This is needed in case you changed the User name during the period under analysis.

Please note that agent session statistics will be incorrect if you do not set Friendly Names when they are needed. In general, anyway, if you need to keep track of multipl epeople working from the same extension, QueueMetrics Hotdesking mode will be a better approach.

See also:

Permalink - Table of contents

Why do I see agents logged in twice - under their own name and as Agent/name?

If you see agent logged in twice, once under their correct name and a second one under the name "Agent/agent name", often with a difference of a few seconds. Sometimes you will see that the correct name will log off at the end of the agent session, while the "Agent/agent name" will linger on for a while.

This is caused by not having "Friendly names" set - see Why do agents on a call show up with a different name? to fix this.

Permalink - Table of contents

How do I enable actions (login, logoff, transfer....) on the Realtime page?

Since QueueMetrics 12.10, the Realtime page lets you perform a set of actions that are sent to Asterisk for processing. These include:
  • Logging agents on and off
  • Pausing and unpausing agents
  • Transferring calls
  • Sending SMS
  • Listening to live calls
If you upgrade from an earlier system, these actions will not usually appear in your RT page - this is because they need three distinct elements:
  1. A security key: each action is enabled by giving your users a specific security key. You should esit the user or class profile and add the required key
  2. A configuration item: the action is possible only if we tell QM that the action is allowed and how to perform it (that is, where is the Asterisk dialplan it should go in order to have the action performed). If you upgrade from an earlier version, you should manually add the configuration items in your All such properties start with "callfile.*"
  3. A dialplan item: the Asterisk dialplan should include an extension (generally in the supplied context named queuemetrics) that actually performs the requested action
Let's see an example: imagine we want to turn on call transfers on an older system.
  1. First we add the key RT_TRANSFERCALL to the Admin class. A list of keys for each feature can be found in the Qm user manual, appendix B: Security keys
  2. Then we add the following configuration item:


    This stanza tells QM that the feature is enabled and that in order to process it is must invoke extension 31@queuemetrics in Asterisk. A list of properties for each feature can be found in the Qm user manual, appendix D. System preferences
  3. The Asterisk dialplan should include a stanza like:
    exten => 31,1,NoOp( " QM: Call redirect ,ade by ${QM_LOGIN} for callID: ${CALLID} to extension ${REDIR_EXT}")
    exten => 31,n,ChannelRedirect(${CALLID},from-internal,${REDIR_EXT},1)
    exten => 31,n,Hangup

    Samples for each possible stanza are found in the extensions_queuemetrics.conf that ships with each version of QM and must be adapted to your local system.
    More details can be found in the Qm user manual, appendix C. The [queuemetrics] context

Permalink - Table of contents

Completion of any call in the queue appears as Caller Completed.

All calls processed by QueueMetrics are reported as if the caller hung up, even when it was the agent hanging up.

This is a known issue with FreePBX 2.10 and you can easily fix it by editing the dialplan as explained in the Asterisk Forums.

Permalink - Table of contents

Printing and mailing out a report automatically

Since QueueMetrics 13.04, it is possible to have QueueMetrics generate a report in PDF or XLS format, and download it or sent it automatically to a group of recipients by e-mail. The following notes only apply to earlier versions of QueueMetrics.

It is possible to print a full report to PDF automatically and have it emailed periodically with no human intervention.
In order to run the following script, you need to install the following packages on your server:
yum install htmldoc
yum install nail

(you need to enable the DAG repository to have nail).

The script is as follows:
#! /bin/bash


# cleanup images
rm -rf $QM_WEBAPP/
rm -rf img/

# download images
wget -nH -k -K -p "$QM_SERVER/$QM_WEBAPP/$QM_USER&pass=$QM_ASS&queues=none&period=t1"

mv $QM_WEBAPP/img/ .

wget -o img/shade-histo.gif "$QM_SERVER/$QM_WEBAPP/img/shade-histo.gif"

# download report
wget -nH -k -K -p -l 1 -O report.html "$QM_SERVER/$QM_WEBAPP/$QM_USER&pass=$QM_PASS&queues=$QM_QUEUE&period=$QM_PERIOD"

# convert to PDF
htmldoc --webpage --size 11x8.5in -f myreport.pdf myreport.html

# mail out
echo "Your daily report is attached as a PDF" | env MAILRC=/dev/null nail -n -s"Daily Report" -a myreport.pdf $EMAIL

This can be run automatically. For valid queue and time period parameters, see the chapter "Automating statistics download: the ROBOT profile" in the QM user manual.

In order to run the script, make sure that the ROBOT user is enabled in your QueueMetrics installation (it is disabled by default).

Permalink - Table of contents

QueueMetrics logs are filling up all of my disk

QueueMetrics produces a detailed activity at the container level that lets us diagnose performance issues and technical errors.

These logs are NOT automatically deleted in any way so they may end up filling all of the disk space if they are never purged.

As disk space is very cheap these days, we advise in any case to make a backup before removing files and data - what is removed cannot be restored.

The system log
The system log is where QM keeps information about actions performed and failed and successful log-ons. You can purge it manually by running the following queries:
mysql> delete from arch_syslog where sys_dt_creazione < DATE_SUB( NOW(), INTERVAL 90 DAY );
Query OK, 756 rows affected (0.04 sec)
mysql> optimize table arch_syslog;

Optimizing is very important as it reclaims disk space. The query above deletes all records older than 90 days.

Tomcat log files
Tomcat keeps a running log of all activity and errors. In a standard QM installation, it should be located in /usr/local/queuemetrics/tomcat/logs.

[root@qm ~]# du --human-readable /usr/local/queuemetrics/tomcat/logs/
6.1G /usr/local/queuemetrics/tomcat/logs/
[root@qm ~]# cd /usr/local/queuemetrics/tomcat/logs/
[root@qm logs]# /etc/init.d/queuemetrics stop
[root@qm logs]# rm -f catalina.out
[root@qm logs]# rm -f localhost*.txt
[root@qm logs]# /etc/init.d/queuemetrics start
[root@qm logs]# du --human-readable /usr/local/queuemetrics/tomcat/logs/
20M /usr/local/queuemetrics/tomcat/logs/

As you can see, it is necessary to stop Tomcat in order to do this.

If you want, it is possible to control the logging made by Tomcat or turn it off altogether - see section "Logs and Logging" of the WombatDialer User Manual at

Permalink - Table of contents

"Agent status cannot be determined" after logging on

After logging on or off from the agent's page, you still see the agent status as"Agent status cannot be determined".

When QueueMetrics performs an action, what it actually does is to send a commandto Asterisk over AMI as an Originate request, waits a few seconds and and thenreads back the results from the queue_log.

There may be two issues here:
  1. if Asterisk is receiving isn't processing the request, then we have no way of knowing that it hasn't been implemented;
  2. if Asterisk is very slow in processing this request because (for example) it is quite busy, then it is possible that it will take a while for the request to be processed, so when the page reloads, the request may not have been loaded yet.
What we suggest in this case is:
  1. Check on the AMI tester from the DBTEST page whether it is possible for QM to send commands to Asterisk and whether the relevant piece of dialplan is present in Asterisk;
  2. if all is well, you should monitor what Asterisk is doing at the CLI level when you receive a failed log-in/off attempt; whether the agent is actually added to the queue or not and whether the queue_log is updated.

Permalink - Table of contents

Moving a QueueMetrics instance to a new server

If you need to move your existing QueueMetrics server to a different host and do not want to lose your current data and configuration, you can do that easily using yum. As a side effect, your system will be updated to the latest version. In this tutorial we expect that the MySQL server was on the old QM server and you want to use a new one on your new server, so you will have to move the database as well. Asterisk may be local on the old server or on a separate server altogether.
  1. Stop any qloaderd running, so the current database is in a stable state
  2. Make a complete backup of your existing system (configuration and database - see below)
  3. Stop the old QueueMetrics instance
  4. Install QueueMetrics using yum on your new server
  5. When it's working (you are able to log in), turn it off
  6. Edit the memory settings for your new system
  7. Overwrite the QueueMetrics database on the new server with the database dump from the old server
  8. Copy web.xml and the various properties files from the WEB-INF/ folder of the old system to the new system
  9. Make sure the access parameters for the database are correct (they usually already are, as the database is searched for on 'localhost')
  10. Start the new QueueMetrics instance
  11. When you connect to the new QueueMetrics, it will sense that the database comes from an older version and will automatically update it, if needed
  12. Edit your qloaderd properties (usually stored in /etc/sysconfig/qloaderd on the Asterisk server) so that it can upload data to the new database
  13. Restart qloaderd
  14. Check that it is able to upload data to the new database (you may need to create a MySQL grant so that qloaderd can connect to the new server)
  15. The new system should be working now!
It is of paramount importance that the new system and the old system are never running at the same time, as this could lead to license deactivation.

See also:
  1. Installing QueueMetrics using yum
  2. Backing up a QueueMetrics system and Backing up and restoring a QueueMetrics system
  3. Tuning Java memory
  4. Access Denied MySQL errors

Permalink - Table of contents

Taking an activity trace

In order to debug a set of issues with agents not logging in correctly, we often ask users to provide an activity trace. Here is how you should do it.

First and foremost, you should take an activity trace only when the PBX is idle; otherwise a number of unrelated log lines are inserted and it is hard to understand the result.

You should open the queue_log file on the PBX that is located in /var/log/asterisk/queue_log - you could e.g. issue the command:
tail -f /var/log/asterisk/queue_log
that will display the new lines being appended.

What you do now is:
  1. You log the agent on (from either the QM agent's page or your own login scripts)
  2. You send a call to the agent; have the agent answer it and hang up
  3. You set a status code for the call
  4. You pause the agent (from either the QM agent's page or your own scripts). If you do it from the QM web interface, do set a pause code.
  5. After a few seconds, you unpause the agent
  6. You log the agent off
You can now send Loway the resulting logs, from which it is possible to understand what is going wrong.

Permalink - Table of contents

Understanding QueueMetrics agent name rewriting

QueueMetrics was built to handle agent names as separate entities from extensions. This raises a few issues with newer versions of Asterisk, as the canonical form Agent/1234 may not be used.

In order to do this, it is better if you start by taking an activity trace as described in a separate FAQ here.

The first thing that we have to implement is that if see channels appearing on the log as Local/1234@from-internal, then you have to set:
so that when QM reads them back, it reads them as Agent/1234. This is used as the channel string is used as the agent's name, as configured in the Edit Agents page of QueueMetrics.

The second issue you may have is that if you use a GUI, it is possible that you see the agent names logged in "friendly" format, as e.g mike boo instead of Local/1234@from-internal. The big problem here is that this only applies to calls and not to agents logging on and off.

This typically leads to a situation where, on the real-time page, you see the agent logging on as e.g. "Mike Boo (1234)" (that's the name you gave the agent in QM) and then when he first receives a call, a new entry "agent/mike boo" appears as well.

In order to solve this, we have to tell QM that when it finds mike boo it needs to read it as Agent/1234. We do this by setting a "fiendly name" for the agent, that must be the exact string that the agent appears on the queue_log as, for our agent in the Edit Agents page of QueueMetrics.

Permalink - Table of contents

I don't see agent sessions without calls

It is possible that when running a custom report, selecting the agents name, the queue and the date and navigating to the "Agents" tab, QueueMetrics shows no information.
This happens because QueueMetrics considers an agent session without activity a logging anomaly as it is very unusual for an agent not to take at least one call throughout a shift.

However, QueueMetrics can be configured in order display these agent sessions where no calls were taken by the agent, by setting the following property to TRUE:


If true, shows all agent sessions. If false, shows only agent sessions with at least one call handled. (The property defaults to false).

Permalink - Table of contents

Backing up and restoring QueueMetrics

To make a backup of a working QueueMetrics system, you should backup the following items:

  • The QM database by typing:

    mysqldump -uqueuemetrics -pjavadude queuemetrics > database.sql

    File will be located at /root/database.sql

  • The web.xml and files being used (You canfind them under the QM webapp under WEB-INF; if you run a recent version ofQM, just look for the System path entry on the Licence page)

    Files will be located (e.g.) at /usr/local/queuemetrics/webapps/queuemetrics-

  • The queue_log data used for input (it is advisable to this in anycase, even if you use MySQL storage, just to be on the safe side).

    Files will be located: /var/log/asterisk


  • Create an appropriately named database on the target machine and make it accessible to user 'queuemetrics' password 'javadude'
  • Load the file using the mysql command:

    mysql -uqueuemetrics -pjavadude queuemetrics < database.sql

  • Restore web.xml, and under the WEB-INF directory of the new QM instance
  • Then open up GUI window where QueueMetrics is located (e.g. ) and run the DB updater wizard to repair.

Permalink - Table of contents

IE8 error: "The following error occurred in the Transaction handler: Il verbo '...' non e' stato trovato tra quelli caricati."

This basically means that the controller (the servlet /tpf ) received an empty HTTP request, so it does not know what to do with it.
To resolve the issue make sure that cookies are set to ON in IE8 Enhanced Security Mode.

Permalink - Table of contents

How do I remove duplicate rows from the queue_log table?

If more than one instance of qloaderd are running concurrently, this will lead to duplicate entries within the queue_log table. These entries must be removed by using the following procedure (requires MySQL 5):

1. Stop all qloaderd's - you should see no data being appended

2. Create a new table called queue_log_b that has the same definition as your current queue_log table:

CREATE TABLE `queue_log_b` (
`partition` varchar( 20 ) NOT NULL default '',
`time_id` int( 11 ) unsigned NOT NULL default '0',
`call_id` varchar( 30 ) NOT NULL default '',
`queue` varchar( 30 ) NOT NULL default '',
`agent` varchar( 30 ) NOT NULL default '',
`verb` varchar( 30 ) NOT NULL default '',
`data1` varchar( 200 ) NOT NULL default '',
`data2` varchar( 200 ) NOT NULL default '',
`data3` varchar( 200 ) NOT NULL default '',
`data4` varchar( 200 ) NOT NULL default '',
`data5` varchar( 200 ) NOT NULL default '',
`serverid` varchar( 10 ) NOT NULL default '',
`unique_row_count` int( 10 ) unsigned NOT NULL AUTO_INCREMENT ,
KEY `idx_sel` ( `partition` , `time_id` , `queue` ( 2 ) ) ,
KEY `partizione_b` ( `partition` , `time_id` , `unique_row_count` ) ,
KEY `by_hotdesk` ( `partition` ( 5 ) , `verb` ( 5 ) , `time_id` )

3. Copy all data from queue_log to queue_log_b

INSERT INTO queue_log_b
FROM queue_log

4. Delete the queue_log table


5. Copy all unique rows back to queue_log

INSERT INTO queue_log (
SELECT `partition`, `time_id`, `call_id`, `queue`, `agent`,
`verb`, `data1`, `data2`, `data3`, `data4`, `data5`,
`serverid`, MIN(`unique_row_count`)
FROM queue_log_b
GROUP BY `partition`, `time_id`, `call_id`, `queue`,
`agent`, `verb`, `data1`, `data2`, `data3`,
`data4`, `data5`, `serverid`
ORDER BY time_id, MIN(unique_row_count)

this may take a while.

6. Restart ONE instance of qloaderd.

7. Do not forget to CLEANUP the temporary table:

DROP table queue_log_b;

Permalink - Table of contents

Why do I get a message "The report exceeds the number of licensed agents"?

This error is displayed when QM senses that there are more than the maximum licensed number of agents in the dataset it is processing.

This may be caused by three reasons:
  1. You have more agents than your license is valid for (and in this case you should purchase an elargement), or
  2. You have less agents than your license is valid for, but agents appear under multiple distinct codes, or
  3. The report covers current and past agents, that in total are more than the licensed number of agents.
Cases #2 and #3 happen if you change your agent codes, or use new agent codes to supplement older ones. From the point of view of QM, each distinct agent code is a unique agent, so it is counted against the license limit.

You can easily check which one is your case by requesting an unlimited demo key and running the same report that displays the error; go to the "Agents on queue" report and count the number of distinct lines that appear there.

What you can do to mitigate this problem:
  • Purchase a larger license key
  • If you changed your agent numbering plan, avoid running reports that overlap both agent sets
  • Try and run reports that do not include more than the licensed agents
  • Edit the dataset manually to use the same code in case the same agent appeared under different codes (e.g. sometimes as Agent/101 other times as SIP/101).

Permalink - Table of contents

Can I move the license key when installing a new server?

QueueMetrics licenses are not tied to a specific server; so you can copy yor existing license from one server to another one. Of course you cannot have multiple copies of the same license active at the same time, even on the same server; this goes against the EULA and the licensing terms.

The license manager tries to avoid multiple instances of the same license being active at the same time; they maystop working, block each other and even invalidate the key. This is by design a random behavior, so it is hard to tell in advance what exactly will happen.

In case you need to install and test a different server, what we usually do is that we send you a demo key to do complete the installation; then you turn off the old server, copy the key to the new one and start it. It would be better to remove the key from the old server at all, so you do not risk to turn it on accidentally.

Permalink - Table of contents

Can I use logrotate for the queue_log file?

On a QueueMetrics system, it is often not necessary to rotate the queue_log file.

If you really need to rotate the queue_log file, you can do this provided that you are using SQL data storage and have qloaderd installed. The qloaderd process must be notified as soon as the file are rotated.

The following logrotate directive can be used:
/var/log/asterisk/queue_log {
  rotate 10
  create 0640 asterisk asterisk
    /etc/rc.d/init.d/qloaderd restart > /dev/null 2> /dev/null

This code will perform weekly rotations and will keep an archive of 10 weeks of data. We suggest in any case to keep a complete backup of all queue_log data that gets written, in order to allow for future analysis.

For further details about log file rotation, refer to the following link: log file rotation

Permalink - Table of contents

After installing the license key, QM does not even start!

You just installed a new QueueMetrics key that you were sent by Loway; after the installation, the whole QueueMetrics webapp seems to be unavailable and displaying an error like the following one:
HTTP Status 404 - /queuemetrics/
type: Status report
message: /queuemetrics/
description: The requested resource (/queuemetrics/) is not available.
Apache Tomcat/5.0.28

This is caused by an invalid or corrupted web.xml file; it prevents the whole webapp from being loaded by the Tomcat container and therefore the webapp is reported as being unavailable.

When you edit the web.xml file, you should make sure that it remains a valid XML document; in order to spot any mistakes, you can check the validity by issuing the following command after every upgrade:
xmllint web.xml
If everything goes well, it should return no errors.

(In case you do not find it on your server, you can install it easily by issuing the command yum install libxml2-devel on Red-Hat basedLinux distributions).

If that don't work try deleting the following file/usr/local/queuemetrics/tomcat/conf/Catalina/localhost/queuemetrics.xmland restarting the queuemetrics service.

Permalink - Table of contents

Why agents that do not logon are not a good idea

Many call-centers prefer to have agents always logged on, that is, the queue always rings the same set of phones 24/7. This is apparently easier to set up, as agents do not have to log on when they start working and off when they stop.

We advise against this method of managing agents, because:
  • Even if your phones are members of the queue 24/7, it is possible that some of them occasionally go unmanned. As Asterisk has no way of knowing which phones are to be used and which are not, it will simply try and ring them in sequence; if nobody answers, it will try a different one. This raises the wait-time for the callers without giving you any benefit. You may also have callers struck for long periods on queues where nobody answers, because there is nobody to answer but Asterisk is not aware of this!
  • As you have extensions and not people as end-points for your queue, it is very hard to tell who did what, whose performance was good and who answered the phone versus those who did a poor job. They all end up in the same statistics. By having people log on, it is easy to distinguish who did what. It is also easy to tell who is available at a given moment, even remotely.
  • As a result of both bullets above, agents know they are reponsible for what they do and know their behavior is monitored; so they have all the right incentives to do their best.
  • Agents that do not logon at every shift do not appear reliably on the RealTime monitoring in QM - see below.
If you still do not want to use agent logons, QueueMetrics will nevertheless monitor reliably your traffic; the Agents page and statitics that depend on agent sessions will be blank or may yeld meaningless results.

See also:

Permalink - Table of contents

What is the time period considered for real-time?

When QueueMetrics has to compute the Real-Time report, it tries to build the current situation based on what happened recently - normally since the last midnight. This usually works fine in the common case where all agents stop working at night and start working by logging on in the morning. On the other side, this produces incorrect results if your call-center works over the 24 hours, because at midnight by default all agents appear to be logged off.

This choice was made in order to minimize database searching for QueueMetrics, and it works just fine in the majority of call centers. There are a few cases where this choice may have to be changed:
  • If your call center stops daily, but not at midnight, you should tell QM the time when you expect all agents to be logged off. If e.g. at 4 AM you are sure all agents are logged off, you should set:

  • If your call-center never stops, but agents work in shift of 6 hours, you should use a "sliding window" instead; this determines the maximum lookback based on a number of hours before now (make it 1.5x to 2x the length of the shift).
    realtime.startHour=s8 Of course, the larger the sliding window, the more data QM has to evaluate every time it produces a realtime report, so it will use more RAM and CPU.
  • If your agents are always logged on, you should ignore the statuses as reported by QM, as QM has no way to reliably know if they are available or not. QM will generally log them on as they take calls within the given time window. See below for a detailed explanation of why it is not a good idea to have permanent agents.
See also:

Permalink - Table of contents

Why aren't all reports showing up in my copy of QM?

If you updtate to a new version of QueueMetrics that includes new reports, or have new reports custom-developed for you and update your system, you will notice that they will NOT appear after upgrading QM with the old database. This is because the definitions for your existing reports do not include the new blocks that were just created.

In order to add the new blocks, do the following:
  • With an admin user, select Edit QueueMetrics settings -> Edit reports
  • Click on a report, e.g. "All Reports"
  • Choose a screen to ad dyour new report to
  • When the list of times for the screen is visible, click on "Create new"
On the "add record page" enter:
  • A title and (optionally) a subtitle for the new report
  • From "Data Blocks", select the new report block - you should have been given a short code like e.g. UN18 so it is easy to select in from the drop-down box
  • Decide whether the new report should be visible in the "All reports" page
After saving, if you try running the report and select the chosen page, the new block will appear.

Permalink - Table of contents

Error: Out of memory error - Tuning Java Memory

This error can manifest itself in a multitude of ways, the most common being an error stating:
Servlet.service() for servlet LowayTransactionController threw exception java.lang.OutOfMemoryError

The problem with Java memory is that it is fixed, i.e. Java will not automatically use free memory unless explicityly told to do so. The default maximum memory size for most JVMs is 64 megabytes maxiumum, and it is not much if multiple users are running multi-megabyte analyses in QueueMetrics.

To tell Tomcat to use more memory than the standard pool, you have to set an environment variable before starting it up:
JAVA_OPTS="-Xms256M -Xmx512M"
export JAVA_OPTS

This tells Java to start by using 256 megabytes and expand the memory pool as needed up to 512 megabytes. Please note that Java will not return memory back to the system memory pool, so the only way to reclaim memory is by restarting Tomcat (you could restart it nightly with a script). You should also set this in the /etc/init.d/queuemetrics startup file, so that it's set system-wide when QueueMetrics starts.

A real-life example for a larger call-center using Sun JDK 1.6 may be the following set:
JAVA_OPTS="-server -Xms3072M -Xmx3072M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing"
export JAVA_OPTS

In any case, if you experience this problem, you should be reading the "Tuning QueueMetrics memory settings" section of QueueMetrics Advanced Configuration manual, that details how to tune and - most important - monitor a running JVM instance.

See for more information on Java memory setting and monitoring.

See also:
  • If the error you get is actually "OutOfMemory: Unable to create new native thread", see this FAQ entry.
  • If the error you get is actually "java.lang.OutOfMemoryError: PermGen space", then you have to set the maximum PermGen size as detailed in the Advanced Configuration manual.

Permalink - Table of contents

Detecting realtime timing issues

If you run MySQL storage, it is easy to check whether the time zone on the Asterisk server is correct:
  • Go to Home -> Edit QueueMetrics settings -> Mysql storage information
  • Look at the partition that contains your Asterisk data
  • Look at the "To" and "Last heartbeat" values; write them down somewhere
  • Send a call to the any queue on the system and look at your watch
  • Go again to Home -> Edit QueueMetrics settings -> Mysql storage information so that the page is reloaded
  • You should see that the "To" and "last heartbeat" values have changed and show the time the call was placed, answered or closed (whetever happened last)
  • If the values have not changed, this means your qloaderd is not running. Try and restart it
  • If the values are off from what you looked up on your watch, this means that Asterisk is using a wrong time or - worse - a wrong time zone.
See also:

Permalink - Table of contents

Updating the Java SDK

If you want to update the Java SDK you use to run QueueMetrics, it is very easy to do it.

Download and install a new version of Java SDK (from SUN, it's better - do not use GCJ).

You can install it anywhere on your system - like imagine you install it as/opt/java/jdk1.6.0b7.

As QueueMetrics accesses its own Java SDK under a symbolic link placed at /usr/local/queuemetrics/java, it is trivial to change that to use a different SDK.
cd /usr/local/queuemetrics
rm -f java
ln -s /opt/java/jdk1.6.0b7 java

then restart QueueMetrics.

To check that the new Java is working, go to the License page and check the Java version that it is using.

Permalink - Table of contents

Why do I get wrong agent names displayed?

In order for QM to work correctly, you should not have an agent name associated with an agent at the Asterisk level; in any case, that name should not contain spaces.

If in Asterisk you have a configuration like:
myvoip*CLI> agent show
123 (John Doe) available at '1234@from-internal' (musiconhold is 'default')

You should remove the agent name from agents.conf or from the realtime table where it is defined; you should make sure that the logging happens as Agent/123 for calls; the in QM you can configure a mnemonic name for the agent so that it apperas in the reports.

Permalink - Table of contents

Updating QueueMetrics and keeping the key and configuration

When updating QueueMetrics, whether you do that manually or using yum, you need to copy web.xml and from the old installetion to the new one.

This is easy to do, as distinct QM applications are stored as:

So they are never deleted.

Before the upgrade, make a backup of the QM database; it may be updated by the QM updater on the first run, so it is better to have a copy - just in case.
After the upgrade, have a look at the WEB-INF/README/Updating.txt file - it shows the new parameters and the new security keys that you m,ay have to enable on an existing install in order to unlock the new functionalities.

See also:

Permalink - Table of contents

Using UTF-8 encoding

QueueMetrics is a fully internationalized application: that is, it handles all user transaction with UTF-8 encodig, and therefore can display and accept any character for any language.

Unfortunately, MySQL does not natively use UTF-8 encoding for its tables and will try to use the "current encoding" whenever possible. So you may notice that if you e.g. enter an agent's name using not-Latin characters, when you read it back from disk it appears all garbled or a series of ??? signs.

To make QM fully able to process UTF-8 strings, you should follow the steps detailed here:

1. Run the following commands on all tables of the database but the queue_log table:

If your system has other tables, please do the conversion on ALL tables.

2. Open the QueueMetrics web.xml and modify the connection string adding, before the </param-value> tag, the string:
After this modification you should have something that looks like:
<param-value>jdbc:mysql:// &amp;jdbcCompliantTruncation=false&amp;user=queuemetrics&amp;password=javadude &amp;useUnicode=true&amp;characterEncoding=utf8&amp;characterSetResults=utf8</param-value>

It must all be written on a single line.

3. Then download the latest MySQL java connector binary package you can find at the link:
Extract the mysql-connector-java-5.1.7-bin.jar file and copy it on your QueueMetrics box, placing in the folder /usr/share/java.
Replace the symbolic link you can find in /usr/local/queuemetrics/webapps/queuemetrics-1.x.x/WEB-INF/lib in order to have it pointing to new connector.

4. Restart the QueueMetrics service issuing a /etc/init.d/queuemetrics restart

This will enable UTF8 support.

Permalink - Table of contents

Mixed-up pages after an upgrade

After an upgrade, you notice that pages are "mixed up" - that is, not all pages show the new version on their title bar. This may lead to many different errors and malfunctions.

This may be caused by two things:
  • You have the page in the clients cache. Clean up the browser cache and retry.
  • The Tomcat system caches are not updated. Do this to clean them up:

/etc/init.d/queuemetrics stop
rm -rf /usr/local/queuemetrics/tomcat/work/Catalina/*
/etc/init.d/queuemetrics start

This should fix all issues.

Permalink - Table of contents

Removing Tomcat logging

QueueMetrics keeps a detailed log of all transactions performed, in order to be able to find which transactions are slow and for forensic analysis (you can never know...). They may end up taking substantial disk space.

First, you may want to rotate Tomcat logs using a logrotate job like the following one:
/usr/local/queuemetrics/tomcat/logs/*.* {
  rotate 5
  create 0640 root root
      /etc/init.d/queuemetrics restart > /dev/null 2> /dev/null

If you want to turn off logging entirely, edit the server.xml file and remove sections:
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="catalina_log." suffix=".txt"

<Logger className="org.apache.catalina.logger.FileLogger"
directory="logs" prefix="localhost_log." suffix=".txt"

Then edit and remove all logging to
"$CATALINA_BASE"/logs/catalina.out 2>&1
by entering:
/dev/null 2>&1
For more information on Tomcat logging, see

Thanks to PSN for input!

Permalink - Table of contents

Repairing a MySQL database

It sometimes happens that if your database server crashes, you may find that:
  • QM is not working because it cannot access the database
  • Qloaderd is not working because it cannot write to the queue_log table
  • You get weird errors when updating from an older version of QM
This sometimes happens even on systems that seemed to work fine for a long time.

In order to fix these issues, you should:
    /etc/init.d/mysqld stop
  2. check tables using myisamchk (use the same case as written here):
    myisamchk -c /var/lib/mysql/queuemetrics/*.MYI
  3. if any error is shown, repair tables:
    myisamchk -r /var/lib/mysql/queuemetrics/*.MYI
  4. after that, restart Mysql:
    /etc/init.d/mysqld start

Permalink - Table of contents

AMI connection not working in Asterisk 1.6

In order to perform a set of actions in Asterisk (eg. getting Live statistics, starting channel monitoring, logging agents on and off, setting call statuses) QueueMetrics needs to connect to Asterisk over the AMI interface.

In Asterisk 1.6 (AMI 1.1), in order to set up its calls, you have to make sure that the account that QM uses has ORIGINATE privileges as well as WRITE.

Permalink - Table of contents

Figures do not match when running hourly versus daily reports

Imagine you run a report for Aug 25th, queue A, between 7 and 8 - it says there are 150 answered calls.
You run it again, between 7 and 13 and look at the hourly statistics - now it says there are 154 answered calls between 7 and 8.
What happened? that's simple - between 7 and 8, some calls were queued but not yet answered - so you are going to find them, but on the "Lost" page and with status "Ongoing".
You run the report again between 7 and 9, and now you see that the call was answered - because it was answered after 8 am.

If you run a report between 7 and 8, QM only sees data that cam between 7 and 8 - not what happened before of afterwards. It's like being at 8am and asking for future data. If you want to see what happened when you have a full day of data, run a report for a full day and look at the hourly breakdowns.

Permalink - Table of contents

Help! QueueMetrics reports shows no data at all!

If you have activity in Asterisk but your QueueMetrics reports show no data at all - no calls processed, no agent sessions, you should check the following possible causes:
  • The qloaderd is not working
    If you have set up QueueMetrics to use the SQL storage model, you need to make sure that the loader process on the Asterisk box is actually sending data to the QueueMetrics database. This can be easily checked by looking at the Licence page (where the storage model will be displayed) and if it is correct, by clicking on the Mysql storage information where you will see a growing number of lines in the selected partition if there is Asterisk activity and the loader is actually working.
  • You are reporting from the wrong partition
    Check on the licence page for the storage model and the partition being currently in use. If the partition code is different, no data will be found.
  • You are asking for the wrong queue
    The queue identifier that appears in QueueMetrics must match exactly, letter by letter, the one that appears as the queue name in Asterisk. If this is not so, the queue will not be displayed.

Permalink - Table of contents

Why do I see duplicate calls in the reports with a Caller-ID set to '*'?

If you see all (or many) calls in the Processed Calls or the Lost Calls reports as being present twice with the same start hour, the first time having a correct Caller-ID and the second time displaying '*' in the Caller-ID field, this means that you have duplicate data in your database.

This is usually caused by having mutiple instances of the qloaderd running at the same time - maybe you run them manually, or one instance was not stopped correctly during a restart. Stop them all manually and restart just one.

In order to "clean up" the database, use the queuePartialUpdater tool that ships with the qloaderd - it will basically unload a queue_log file and will reload it.

Permalink - Table of contents

Exception: java.nio.BufferOverflowException - Encoding problems when reading files

If QueueMetrics crashes with an exception like:
[ERR] -- Inner Exception --
Exception: java.nio.BufferOverflowException
Stack trace:
at java.nio.charset.CoderResult.throwException(
at java.lang.StringCoding$CharsetSE.encode(
at java.lang.StringCoding.encode(
at java.lang.String.getBytes(
at Method)

this means that it is trying to read a file using the current Locale that is set for your server but this is not correct for QueueMetrics. You can check what is the encoding of the file names in your local server by typing "locale".

You can anyway force it to UTF-8 by changing JAVA_OPTS in the file /etc/init.d/queuemetrics:
JAVA_OPTS="-Xms512M -Xmx512M -Dfile.encoding=UTF-8"
Or, if it still does not work:
JAVA_OPTS="-Xms512M -Xmx512M -Dfile.encoding=ISO-8859-1"
Make sure that you kill the current Java process and restart it before logging on again in QM.

This error might also be triggered when reading a directory that has too many files, e.g. the place where you store audio recordings. You can override this behaviour by using the LocalFilesByDay storage model - it will also be way faster when retrieving recordings. See e.g.: and

Permalink - Table of contents

Help! The Real-time page is showing no data!

If the Real-time page will show no data at all - no agents logged on, no calls being processe, you should check the following items:
  • Make sure that reports are showing data
    If they show no data, see this FAQ entry.
  • The time on the Asterisk server is far off from the time on the QM server
    In order for the real-time page to work correctly, the clocks on the Asterisk server, the one on the QM server and the one on the MySQL server must be aligned with a sub-second difference. If this is not so, QM has no way of knowing which calls are in transit and which are terminated.
    In order to check this, there is a label on the Licence page that will show if there are differences between QM and its MySQL server. To assess timing differences from the Asterisk box, try and process a call and then run a report where that call appears and check if the time is correct.

    Luckily, it is trivial to keep the clocks aligned - see this FAQ entry.
See also:

Permalink - Table of contents

Installing QueueMetrics on a Debian or Ubuntu server

While on RedHat-derived systems a fully automated install using yum is available, on Debian the installation must be performed manually when running as root.

First, we make available the repository for Java:
# nano /etc/apt/sources.list
Add the following lines:
deb etch main contrib non-free
deb-src etch main contrib non-free

Now let's install Java:
# apt-get install sun-java5-jdk
Then set:
# update-alternatives --config java
# update-alternatives --config javac
# export JAVA_HOME="/usr/lib/jvm/java-1.5.0-sun"

When you run:
# java -version
It should answer:
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_10-b03)
Java HotSpot(TM) Client VM (build 1.5.0_10-b03, mixed mode, sharing)

Now let's install Tomcat:
# apt-get install tomcat5.5 tomcat5.5-admin tomcat5.5-webapps
We will now turn off Java Security (see this FAQ entry if you need to keep it turned on, but it's easier if you turn it off now).
# nano /etc/init.d/tomcat5.5
Change the line TOMCAT5_SECURITY=yes to no.

Now let's prepare the database:
# mysql --user root -p
Enter the root password, and now the following commands to create a database:
Mysql> CREATE DATABASE queuemetrics;
Mysql> GRANT ALL PRIVILEGES ON queuemetrics.* TO 'queuemetrics'@'localhost' IDENTIFIED BY 'javadude';
Mysql> quit

Now let's download and install QueueMetrics:
# cd /var/lib/tomcat5.5/webapps
# wget
# tar -xvzf QueueMetrics-1.5.4-trial.tar.gz
# mv queuemetrics-1.5.4 queuemetrics

Let's import the sample database:
# cd /var/lib/tomcat5.5/webapps/queuemetrics/WEB-INF/README/
# mysql --user=queuemetrics --password=javadude queuemetrics < queuemetrics_sample.sql

Now we download and install the MySQL connector:
# cd /var/lib/tomcat5.5/webapps/queuemetrics/WEB-INF/lib/
# wget
# tar -xvzf mysql-connector-java-5.0.0.tar.gz
# cp mysql-connector-java-5.0.5/mysql-connector-java-5.0.5-bin.jar /var/lib/tomcat5.5/webapps/queuemetrics/WEB-INF/lib/

Start Tomcat and set your browser to http://myserver:8080/queuemetrics to access QM.

Permalink - Table of contents

How do I modify or turn off the sounds on the Real-time page?

The default Real-time page that ships with QueueMetrics will play sounds when yellow or red alarms are triggered. The sounds played, or whether to play any, are controlled by a couple of system properties in the file:

If you want to turn them off completely, just set them to blank.

Of course, alarm thresholds are user configurable from the Queue editor page.

Permalink - Table of contents

How do I secure access from a given subnet only?

Very often, you will want to make sure that the QueueMetrics application is accessible only from a given subnet. Even if QueueMetrics has its own security mechanism built-in, denying access to all clients that have no right to access QM will surely improve security.

In order to do so, you just edit the file: /usr/local/queuemetrics/tomcat/conf/Catalina/localhost/queuemetrics.xml so that it looks like the following one.

<Context docBase="/usr/local/queuemetrics/webapps/queuemetrics-1.5.1"

<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow=""/>

You could use the following format for the address instead of
  • allow=",," to specify multiple IP addresses, or
  • allow="128.117.140.*" to specify a full class.
If all goes well, when you restart QueueMetrics and try to access it from a forbidden IP address, you get the message "Access to the specified resource has been forbidden."

Please note that the queuemetrics.xml file is rebuilt upon automatic update, so you will have to edit it after running "yum update".

Permalink - Table of contents

How to upload an older queue_log file

Imagine you have a queue_log file that uploads to partition P003, and is missing from timestamp 100 to 150; and imagine that old data is available in a file called queue_log.old
  1. Make sure there is no data in the table for partition P003 between timestamps 100 and 150.
    e.g SELECT * FROM queue_log WHERE partition='P003' AND time_id BETWEEN 100 and 150
  2. Stop importing on partition P003
  3. Move queue_log data newer than timestamp 150 to a new partition (eg P003B)
    e.g. UPDATE queue_log SET partition = 'P003B' WHERE partition='P003' AND time_id > 150
  4. Run the qloaderd on your queue_log.old file, so that it will load all data.
    You will have to watch its log file to se when it ends adding lines.
  5. Check that all data has been loaded
    e.g. SELECT count(*) FROM queue_log WHERE partition='P003' AND time_id BETWEEN 100 and 150
  6. Stop the qloader process
  7. Move back newer data from P003B to P003
    e.g UPDATE queue_log SET partition='P003' WHERE partition='P003B'
  8. Point qloaderd to your normal queue_log file, and restart normal importing
After you are done, try running a report to see if old data is actually seen by QueueMetrics.

Permalink - Table of contents

Tracking timing and time-zone problems in QueueMetrics

It sometimes happens that a new QueueMetrics install has time-zone problems on a specified box. Generally speaking, the local time for the QueueMetrics instance should be the same as your own local time, and so should be for the MySQL server and the Asterisk server it relies on.

Small timing discrepancies can cause many problems, like calls not shown, wrong call duration and wait times on the realtime page, or even calls not showing at all on the realtime page.

Generally speaking, the first thing you should do if you suspect a timing problem is run a command that will sync the system clock with an high-precision atomic clock on all involved machines, for example:

As harware clocks tend to "drift" in the long period, it is a good idea to add this command to a nightly cron job that will keep the clocks of all involved systems below a one-second difference.

If you want to see the current clock and time zone for the QueueMetrics server and its MySQL instance, just click on the Licence page and those values will be shown. It's important that there is no difference between those values.

If one of the clocks is very different from the current time, it is usually a time zone problem on your box. This can usually be solved/detected running the following commands:
[root@asterisk1 ~]# hwclock --show
[root@asterisk1 ~]# date -R
[root@asterisk1 ~]# date
[root@asterisk1 ~]# more /etc/sysconfig/clock

If everything seems correct and still the QueueMetrics server will insist on using the wrong time zone, you should try the following options:
  • Set the TZ environment variable, like export TZ="US/Eastern" in the startup script you use for the QueueMetrics server
  • Add the following option to the JAVA_OPTS environment variable: -Duser.timezone=US/Eastern in the startup script you use for the QueueMetrics server.

    For example, if you live in a place that is GMT+5, you could change the /etc/init.d/queuemetrics init script so that it has an options line like:

    export JAVA_OPTS="-Xms128M -Xmx128M -server -Duser.timezone=GMT+05:00"

    After saving and restarting QM, if you go to the Realtime page, you should see that the time is now correct.
See also:

Permalink - Table of contents

Transfers from the queue are not reported in QM

If your agents on a queue use to transfer calls out to other callers or to other queues, you may notice that this is not reported correctly by QueueMetrics. You may also notice that if you use agent channels, an agent stays idle after the transfer until the transferred call is over.

Unfortunately this is "by design"; this is because when you use the Attended transfer button on the agent's phone, the main PBX is not notified that the call is "handed-over", so it still thinks it's connected to the original agent. The official documentation says that "transfers performed by SIP UA's by way of a reinvite may not always be caught by Asterisk [...] The only way to be 100% sure that you will get this event when a transfer is performed by a queue member is to use the built-in transfer functionality of Asterisk".

So the only way there is to handle this case is then to use so-called "Unattended transfer", that is, setting the t option in the queue and then having your agent press # to start a transfer to a different extension. Unfortunately, this does not give you Attended transfer, that is, speaking to the receiver before handing over the call.

Our real-life workaround is to use the "#" unattended transfers of Asterisk to transfer calls only after having opened up a parallel conversation to negotiate with the receiver. We know it's sub-optimal, but this has been shown to work.

Permalink - Table of contents

Using multi-stint mode in reports

When QueueMetrics run an activity report, its basic "unit of measurement" is the queue; that is the activity that your call made on a specific queue. This may lead to a situation that is harder to understand if you have spill-over queues in place, that is, if a call is not handled in one queue it is moved to a different one.

In order to address this problem, queueMetrics implements a multi-stint analysis mode, where mutiple passages on different queues are "joined together", like in the following example. Imagine this call:
h 10.00.00 enters queue 1
h 10.00.59 exits queue 1
h 10.01.00 enters queue 2
h 10.01.59 exits queue 2
h 10.02.00 enters queue 3
h 10.02.30 answered on queue 3
h 10.03.00 caller hangs up

With single stint mode you would see:
h 10.00.00 lost call on "queue 1", waited for 59 seconds
h 10.01.00 lost call on "queue 2", waited for 59 seconds
h 10.02.00 answered call on "queue 3", waited for 30 seconds, duration 30 seconds

With multi-stint mode you would see:
h 10.00.00 call enters on queue 3, waits for 2:30, duration 30 seconds
and by clicking on the call detail, you get the whole history.

In order to have multi-stint work correctly, you should include ALL the queues that the call was handled upon in the same report - otherwise it will not find out where the call passed.

Of course, in real-life you can run both multi-stint and single-stint analyses when querying the performance of your call-center; you use multi-stint to see the performance from the point of view of the caller, and single-stint to see what happended from the point of view of the providers, e.g. service groups.

Permalink - Table of contents

How to let Agents access the Realtime page

It is possible to let your QueueMetrics agents access the full RealTime page and not just the Agent's page:
  1. Create a new class for agents. You may call it RTAGENTS (Realtime Agents)
  2. Give your agents the following keys: USER AGENT CHPASSWD REALTIME. For the exact meaning of each key, see Appendix II of the User Manual.
  3. Create (or select) some agents and assign them to class RTAGENTS.
Those users will be able to login, access the realtime page, access the agent's page and change password.
If you want your agents to be able to see only a subset of all possible queues through the Realtime page, you should see also:How do I make some queues visible by some users only?.

Please consider that running the realtime page instead of the Agent's page is extremely expensive, computationally speaking, so run a few test before deploying this in a 1000-agent setting.

Permalink - Table of contents

XML-RPC not working: Could not instantiate XMLReader parser

If the XML-RPC interface of QueueMetrics is not working, i.e you get no meaningful response, you have to look up on the catalina.out file in order to detect possible problems.

Xerces not installed

With Java 1.5 and Tomcat 5.5, you may encounter the problem as an error string stating redstone.xmlrpc.XmlRpcException: Could not instantiate XMLReader parser. This means the Xerces XML parser cannot be found.

If this happens, download Xerces from and put the file called xercesImpl.jar in your queuemetrics/WEB-INF/lib. This should solve your problems.

Permalink - Table of contents

Missing records on KeyPress

Sometimes calls in Qm seem to go on forever... even if they have been terminated. This is often the case when your users exit the key by pressing a numeric key; some versions of Asterisk don't log this event correctly, so the call appears to be going on and on.

In order to check if this is the case, you should monitor your queue_log file when you exit a call by pressing a key; you should expect a line that looks like:
If such a line is not present, you may detect the event via the ${QUEUESTATUS} variable when the queue() app terminates, and produce a record like the following one:
exten => s,1,System( echo"${EPOCH}|${UNIQUEID}|myqueue|NONE|EXITWITHKEY|key|1|" >>/var/log/asterisk/queue_log )
Where "myqueue" is the queue name and "key" is the key pressed (if you need to track it, otherwise set it to 1).

See also Handling ghost calls.

Permalink - Table of contents

Handling 'Ghost Calls'

Sometimes calls in Qm seem to go on forever... even if they have been terminated. This may be caused by two reasons:
  1. In some versions of Asterisk, some ways of exiting a queue trace no log
    Mostly on older (1.0 and 1.2) versions of Asterisk, sometimes you discover that exiting a queue in a certain manner (eg a timeout, a transfer) consistently provides no end-of-call log. This makes it impossible for QM to know that the call is over.
  2. Asterisk sometimes randomly "forgets" to trace some end of call.
    This is a problem that happens on most large systems. If this is below 1% of all calls, it should be considered normal. Some installations are almost completely unaffected while others are heavily affected.
While case #1 can be fixed adding some dialplan logic to test the exit status and output a call closure log, case #2 still lingers.

QM handles this problem in two ways:
  • The realtime page can be instructed about "anomalous" calls that will not be displayed if the wait or talk times are too long. This is what default.maxOngoingWaitTime and default.maxOngoingTalkTime are for (as the definition of "too long" varies from call center to call center).
  • Since QM 1.4.5 and when running with a MySQL database, it is possible for certain administrative users to "close" ongoing ghost calls by finding them on the real-time or the historical call list (requires security key CLOSECALLS)
See also Missing records on KeyPress.

Permalink - Table of contents

How do I run QueueMetrics with Java Security?

Java Security is a way to fine-tune the grants that a web-application has. This can be quite complex if you do not exactly know what a webapp is doing internally. You can set this by updating a policy file and running Tomcat in secure mode.
To make sure you are running under Java Security, you can check the value of the property under the Licence page - if it is set to something like =/usr/local/queuemetrics/tomcat/conf/catalina.policy, then security is enabled.

The following permissions apply to QM 1.4.5 - just add them to your catalina.policy file:
grant codeBase "file:/usr/local/queuemetrics/tomcat/webapps/queuemetrics/-" {
permission "localhost:3306", "connect,resolve";
permission "/var/log/asterisk/queue_log", "read";
permission java.util.PropertyPermission "*", "read,write";
permission java.lang.RuntimePermission "createClassLoader";
permission "${}/-", "read,write,delete";

// if you use LIVE connection to Asterisk instances:
permission "", "connect,resolve";

Of course you have edit them to:
  • set the correct path for your QM webapp in the grant codeBase line
  • set the correct path to your database
  • set the cortrect path to the manager port of your Asterisk server
  • if you use external XML-RPC services, you should add "connect, resolve" grants for those as well.

Permalink - Table of contents

Configuring ViciDial for QueueMetrics

ViciDial, a widely-used outbound dialer and campaign manager, can be configured to write its call activity logs directly to the QueueMetrics call database.

In ViciDial, this can be enabled as follows (Go to "System Settings"):
  • Enable QueueMetrics logging: 1
  • QueueMetrics server IP / DB name / DB login / DB password: These values are for the MySQL server that holds the QM database
  • QueueMetrics URL: enter a fully qualified URL of your QM system, e.g. http://qmserver:8080/queuemetrics
  • QueueMetrics LogID: this is the name of the QM partition ViciDial will write to. E.g. P001, or VIC.
  • QueueMetrics EnterQueue Prepend: you can use this switch to prepend the campaign-id to the caller-id so you can run a breakndown using QM's are analysis. In most cases just leave that to NONE.
This should be it. Now create the campaigns in QM and make sure you're using the chosen LogID as the partition (e.g. if your log-id is VIC, you should enter sql:VIC as the file name).

Permalink - Table of contents

Backing-up a QueueMetrics system

To make a backup of a working QueueMetrics system, you should backup the following items:
  • The QM database
  • The web.xml and files being used (You can find them under the QM webapp under WEB-INF; if you run a recent version of QM, just look for the System path entry on the Licence page)
  • The queue_log data used for input (it is advisable to this in any case, even if you use MySQL storage, just to be on the safe side).
Nothing else is needed.

See also:

Permalink - Table of contents

How do I make some queues visible by some users only?

In order to make sure that some users (e.g. supervisors) can only see their queues, you should use QM's security model. When you protect something with a key, this means that you protect it (physically speaking) with a lock that opens if the user holds that key in his keyring. You know that eash user has a keyring, that is the sum of the keys that belong to his current class plus the keys that he individually has.

So, if you have a number of supervisors and a number of queues, you could protect each queue individually with a different key, and then give each supervisor individually the required key.

For example, you can do this:
  • queueA -> key KA
  • queueB -> key KB
  • queueC -> no key
  • queueD -> key KD
  • queueE -> key KE

  • supervisor Alice -> keys KA and KD
  • supervisor Bob -> keys KB and KE
When they log on, Alice sees queue A, queue C and queue D. Bob instead will see queue B, queue C and queue E.

Please note that if you have an aggregate queue, only the key protecting the aggregate queue will be ckecked, i.e. the checks on the members will NOT be performed (so you can have an aggregate queue that behaves differently in security terms from the set of its members, if you need it).

Permalink - Table of contents

How is the field "N.Agents" computed?

The first cell of the top realtime panel ("N Agents") is computed as follows:
  • for each queue, QM looks for all agents that are KNOWN MEMBERS of that queue (that is, they have an association through QM's editor) plus all agents that are logged on dynamically to that queue
  • for the grand total (first line) QM looks for all agents that appear in the report - they should match the number of lines of the lowest table
Therefore it is very well possible that the first number does not match the following ones, because on one side an agent can be a known member of more than one queue, and on the other side an agent may not be a known member on any queue (in this case, it will be counted on the grand total but not on a queue-per-queue basis).

Permalink - Table of contents

Error: "You do not have the rights to perform the requested action."

While working on the "Agent's page" and trying to log-on, log-off or pause an agent, the following error is displayed in the pop-up window after entering the Agent's code and Extension: "You do not have the rights to perform the requested action."

This means that QM is trying to connect to Asterisk to run that action, but Asterisk refuses the connection. In order to make it work, the following steps should be hand-checked:
  1. Are the connect credentials correct?
    The credentials supplied in the file should look like:
    Check that they match the ones in Asterisk's own /etc/asterisk/manager.conf

  2. Is the dialplan context [queuemetrics] included?
    You can check that by typing the following command in Asterisk:
    asterisk*CLI> show dialplan queuemetrics
    [ Context 'queuemetrics' created by 'pbx_config' ]

    '10' => 1. Answer() [pbx_config]
    2. Wait(10) [pbx_config]

    ..and a lot more stuff here....

    If it's not included, you can find the example file extensions_queuemetrics.conf under QueueMetrics' own README directory - just copy that to /etc/asterisk and #include it in the main dialplan (note: you should review that file before inclusion as it should be customized to fit your environment).

  3. Are you seeing connection attempts?
    If you open the Asterisk CLI, you should see a message when QM connects and disconnects. If you see nothing, there is some setup error (e.g. a firewall) that prevents QM to connect to Asterisk.

Permalink - Table of contents

Using a different Asterisk manager port

It is possible to switch the port QueueMetrics uses to connect to the Asterisk manager interface fom the default port 5038 to any other port - use something like:
This will set the Manager to port 1234 on server

Permalink - Table of contents

Using fully dynamic members with QM 1.4 and Asterisk 1.2

If you run QueueMetrics 1.4.1 or newer, you can fully use the new ADDMEMBER / REMOVEMEMBER to track agents logging on on a queue-by-queue basis. Unfortunately, Asterisk 1.2 does not automatically log them, so we must resort to something like the following example.

In this example, we assume that:
  • All agents are entered as Local/NUM@agents - feel free to use Local/XX@from-internal or whatever matches your system configuration
  • The example queue you join here is called my-queue
  • You will call the following pieces of dialplan:
    1. 422XX to log on Agent/XX to the queue my-queue
    2. 423XX to log off Agent/XX from the queue my-queue
    3. 416XX to pause Agent/XX (on all queues she's working on)
    4. 417XX to unpause Agent/XX
This is the relevant piece of dial plan:
; addqueuemember - 422
exten => _422XX,1,Answer
exten => _422XX,2,AddQueueMember(my-queue,Local/${EXTEN:3}@agents)
exten => _422XX,3,System( echo "${EPOCH}|${UNIQUEID}|my-queue|Agent/${EXTEN:3}|ADDMEMBER|-" >> /var/log/asterisk/queue_log )
exten => _422XX,4,DBput(dynlogin/log_Agent-${EXTEN:3}=${EPOCH})
exten => _422XX,5,Hangup

; removequeuemember - 423
exten => _423XX,1,Answer
exten => _423XX,2,RemoveQueueMember(my-queue,Local/${EXTEN:3}@agents)
exten => _423XX,3,DBget(ORGEPOCH=dynlogin/log_Agent-${EXTEN:3})
exten => _423XX,4,Set(RV=$[${EPOCH} - ${ORGEPOCH}])
exten => _423XX,5,GotoIf($["${RV}" = "0"]?8:6)
exten => _423XX,6,System( echo "${EPOCH}|${UNIQUEID}|my-queue|Agent/${EXTEN:3}|REMOVEMEMBER|-|${RV}" >> /var/log/asterisk/queue_log )
exten => _423XX,7,DBdel(dynlogin/log_Agent-${EXTEN:3})
exten => _423XX,8,Hangup

; agent pause
exten => _416XX,1,PauseQueueMember(|Agent/${EXTEN:3})
exten => _416XX,n,Hangup()

; agent unpause
exten => _417XX,1,UnpauseQueueMember(|Agent/${EXTEN:3})
exten => _417XX,n,Hangup()

Do not forget to also change the value:
in QueueMetrics' WEB-INF/ file.

Permalink - Table of contents

Using fully dynamic members with QM 1.4 and Asterisk 1.4

If you run QueueMetrics 1.4.1 or newer, you can fully use the new ADDMEMBER / REMOVEMEMBER to track agents logging on on a queue-by-queue basis. If you run Asterisk 1.4, most of the logging is already done correctly by Asterisk itself.

In this example, we assume that:
  • All agents are entered as Local/NUM@agents - feel free to use Local/XX@from-internal or whatever matches your system configuration
  • The example queue you join here is called my-queue
  • You will call the following pieces of dialplan:
    1. 422XX to log on Agent/XX to the queue my-queue
    2. 423XX to log off Agent/XX from the queue my-queue
    3. 416XX to pause Agent/XX (on all queues she's working on)
    4. 417XX to unpause Agent/XX
This is the relevant piece of dial plan:
; addqueuemember - 422
exten => _422XX,1,Answer
exten => _422XX,2,AddQueueMember(my-queue,Local/${EXTEN:3}@agents)
exten => _422XX,3,Hangup

; removequeuemember - 423
exten => _423XX,1,Answer
exten => _423XX,2,RemoveQueueMember(my-queue,Local/${EXTEN:3}@agents)
exten => _423XX,3,Hangup

; agent pause
exten => _416XX,1,PauseQueueMember(|Agent/${EXTEN:3})
exten => _416XX,n,Hangup()

; agent unpause
exten => _417XX,1,UnpauseQueueMember(|Agent/${EXTEN:3})
exten => _417XX,n,Hangup()

Do not forget to also change the value:
in QueueMetrics' WEB-INF/ file.

Permalink - Table of contents

Tracking agent extensions for outbound dialing

When you do outbound calling, it's easy to track the extension that is doing outbound calling. It would be nice to match the agent that is logged on to that extension.
To do this, we must store the current agent's estension in a global variable:
exten => 2000,1,Answer
exten => 2000,2,NoOp( "QM: Logging on Agent/${AGENTCODE} to extension ${AGENT_EXT}@from-internal" )
exten => 2000,3,AgentCallBackLogin(${AGENTCODE}||${AGENT_EXT}@from-internal)
exten => 2000,4,Set(AGENTE_${AGENT_EXT}=${AGENTCODE}|g)
exten => 2000,5,Hangup

When you need to dial out you do:
exten => _7.,1,Set(MY_QUE=300)
exten => _7.,n,Set(MY_NUM=${EXTEN:1})
exten => _7.,n,Set(MY_AGENT=${AGENTE_${CALLERID(num)}})
exten => _7.,n,NoOp,Ag: ${MY_AGENT} N: ${MY_NUM} Q: ${MY_QUE}

This way it works easily.

Permalink - Table of contents

How to write internationalized data to the database

If you use an internationalized version of QueueMetrics for a language based on a non-Latin character set, you may find yourself unable to write strings in your own language (e.g. the name of a queue) into QueueMetrics. This is usually not caused by QueueMetrics itself (that is completely UTF-8 compliant) but by the underlying MySQL instance.

In order to make sure that your charset is accepted by your database:
  1. Make sure that MySQL is installed in/for your language.
  2. Run the following commands on all tables of the database but the queue_log table:
    ALTER TABLE `call_status` CHARACTER SET utf8;
    ALTER TABLE `pause_codes` CHARACTER SET utf8;

    This tells the database engine to accept UTF-8 on all storage tables.
  3. Modify the connection string in web.xml so that it ends with:
    This tells the MySQL connector to force UTF-8 encoding when talking to the datbase server.
In our experience this is usually all that is needed to run an Unicode datbase instance.

Permalink - Table of contents

How to use subqueues

If you work in an environment where a single queue is used to service a number of different calling clients, it might be of interest to you to enable subqueues; i.e. to have the queue name rewritten appending a client code at the end, so that you can query them from QueueMetrics as if each client was serviced by a dedicated queue.
You can also use this technique in order to have very few actual queues in your call center but you still want to differentiate callers based on their incoming DID, or the group they belong to.

To set up this feature you should:
  1. Be running qloaderd and being successful in using the MySQL storage in QueueMetrics
  2. Create the new table qlog_opencalls as described in the qloaderd documentation
  3. Enable subqueues changing the file and setting:
    my $use_subqueue = 1;
  4. when you call a queue, you pass the DID code in its URL parameter, e.g.
    exten => s,8,Queue(queue-service|t|1234||180)
  5. When qloaderd picks up the call, it will import it as queuename.code; in the example above, it would import the call as queue-service.1234.
Please note that you should mantain the qlog_opencalls table yourselves, deleting periodically rows with a 'lastUpd' timestamp over one day old and optimizing it as needed.

Permalink - Table of contents

Metadata file does not match checksum in Yum

When trying to install or update via Yum, you get an error like:
Reading repository metadata in from local files
primary.xml.gz 100% |=========================| 3.7 kB 00:00 [Errno -1] Metadata file does not match checksum
Trying other mirror.
Error: failure: repodata/primary.xml.gz from LowayResearch: [Errno 256] No more mirrors to try.

This might be caused by having corrupted metadata information, and it sometimes cannot be fixed even if you runyum clean all. If this is your case, try the following:
yum clean all
cd /var/cache/yum/LowayResearch/
wget --cache=off
wget --cache=off
wget --cache=off

And will then run the yum update queuemetrics command.

Permalink - Table of contents

Error: OutOfMemory: Unable to create new native thread

After running QueueMetrics for a while, the JVM stops with the exception "OutOfMemoryError: unable to create new native thread". This is usually caused by using the wrong JVM / Tomcat / Linux Kernel set, and is usually solved by:
  • Installing a newer (or older) JDK, or one that is designed right for your hardware
  • Installing a newer (or older) Tomcat version
QM will run just fine with any JDK >= 1.4.2 and Tomcat >= 4.0, so there is usually no great benefit in running the very latest version of them.

See also: Java thread tuning.

Permalink - Table of contents

Some pages won't compile and show JasperException

It sometimes happens that some pages of QueueMetrics cannot be opened; they crash during the JSP compilation stage with a "JasperException" showing that the page cannot be compiled.

This is often caused by having the wrong system-wide charset encoding, so that the source files cannot be read correctly from the disk.

To check if this is your case, you should go to the Licence Page, click on the [...] link to see all Java properties and check the value of file.encoding that should be ISO-8859-1. If it's anything else, it is a good idea to tell the Java subsystem to use this as a default encoding. To do this, you have to set an environment variable before starting Tomcat:
JAVA_OPTS="-Dfile.encoding=ISO-8859-1 -Xms256M -Xmx512M"
export JAVA_OPTS
This tells Java to start by using ISO-8859-1 as the default file encoding and use a minimum of 256 megabytes and expand the memory pool as needed up to 512 megabytes. You should also set this in the /etc/init.d/queuemetrics startup file, so that it's set system-wide when QueueMetrics starts.

See also FAQ: Out of memory error for more information on Java setup variables.

Permalink - Table of contents

Why do some calls disappear from the Realtime page?

You know that most call centers have a 80/20 rule (80% of the calls taken withing 20 seconds), so it is very abnormal for them to have calls answered after tens of minutes. In order to avoid showing calls that are actually logging anomalies, QueueMetrics considers calls that have been waiting too long or have conversation times too long on the realtime page as errors and does not show them anymore.

The basic wait duration is 1000 seconds, but if your call center shows such calls routinely, you can change this feature or turn it off altogether through the following settings:

#If an ongoing call has a wait time that exceeds this value, drop it. 0: ignore

#If an ongoing call has a talk time that exceeds this value, drop it. 0: ignore

Permalink - Table of contents

Tracking hourly call distribution for multiple incoming DIDs

If you have multiple incoming DIDs pointing to the same queue, and you would like to track the hourly distribution of calls on each DID for planning, there is a simple thing you can do. You create a "virtual queue" for each DID, then when a call comes in into that DID, and before passing it to the actual queue that's servicing it, you write two log lines as if it was a lost call. Then you can define each "virtual queue" in QueueMetrics and run reports on it like you currently do; you will find all calls as "lost" but you do get call count, incoming caller id and hourly/daily/weekly call distribution.

In practice what you do is modify the dialplan so that:
exten => s,n, .....
exten => s,n,Macro(qm-lostcall,did-11,${CALLERID(name)})
exten => s,n,Queue(service-q,,30)
exten => s,n, .....

; ${ARG1} - the name for the fake queue
; ${ARG2} - the caller id to be logged
exten => s,1,System( echo "${EPOCH}|${UNIQUEID}.1|${ARG1}|NONE|ENTERQUEUE||${ARG2}" >> /var/log/asterisk/queue_log )
exten => s,2,System( echo "${EPOCH}|${UNIQUEID}.1|${ARG1}|NONE|ABANDON|0|0|0" >> /var/log/asterisk/queue_log )

Now if you want to know what happended through the usual statistics, you run a report for queue service-q, while if you want to know about the incoming DID #11 you run a report for did-11.

See also Tracking the incoming DID on a queue.

Permalink - Table of contents

Why does the Agent report show all Agent levels as "Undefined"?

The reason is usually pretty simple - because they are undefined. Whenever QueueMetrics runs a report on a queue, it loads the "agent level" information from that very queue definition that is being run - this means that if you use the same queue multiple times, e.g. once by itself, once as a member of an aggregate queue, you'll have to set the agent priority for all cases.

In order to assign agents to a queue, you follow the following procedure:
  • Go to the queue editor and select the queue you're reporting upon (from the main page, click on "Edit queue")
  • Click on the agents icon for the queue you intend to work on (that's the middle icon on the right with little people showing) - you should be driven to a page with "Main", "Wrap" and "Spill" columns
  • Click who is who for each level - "Main" is the first line level, "Wrap" is a backup for Main, and "Spill" is the backup for Wrap.
Of course, in order for this to produce meaningful results, you should set up penalities accordingly in the queue definition for Asterisk.

Permalink - Table of contents

Page encoding problems (Getting "JasperException: Exception parsing file" or "JasperException Error: Cannot read file" errors)

Some JVM's, particularly IBM's, seem to be a bit more picky on page encoding that Sun's. The result is that some pages of QueueMetrics do not get compiled at all, resulting in one of the exceptions above.

If this happens to you, please notify Loway of the pages you are having problems with, so that we can fix them for the next version. There is also a simple workaround that will make the page readable in most cases:
  • Stop QueueMetrics
  • Make a copy of your broken page (in this example we assume it's licence.jsp - copy licence.jsp and call it licence_OLD.jsp)
  • Run the command: iconv --from-code=ISO_8859-1 --to-code=UTF-8 --output licence.jsp licence_OLD.jsp
  • Restart QM
  • See if the culprit page loads

Permalink - Table of contents

Deploying QueueMetrics with JBoss

It is possible to deploy QueueMetrics into a JBoss application server:
  • Frst, unpack QM and set the necessary config changes (like the JDBC URL in WEB-INF/web.xml)
  • Create a WAR file out of the unpacked directory (see this tutorial)
  • Drop the war file in the JBoss deploy directory and restart Jboss

Permalink - Table of contents

Tracking the incoming DID on a queue

If you have a scenario where you have multiple incoming DIDs pointing to the same queue, and want to track how many calls you received on the queue from each of those DIDs, the easiest thing to do is use the Area Analysis function of QueueMetrics to take care of this automatically.

When a call comes in, you add the DID code to the incoming Caller ID, so that you get incoming numbers like "D7-0123456" where D7 means the call was received on DID 7 and 0123456 is the original Caller-ID. Then if you go to the Area Analysis in QueueMetrics, you can ask for a call report based on a number of Caller-ID digits (like 2 in this case, to extract the first two characters of the caller), and it will break down all calls by DID code.

You may also use this same function to track other information associated with the same calls, like multiple IVR choices pointing to the same queue.

For more information on Caller-ID rewriting, see the FAQ entry "How to set the Caller-ID".

If you need a break down of calls by calling DID and time, see Tracking hourly call distribution for multiple incoming DIDs.

Permalink - Table of contents

How to set the Caller-ID

If you need to rewrite the caller-ID of the incoming call and want the rewritten number to apperar in QueueMetrics, you should set the following Asterisk dialplan variable: CALLERID(num). This variable gets written to the queue_log, so that the information can be picked up by QueueMetrics.

The popular TrixBox distro sets the authenticated caller-ID name in the CALLERID(name) variable but not in CALLERID(num); the following piece of diaplan will do the trick:

exten => _X.,1,Set(CALLERID(num)=${CALLERID(name)})
exten => _X.,n,Set(CALLERID(name)=${CALLERID(name)})
exten => _X.,n,Goto(from-trunk,${EXTEN},1)

(thanks to Barry for pointing this out).

Permalink - Table of contents

The Qloaderd process will stop working at night

The Qloaderd process will send data from a machine's queue_log to a MySQL server. It was designed for maximum safety, so that in case there are connection errors it will try resubmitting the same query over and over, but we noticed that with some versions of the DBI it will not be able to reconnect successfully if the MySQL connection was terminated because of inactivity.

In order to avoid this, you may want to set the inactivity timeout to a very high value, by editing or adding the following variables in the [server] section of your /etc/my.ini file:

interactive_timeout = 2764800
wait_timeout = 2764800

This will avoid MySQL marking the connection as dead when the CC is inactive for may hours.
Starting from version 1.3, Qloaderd will also issue periodical queries every 15 minutes even when there is no activity to avoid this problem.

Permalink - Table of contents

How to fix timing problems in the realtime page when using MySQL storage

If you run QueueMetrics with MySQL storage mode, you will likely have QueueMetrics reside on a server that will be different from the one Asterisk is, and might as well be different from the one MySQL is.
If the clocks of all or some of those those machines have small discrepancies, this can lead to minor problems with the realtime page, showing calls with negative or positive length offsets and sometimes completely ignoring the shortest of calls.
Those problems will be experienced only with the realtime page, while the standard reports are unaffected (as they compute durations from actual data and not by inferring them from the local time).
To fix those problems, we strongly suggest you use a high-precision time syncing utility like the NTP package found in most Linux distros, and that you run it on all servers involved (Asterisk, QueueMetrics and MySQL) in order to have highly coherent timing and logging data.

To do this, simply run the following command as root to fix your system clock:
ntpdate We strongly suggest running it daily using a cron job so that you make sure the servers are consistently time-aligned in the future.

Permalink - Table of contents

How to monitor multiple queues at once

To monitor multiple queues at just create a composite queue, that is a queue which definition is a set of other queues; they can be inbound, outbound or mixed. To do this, log on as an administration, click on "Edit queues", then fill in the form on the bottom of the page called "Add new queue".

Fill-in the following form fields:
  • Alias is the name you want your composite queue to be shown as in QueueMetrics
  • Queue(s) must be filled with a set of Asterisk queue names separated by the pipe symbol (like A|B|C to monitor queues A, B and C at once)
Save and go back to the home page. Now you are ready to test your composite queue on both historical and real-time reports.

In thisway you can run a report for a composite queue and see the details of a number of queues at once (this is very useful e.g. for real-time monitoring).

We also suggest creating a queue named "00 All" that will always appear as the first in the drop-down queue selection box and will allow easy access to the overall monitoring.

Permalink - Table of contents

How to change the realtime page refresh time

You can modify the realtime page refresh rate from the basic 20-second period to any value you choose. Just set the following property:

#In how many seconds is the realtime page to refresh?

We do not suggest using a value less than 10 seconds, or the browser will flicker a bit. Time ranges in the 15-30 seconds usually work best. Please consider that decrementing the refresh timeout will add more load on the server.

Permalink - Table of contents

Logged-on agents disappear at midnight

If your agents work in shifts around midnight, with a plain QueueMetrics installation you will see that they will "disappear" at midnight from the Realtime screen, as if they logged off, though they will continue receiving calls (and calls they receive will be reported correctly). Calls handled over the midnight (i.e. started before the midnight and ending after the midnight) may seem to have been dropped as well from the realtime screen.

This is because QueueMetrics will consider agent logon information starting from the last midnight, and this arrangement works great for call centers working during the classical 9-to-5 office hours. If you need a different arrangement, you can use a "sliding window" model, where QM will look for information during a time period you define. For example, to set a sliding window of 12 hours, you would set the following property:

#The hour of the day to start real-time monitoring or sXX: sliding window of XX hours

You could also set it to "s18" or "s24" to look back 18 or 24 hours respectively - of course, the longest this period, the more data QM has to process each time.

Permalink - Table of contents

Non existent calls taken when no agents were available seem to be lagging in the queue

If you enable the maxlen, joinempty, leavewhenempty options in a queue, it is well possible that if a call enters a queue with too many waiters, or no available agents, the call is not queued but terminated immediately. Unfortunately such ghost calls seem to be present in QueueMetrics and never being taken by any agent. This is because Asterisk is not logging the piece of information that tells us that the call was rejected from the queue, so QueueMetrics has no way to know the call is not there anymore.

What we do to fix this case is that whenever the queue() command terminates and goes on with the dialplan, we make sure that we output the missing information - and this is in fact pretty easy..

We configure a queue like this:

exten => s,1,Queue(queuename||)
exten => s,2,System( echo "${EPOCH}|${UNIQUEID}|queuename|NONE|EXITWITHTIMEOUT|1" >> /var/log/asterisk/queue_log )

Of course this is a very simplified case, but you should get the idea of how to do it.

Permalink - Table of contents

Fully dynamic agents and QueueMetrics

 NOTE: If you run QueueMetrics 1.4.x and would like to enable queue-by-queue logons and logoffs with fully dynamic agents, see here for Asterisk 1.2 or here for Asterisk 1.4.QueueMetrics requires a little tweaking to work with fully dynamic agents. This is because the AddQueueMember() command will not log data correctly to queue_log, so we have to do this manually.The best way to do this is to log on your agents to all the queues you need and do an AGENTLOGIN, and then log them off when you do an AGENTLOGOFF. Calls will be reported correctly to the correct queue anyway.

For example, if your operator works on queue q1 and q2 and q3, you would do like this:

; Add Member - 422
exten => _422XX,1,Answer
exten => _422XX,2,AddQueueMember(q1,SIP/${EXTEN:3})
exten => _422XX,3,AddQueueMember(q2,SIP/${EXTEN:3})
exten => _422XX,4,AddQueueMember(q3,SIP/${EXTEN:3})
exten => _422XX,5,System( echo "${EPOCH}|${UNIQUEID}|NONE|SIP/${EXTEN:3}|AGENTLOGIN|-" >> /var/log/asterisk/queue_log )
exten => _422XX,6,DBput(dynlogin/log_Agent-${EXTEN:3}=${EPOCH})
exten => _422XX,7,Hangup

; Remove Member - 423
exten => _423XX,1,Answer
exten => _423XX,2,RemoveQueueMember(q1,SIP/${EXTEN:3})
exten => _423XX,3,RemoveQueueMember(q2,SIP/${EXTEN:3})
exten => _423XX,4,RemoveQueueMember(q3,SIP/${EXTEN:3})
exten => _423XX,5,DBget(ORGEPOCH=dynlogin/log_Agent-${EXTEN:3})
exten => _423XX,6,Set(RV=$[${EPOCH} - ${ORGEPOCH}])
exten => _423XX,7,GotoIf($["${RV}" = "0"]?10:8)
exten => _423XX,8,System( echo "${EPOCH}|${UNIQUEID}|NONE|SIP/${EXTEN:3}|AGENTLOGOFF|-|${RV}" >> /var/log/asterisk/queue_log )
exten => _423XX,9,DBdel(dynlogin/log_Agent-${EXTEN:3})
exten => _423XX,10,Hangup

If you use Local/XX@ext channel rewriting to Agent/XX, make sure to log 'Agent/${EXTEN:3}' instead of 'SIP/${EXTEN:3}'

As a further alternative, you could have your agents login in the morning to a "fake" extension producing the log line, then join each single queue without producing a log line, and then logging off in the evening to another "fake" extension producing the log line.

As a last alternative, if you need to track the actual logon-logoff times for each queue, what you have to do is to log on each queue by logging to a different agent, like:
  • Operator 20 on queue q1 is Agent/q1-20
  • Operator 21 on queue q2 is Agent/q2-21
And so on. This way you can track precisely the queue logon and logoff times for each agent on each queue. In order for this to work, you must set the following configurtation properties:

The login-logoff code in this case is as follows (for queue 'q1'):

; Add Member - 422
exten => _422XX,1,Answer
exten => _422XX,2,AddQueueMember(q1,SIP/${EXTEN:3})
exten => _422XX,3,System( echo "${EPOCH}|${UNIQUEID}|NONE|Agent/q1-${EXTEN:3}|AGENTLOGIN|-" >> /var/log/asterisk/queue_log )
exten => _422XX,4,DBput(dynlogin/log_Agent-q1-${EXTEN:3}=${EPOCH})
exten => _422XX,5,Hangup

; Remove Member - 423
exten => _423XX,1,Answer
exten => _423XX,2,RemoveQueueMember(q1,SIP/${EXTEN:3})
exten => _423XX,3,DBget(ORGEPOCH=dynlogin/log_Agent-q1-${EXTEN:3})
exten => _423XX,4,Set(RV=$[${EPOCH} - ${ORGEPOCH}])
exten => _423XX,5,GotoIf($["${RV}" = "0"]?8:6)
exten => _423XX,6,System( echo "${EPOCH}|${UNIQUEID}|NONE|Agent/q1-${EXTEN:3}|AGENTLOGOFF|-|${RV}" >> /var/log/asterisk/queue_log )
exten => _423XX,7,DBdel(dynlogin/log_Agent-q1-${EXTEN:3})
exten => _423XX,8,Hangup

Permalink - Table of contents

How to install and update QueueMetrics using yum

Yum is a package manager that is used on a number of Linux systems, notably Red Hat / CentOS and derivatives like Asterisk At Home / TrixBox, in order to ease the installation and update of software packages.

If your systems uses yum, you can install QueueMetrics from scratch using the following commands:

wget -P /etc/yum.repos.d
yum install queuemetrics

And then following the on-screen instructions in order to create the database.The first line is needed in order to add Loway Research as one of the authorized repositories into which yum can search for packages.

To update QueueMetrics to the latest version, just use:

yum update queuemetrics

And then have a look at the Updating.txt file in order to modify the database and/or the file if so is needed.

As an alternative, you may want to delete it and reinstall it from scratch, as:

yum erase queuemetrics
yum install queuemetrics

Permalink - Table of contents

Why do I get the error 'Bad interpreter' trying to run a shell file or an AGI?

If you run a command file that is written in Perl, and the file does not seem to run at all unless it is launched manually with "perl" it is very likely that you forgot to convert it from DOS format to UNIX. You usually get the error "bad interpreter" when running it manually.

To solve this problem, type dos2unix commandname - the file will be changed from DOS format to UNIX and will be immediately runnable by typing ./commandname

If this is not enough, make sure that the file is executable (chmod a+x commandname) and that the path of the Perl interpreter as specified in the first line is correct for your environment.

Permalink - Table of contents

What do the fields named UNK and BSY mean?

In the realtime view, there are two fields that may look puzzling: BSY and UNK.
  • BSY is the number of agents that are currently busy on a different queue.
    Like, if you have an agent that is active on queue A and queue B, when he is on conversation in queue A will be counted as BSY on queue B, as he is not actually ready to take calls in queue B.

  • UNK are unknown agents that are speaking on the queue.
    When QueueMetrics tries to determine how many agents are ready for a queue, it takes the total number of known agents and subtracts those who are speaking, those who are on pause and those who are BSY. If an agent shows up in a queue and QM does not know that the agent is working on that queue, the agent is counted in the UNK field.
    If you want to avoid having UNK agents, make sure that your QM agents-on-queue configuration actually matches the underlying Asterisk configuration.

Permalink - Table of contents

Why doesn't my AGI file seem to work

When installing a new AGI script, sometimes Asterisk seems to reporting that the file gets executed with result 0 while the file it is not in fact being executed at all.
If it does not, there are a few possible reasons:
  1. the script does not exist at the given agi-bin location or it is not "visible" to the user running Asterisk (solution: update unix file permisions)
  2. the script is not executable - try running it manually (do a "chmod a+x queueDial.agi")
  3. the script is in DOS mode - i.e. uses CR/LF as the line endings - and won't start from the shell (do a "dos2unix queueDial.agi" to fix it)
  4. check if the file /var/log/asterisk/agi-log.txt is read/writeable by Asterisk

Permalink - Table of contents

How to implement a dial-out queue

Note: this FAQ applies to an outdated approach. See the document "Tracing outbound calls through QueueMetrics in TrixBox" version 2.0, available form the Downloads page.

The following is is a piece of real-world dialplan one of our clients is using:

exten => _9XXX.,1,Set(MY_QUE=${EXTEN:1:3})
exten => _9XXX.,2,Set(MY_NUM=${EXTEN:4})
exten => _9XXX.,3,Set(MY_AGENT=${CALLERID(num)})
exten => _9XXX.,4,NoOp,Ag: ${MY_AGENT} N: ${MY_NUM} Q: ${MY_QUE}
exten => _9XXX.,5,MixMonitor(Q-${MY_QUE}-${UNIQUEID}.wav|b|)
exten => _9XXX.,6,DeadAGI(queueDial.agi|${MY_NUM}|Zap/g0/${MY_NUM}|q-${MY_QUE}|Agent/${MY_AGENT})
exten => _9XXX.,7,Congestion

This example needs a three digit campaign number, like '301'. If you have to dial the number 01234567 for campaign #301, you actually dial 9 301 01234567 so that the system knows on which outbound queue the call is being handled. The agent code is inferred from the current terminal it is being used and all calls are saved to disk for future reference with a name that QueueMetrics can understand (so you can listen to them with a click from the mouse).

As this feature requires making a number of changes to the Asterisk configuration, we suggest you proceed one step at a time during its implementation:
  1. First change the dialplan in order to have a NoOp() console output - like the example above steps 1-4 - so you can see that your changes to the dialplan are correct and do indeed work
  2. Then try adding the queueDial.agi in that point in the dialplan so that you are sure it is called through the diaplan (you can see it being called through the Asterisk command line interface, though it might not work yet)
  3. Once you are sure it is called, check if all file permissions are OK and the queueDial.agi does actually what it is supposed to do - places a call and adds lines to the queue_log. If it does not, chances are it is not being executed at all - see "Why doesn't my AGI file seem to work?"
  4. When everything is ready, configure QM to pick up the new queue you created.
Note: if you run some of the latest Asterisk 1.4s, it is possible that some of the calls terminated using the queueDial.agi script fail and remain "hung" in QueueMetrics - to fix this, see Quemeterics not recognising remote caller hangup on the forums.

Permalink - Table of contents

Error: java.lang.NoSuchMethodError

This error manifests itself usually after upgrading the webapp and has no apparent meaning, as the required class seems to be present in the compiled jar files. It is usually due to one of the two following causes:
  • An old version of the compiled classes is being cached by Tomcat, or
  • Tomcat is not being restarted, i.e. Tomcat receives the shutdown command but for some reason cannot terminate
To solve this problem:
  • Shut down Tomcat (check with the Unix command ps fax that no instances of java keep running after the required shutdown and - in case they do - kill them manuall with killall -9 java).
  • Clean up the Tomcat class cache - delete the entire content of the directory work that is usually located within the main Tomcat directory
  • Make sure that there is one and only one QueueMetrics webapp in the entire Tomcat system (look below the webapps directory and delete accordingly)
  • Restart Tomcat
This should fix your problem. If you fear that you have too few RAM for QueueMetrics, an ongoing "deep" garbage collection can slow down the JAva VM to a crawl and prevent it from stopping when requested to do so. In this case,see also "Out of memory error".

Permalink - Table of contents

Error: "Problema update DB: com.mysql.jdbc.MysqlDataTruncation ..."

To fix this problem, that comes with the newer versions of MySQL and Connector/J, add the parameter jdbcCompliantTruncation=false to your JDBC URI in WEB-INF/web.xml.

Permalink - Table of contents

Error: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

The Java MySQL driver was not found. Try downloading it again, putting the appropriate JAR file in WEB-INF/lib and restarting the servlet container.

Permalink - Table of contents

Java Security errors

On some systems, notably Debian, the Tomcat package is installed by default with Java security policies active; such policies are very restrictive and may block Tomcat when trying to access the database or read files from the local file system.

See the entry Running with Java security for an example ruleset that applies to QM 1.4.5.

If this is not possible, you'd better install Tomcat fresh from the tar file as described in the User Manual.
See also the Tomcat Security Manager HOW-TO for a better undertanding of the security manager.

Permalink - Table of contents

Error: java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column 14 to TIMESTAMP

You are using a version of the MySQL connector that is >= 3.1. To solve this problem add the parameter zeroDateTimeBehavior=convertToNull to your JDBC connection string located in WEB-INF/web.xml, like in the following example:


Permalink - Table of contents

Error: java.sql.SQLException: Data source rejected establishment of connection, message from server: 'Host 'localhost.localdomain' is not allowed to connect to this MySQL server'

You always think that your machine is localhost when connecting from the same host, but MySQL sometimes thinks that it's localhost.localdomain and so your credentials will not match. On MySQL, try the following line:
grant all privileges on queuemetrics.* to 'queuemetrics'@'localhost.localdomain' identified by 'password';

Permalink - Table of contents

QueueMetrics does not seem to work with GCJ

QueueMetrics does not currently work with GCJ 3 and seems to use a lot of CPU and memory on GCJ 4. GCJ is a free Java compiler/interpreter usually found on most Linux distributions but is not currently 100% compatible yet with the standard Java bundle - see

You should use an industrial-strength Java SDK instead, like the ones from Sun or IBM. Our suggestion is to go for the latest Sun SDK available.

Permalink - Table of contents

Error: java.sql.SQLException: Access denied for user 'queuemetrics'@'mydb' (using password: YES)

The error means that the user and/or password given in WEB-INF/web.xml do not match credentials supplied with MySQL. On MySQL, try the following line:
grant all privileges on queuemetrics.* to 'queuemetrics'@'mydb' identified by 'password';

Permalink - Table of contents

Error: "Il verbo '.....' richiede una chiave non disponibile all'utente corrente"

You need a key you do not currently have to run the required transaction. Likely, your session timed out for inactivity, so you have no key at all associated with your profile; when you then click on a link, the system tells you that you have to log on again.

Permalink - Table of contents

Error: java.sql.SQLException: Invalid authorization specification message from server: 'Access denied for user: 'queuemetrics@localhost.localdomain' (Using password: YES)'

You always think that your machine is localhost when connecting from the same host, but MySQL sometimes thinks that it's localhost.localdomain and so your credentials will not match. On MySQL, try the following line:
grant all privileges on queuemetrics.* to 'queuemetrics'@'localhost.localdomain' identified by 'password';

Permalink - Table of contents

Error: "Il verbo '.....' non consente la creazione di una nuova sessione"

Your session timed out for inactivity; when you then click on a link, the system tells you that you have to log on again.

Permalink - Table of contents

QueueMetrics Training