Uploading data to QueueMetrics Live

While the section below explains how data export, data splitting and automatic configuration work, your life will be easier if you designate a small VM separate from the main PBX to do these jobs, and then use the Ansible scripts provided here: https://github.com/Loway/OpenQueueMetricsAddOns/tree/master/ansible-fusionpbx to run and manage all these tasks for you.

Setting up the services

We will be creating two services on the FusionPBX box; one of them uniloader-freeswitch downloads data continuously from FreeSwitch and generates a queue_log file; and the other one uniloader-splitter knows which tenants are active (based on a file you specify) and uploads data to all of them.

All commands below need to be run as root.

Installing Uniloader

We will install Uniloader as a symlink under /opt/uniloader, so that it is always in the same place even when it is upgraded. We will also add it to the system path so that it’s available from any shell.

The link for the current version of Uniloader is available from https://www.queuemetrics.com/download.jsp

mkdir -p /opt/uniloader
cd /opt/uniloader
wget https://downloads.loway.ch/qm/uniloader-21.04.6.tar.gz
tar zxvf uniloader-21.04.6
ln -s ./uniloader-21.04.6/bin/uniloader_amd64 uniloader
ln -s /opt/uniloader/uniloader /usr/bin/uniloader

Now we create a folder to store queue_log data into:

mkdir -p /opt/uniloader/qlogs

Checking PBX accesses and passwords

In order to continue, you will need accesses to your FusionPBX / FreeSwitch system. Uniloader includes ways to test and debug connections, so we will use it to assert everything is okay.

ESL access to FreeSwitch

You can make sure that local access to FreeSwitch’s ESL port is allowed by typing:

# uniloader test fsw-esl --host "127.0.0.1" --port "8021" --auth "ClueCon"
2020/02/04 06:43:19 Testing Freeswitch connection to '127.0.0.1:8021' with auth token 'ClueCon'

2020/02/04 06:43:19 <ESL: Content-Type: command/reply
2020/02/04 06:43:19 <ESL: Reply-Text: +OK accepted
2020/02/04 06:43:19 <ESL:
2020/02/04 06:43:19  ======= Login OK
....

If you see the Login OK message, then you are set. If not, you will have to check ESL access credentials and allowed IPs.

Access to FusionPBX’s database

FusionPBX generates a random password for the database on installation. To find the password for your FusionPBX database, print the contents of your file /etc/fusionpbx/config.php:

//pgsql: database connection information
	$db_host = 'localhost'; //set the host only if the database is not local
	$db_port = '5432';
	$db_name = 'fusionpbx';
	$db_username = 'fusionpbx';
	$db_password = 'UELfQn8gWg6bp6SRMoOhwqZ34F0';

Now test that it’s working by typing:

# uniloader test postgres --ps-uri "localhost/fusionpbx" --ps-login "fusionpbx" --ps-pwd UELfQn8gWg6bp6SRMoOhwqZ34F0
2020/02/04 06:49:04 Testing Postgres connection to 'postgres://fusionpbx:UELfQn8gWg6bp6SRMoOhwqZ34F0@localhost/fusionpbx'

2020/02/04 06:49:04  -- Connection took 13.287µs
2020/02/04 06:49:04  -- Query took 11.365098ms
2020/02/04 06:49:04 Local time on database is: 2020-02-04T06:49:04.033431+01:00

If it prints out the local time, it’s working.

Service uniloader-freeswitch: log generation

We will create a systemd service to export data out of the PBX and format it in a way that is compatible with QueueMetrics.

Create a new file /etc/systemd/system/uniloader-freeswitch.service.

#
# Systemd Unit for Uniloader FreeSwitch ESL Export
#

[Unit]
Description=Generates queue_log from ESL events
After=syslog.target network.target freeswitch.service

[Service]
Type=simple
#EnvironmentFile=/etc/uniloader-freeswitch
Nice=15
KillMode=process
PIDFile=/var/run/uniloader-freeswitch.pid
ExecStart=/opt/uniloader/uniloader fsw  --queuelog /opt/uniloader/qlogs/qlog-synth.txt --ps-pwd UELfQn8gWg6bp6SRMoOhwqZ34F0  --shorten-domain "1" --use-addmember "1"
RestartSec=1
Restart=on-failure


[Install]
WantedBy=multi-user.target
The code above generates ADDMEMBER log-on events; it is compatibile with Uniloader 21.04.6 and newer. On earlier versions, remove the --use-addmember option. See ADDMEMBER.

We now run:

systemctl daemon-reload
systemctl start  uniloader-freeswitch
systemctl enable uniloader-freeswitch

This way the service is started immediately and will restart on boot, after Freeswitch itself starts.

To check if the system is working correctly, run:

# systemctl status  uniloader-freeswitch
- uniloader-freeswitch.service - Generates queue_log from ESL events
   Loaded: loaded (/etc/systemd/system/uniloader-freeswitch.service; disabled; vendor preset: enabled)
   Active: active (running) since Tue 2020-02-04 07:01:36 CET; 6s ago

Now, if we have any activity in mod_callcenter, a file should appear under /opt/uniloader/qlogs/.

If this service is not active, queue data generated on the switch will be lost. So you should never stop (or even restart) this sevice while the PBX is running.
A note on ADDMEMBER mode

FusionPBX does not allow the selection of which queues an agent is supposed to work on; an agent becomes available (or unavailable) on all of the queues they are configured on.

In terms of reporting, this means that QueueMetrics Live will display an agent as available on a fake queue called * ALL *, as we have no information on which queues an agent is actually working on.

If you enable ADDMEMBER mode, by passing --use-addmember "1" to uniloader fsw, then each time an agent logs on or off, their current set of queues is queried on the FusionPBX database, and separate log-on records are emitted for each queue. This gives QueueMetrics the information needed to display the current set of calls an agent is working on.

This does not change the fact that logging on, logging off or pausing happen at once on all queues, and never separately. As a possible workaround, see Using multiple agent/queue sets.

Service uniloader-splitter: Setting up data export

We now have to define a service for data export. For now, let’s imagine we have no tenant, so that it has nothing to do. Our service will read data from the queue_log file generated by uniloader-freeswitch, check each entry against a set of rules that specify our known tenants we want to feed, and do nothing because we have none so far.

We first create the rules file; edit a new file under /opt/uniloader/splitter.json that just contains two square brackets, as below:

[]

Create a new file /etc/systemd/system/uniloader-splitter.service.

#
# Systemd Unit for Uniloader Splitter
#

[Unit]
Description=Loway Uniloader Splitter
After=syslog.target network.target


[Service]
Type=simple
#EnvironmentFile=/etc/uniloader-splitter
Nice=15
KillMode=process
PIDFile=/var/run/uniloader-splitter.pid
ExecStart=/opt/uniloader/uniloader -s /opt/uniloader/qlogs/qlog-synth.txt  upload --splitter /opt/uniloader/splitter.json  --pid /var/run/uniloader-splitter.pid
RestartSec=1
Restart=on-failure


[Install]
WantedBy=multi-user.target

We now install the service as:

systemctl daemon-reload
systemctl start  uniloader-splitter
systemctl enable uniloader-splitter

To make sure it is working correctly, and see its logs when needed:

# systemctl status uniloader-splitter
● uniloader-splitter.service - Loway Uniloader Splitter
   Loaded: loaded (/etc/systemd/system/uniloader-splitter.service; disabled; vendor preset: enabled)
   Active: active (running) since Tue 2020-02-04 07:19:27 CET; 2s ago
 Main PID: 3590 (uniloader)
    Tasks: 6 (limit: 4915)
   CGroup: /system.slice/uniloader-splitter.service
           └─3590 /opt/uniloader/uniloader -s /opt/uniloader/qlogs/qlog-synth.txt upload --splitter /opt/uniloader/splitter.json --pid /var/run/uni

Feb 04 07:19:27 debian systemd[1]: Started Loway Uniloader Splitter.
Feb 04 07:19:27 debian uniloader[3590]: 2020/02/04 07:19:27 Uniloader 0.6.7 (149-20191004.1255) starting upload [PID 3590].
Feb 04 07:19:27 debian uniloader[3590]: 2020/02/04 07:19:27 Uniloader 0.6.7 (149-20191004.1255) is alive - GR: 3 - Mem: Alloc 321k (Free 0k) Sys 68

Creating a new tenant

To create a new tenant you will need:

  • An existing tenant in FusionPBX that you want to send, and

  • A QueueMetrics Live instance to upload data to; in our example it will be:

If you have API access you can activate such instance automatically; if not, contact Loway for its creation.

Checking prerequisites

We first want to make sure that the QueueMetrics Live instance is available and that our password is correct:

# uniloader test upload --uri  https://stats.pbx.my/tenant1 --pass 12345678
Testing upload credentials.

High Water Mark is 1580741450 [2020-02-03 15:50:50 +0100 CET]
Connection OK

On a brand new system, you will see the High Water Mark set to zero.

We then want to make sure that our tenant is available in FusionPBX:

# uniloader pbxinfo fusionpbx --ps-pwd UELfQn8gWg6bp6SRMoOhwqZ34F0

=  Tenant # 1: tenant1.pbx.my

-- Queues found: 3
   #            Code            Name                       Ext.Ref.
   1           00all          00 All
   2             500            q500 64032aac-f3b2-474b-a2c3-08f1a35ea16a
   3             501            q501 53b66cc6-51b7-43b9-84ef-22d44fc46f69

-- Agents found: 3

   #            Code            Name                       Ext.Ref.
   1       Agent/200          Martin 391770f4-aaad-4834-9050-0770a32782d0
   2       Agent/201           Vince 6d26623c-e5a9-46a1-93b3-937389ca8a02
   3       Agent/202            Dave 64eab4f9-829a-4fb8-8cbc-d2e6a5443fd6

If you see any agents/queues appearing, it means that the tenant will generate data and can be uploaded.

The number of agents you see here is a good guess about the required size of your QueueMetrics Live instance.

Editing the tenant rules

Our splitter files contains multiple JSON object that tell Uniloader how to match log entries to known QueueMetrics Live instances and where to send them. While the queue_log file contains information for all queue activity on the system, you will only be sending out data for tenants you have configured.

In our example:

[
	{
		"uri": "https://stats.pbx.my/tenant1",
		"login": "webqloader",
		"pass": "12345678",
		"token": "",
		"matcher": ["tenant1-"],
		"match": "any",
		"removematch": true,
		"disabled": false,
		"noactions": false,
		"clientname": "tenant1"
	}
]

Make sure that:

  • uri and pass are the ones you checked with QueueMetrics Live

  • matcher is the subdomain you use for your tenant, plus a dash.

  • clientname is a free comment

  • you can set disabled to true if you want to "switch off" data upload for a tenant without deleting it from this file.

When done, just restart the service so that changes are picked up.

systemctl restart uniloader-splitter

While the service is restarted (and even if it stays down for a few seconds), no data is being lost, as data is still being written by the uniloader-freeswitch service and stored safely into the queue_log file. The worst thing that can happen are a few seconds of delay on the wallboards - but data is always computed correctly and will sync automatically.

The splitter file should be backed up after each change.

Checking that it’s working

Try sending a call to a queue on your tenant. Answer the call, then hang it up.

Now log in to your QueueMetrics Live instance; from the Home Page click on "Administrative Tools" → "System Diagnostic Tools" → "Live DB Inspector": you should see a number of records appear on the page.

Pre-configuring your QueueMetrics Live instance

You should now run an automated configuration of the QueueMetrics Live instance:

uniloader pbxinfo --mode syncqm -u https://stats.pbx.my/tenant1 -p 12345678
     fusionpbx -ps-pwd UELfQn8gWg6bp6SRMoOhwqZ34F0 --single-tenant tenant1.pbx.my

This will:

  • Create queues

  • Create agents

  • Set the correct FusionPBX IDs for agents, so they can be controlled through QueueMetrics

You should run this command whenever the configuration changes on FusionPBX, so everything stays in sync.