Есть колл-центр. Есть Asterisk/FreePBX с настроенными очередями. Есть агенты, которые должны обслуживать вызовы. Но потенциальных клиентов так много, а агентов так мало, что первые никак не могут дозвониться до вторых — повисят-повисят в очереди минуту, да и отключаются.
Но зачем-то они же звонили! Может, они хотят денег занести в компанию? Попробуем вернуть и клиентов и их деньги на примере FreePBX.
В настройках очереди можно указать Fail Over Destination — то, куда направлять вызов, когда очередь переполнена, истекло время ожидания и т.п. Но зачастую бывает так, что звонивший отключается раньше, чем его успевает перенаправить в Fail Over Destination — мало ли, связь оборвалась. Готового решения для таких случаев нет. Поэтому идём под кат и пишем своё — с отправкой оповещения в Telegram/Slack/E-mail/куда-то там еще.
И первое, что нам надо понять — как FreePBX пишет логи очередей. В самом простом случае это текстовый файл /var/log/asterisk/queue_log.
Так в лог пишется обычный звонок от абонента 8964467ХХХХ, позвонившего по номеру 302221ХХХХ, попавшего в очередь №603 на первую позицию, которому через 8 секунд ответил Agent Girl. Они проговорили 133 секунды и первым трубку положил абонент — всем бы таких вежливых менеджеров!
А вот немного другая история, когда абонент 8996453ХХХХ дозвонился по номеру 302257ХХХХ, повисел 10 секунд в очереди №210 в первой позиции и отключился. Даже голосовое меню не дослушал!
Вот про него-то мы и напишем в мессенджер.
Для этого нам надо отловить появление события ABANDON в файле лога. Я долго ломал себе голову как это можно сделать, но потом совершенно случайно наткнулся на прекрасный инструмент — MONIT. В нашем случае он будет следить за логом очередей, и как только в нём появится строка «ABANDON» будет вызывать скрипт обработки данного события.
Для этого после установки пакета:
Настроим его — создадим файл /etc/monit.d/queue_log и запишем в него буквально три строчки:
Таким образом, при появлении слова «ABANDON» в логе очередей, что говорит нам о преждевременном отключении абонента, будет вызван скрипт /var/lib/asterisk/agi-bin/qlogevent.sh с параметром $EVENT, что есть ничто иное, как полностью строка, в которой это слово появилось.
Это просто.
А теперь начинаются не шахматы — тут думать надо.
В строке, переданной в скрипт, отсутствует информация о номере звонившего:
В ней есть только Timestamp (1581728720), уникальный ID звонка (1581728690.59367), номер очереди (210), само событие и еще несколько несущественных параметров. Т.е. искать номер абонента придется нам самим. А каким же образом? А очень просто, ведь UID звонка у нас есть!
Обратимся опять к логу данного звонка, конкретно — к строке, в которой абонент попадает в очередь:
При возникновении события «ENTERQUEUE» один из параметров — необходимый нам номер абонента. Нам остается только отыскать данную строку в файле queue_log. Этим как раз занимается скрипт на bash, который MONIT нам заботливо вызвал:
Собственно, и всё!
Правда, есть один казус — MONIT, предназначенный для мониторинга всего и вся, сам нуждается в мониторинге, т.к. периодически падает.
Но зачем-то они же звонили! Может, они хотят денег занести в компанию? Попробуем вернуть и клиентов и их деньги на примере FreePBX.
В настройках очереди можно указать Fail Over Destination — то, куда направлять вызов, когда очередь переполнена, истекло время ожидания и т.п. Но зачастую бывает так, что звонивший отключается раньше, чем его успевает перенаправить в Fail Over Destination — мало ли, связь оборвалась. Готового решения для таких случаев нет. Поэтому идём под кат и пишем своё — с отправкой оповещения в Telegram/Slack/E-mail/куда-то там еще.
И первое, что нам надо понять — как FreePBX пишет логи очередей. В самом простом случае это текстовый файл /var/log/asterisk/queue_log.
Так в лог пишется обычный звонок от абонента 8964467ХХХХ, позвонившего по номеру 302221ХХХХ, попавшего в очередь №603 на первую позицию, которому через 8 секунд ответил Agent Girl. Они проговорили 133 секунды и первым трубку положил абонент — всем бы таких вежливых менеджеров!
1584318765|1584318747.89449|603|NONE|DID|302221ХХХХ
1584318765|1584318747.89449|603|NONE|ENTERQUEUE||8964467ХХХХ|1
1584318774|1584318747.89449|603|Agent Girl|CONNECT|9|1584318765.89450|8
1584318907|1584318747.89449|603|Agent Girl|COMPLETECALLER|9|133|1
А вот немного другая история, когда абонент 8996453ХХХХ дозвонился по номеру 302257ХХХХ, повисел 10 секунд в очереди №210 в первой позиции и отключился. Даже голосовое меню не дослушал!
1581728710|1581728690.59367|210|NONE|DID|302257ХХХХ
1581728710|1581728690.59367|210|NONE|ENTERQUEUE||8996453ХХХХ|1
1581728720|1581728690.59367|210|NONE|ABANDON|1|1|10
Вот про него-то мы и напишем в мессенджер.
Для этого нам надо отловить появление события ABANDON в файле лога. Я долго ломал себе голову как это можно сделать, но потом совершенно случайно наткнулся на прекрасный инструмент — MONIT. В нашем случае он будет следить за логом очередей, и как только в нём появится строка «ABANDON» будет вызывать скрипт обработки данного события.
Для этого после установки пакета:
yum install monit
Настроим его — создадим файл /etc/monit.d/queue_log и запишем в него буквально три строчки:
check file queue_log with path /var/log/asterisk/queue_log
if content = "ABANDON" then
exec "/var/lib/asterisk/agi-bin/qlogevent.sh $EVENT"
Таким образом, при появлении слова «ABANDON» в логе очередей, что говорит нам о преждевременном отключении абонента, будет вызван скрипт /var/lib/asterisk/agi-bin/qlogevent.sh с параметром $EVENT, что есть ничто иное, как полностью строка, в которой это слово появилось.
Это просто.
А теперь начинаются не шахматы — тут думать надо.
В строке, переданной в скрипт, отсутствует информация о номере звонившего:
1581728720|1581728690.59367|210|NONE|ABANDON|1|1|10
В ней есть только Timestamp (1581728720), уникальный ID звонка (1581728690.59367), номер очереди (210), само событие и еще несколько несущественных параметров. Т.е. искать номер абонента придется нам самим. А каким же образом? А очень просто, ведь UID звонка у нас есть!
Обратимся опять к логу данного звонка, конкретно — к строке, в которой абонент попадает в очередь:
1581728710|1581728690.59367|210|NONE|ENTERQUEUE||8996453ХХХХ|1
При возникновении события «ENTERQUEUE» один из параметров — необходимый нам номер абонента. Нам остается только отыскать данную строку в файле queue_log. Этим как раз занимается скрипт на bash, который MONIT нам заботливо вызвал:
#!/bin/bash
#MONIT_DESCRITION - строка, которая передана как параметр в скрипт.
#Преобразуем timestamp в человеческое представление даты-времени (параметр №1).
timedate=$(echo $MONIT_DESCRIPTION | cut -d\| -f1 | cut -d\: -f2 | gawk '{print strftime("%d.%m.%Y %H:%M:%S",$0);}')
#Получаем UID (параметр №2)
call_id=$(echo $MONIT_DESCRIPTION | cut -d\| -f2)
#и номер очереди (параметр №3)
qnum=$(echo $MONIT_DESCRIPTION | cut -d\| -f3)
#По номеру очереди присваиваем ей человеческое имя
case $qnum in
210)
qname="Очередь 1"
;;
220)
qname="Очередь 2"
;;
esac
#И ищем в логе строку с UID, номером очереди и событием ENTERQUEUE
str=$(grep "|$call_id|$qnum|.*|ENTERQUEUE" /var/log/asterisk/queue_log)
#Получаем из неё номер позвонившего абонента (параметр №7)
caller_id=$(echo $str | cut -d\| -f7)
#Время его попадания в очередь (паоаметр №1)
time_enter=$(echo $str | cut -d\| -f1)
#И время пропадания из очедери (параметр №1 из события ABANDON)
time_abandon=$(echo $MONIT_DESCRIPTION | cut -d\| -f1 | cut -d\: -f2)
#Формируем сообщение
data="Абонент $caller_id $timedate позвонил в $qname, не дождался ответа и отбился через $(($time_abandon-$time_enter)) сек."
#И отправляем его в мессенджер/почту. В данном случае это Slack.
/usr/bin/curl -X POST -H 'Content-type: application/json' --data '{"text":"'"$data"'"}' "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
Собственно, и всё!
Правда, есть один казус — MONIT, предназначенный для мониторинга всего и вся, сам нуждается в мониторинге, т.к. периодически падает.
arheops
Очереди элементарно запихиваются в MySQL. Двумя строчками буквально.
После чего можно все просто заменить обычным crontab скриптом раз в минуту, и ничего не падает.
Ваш скрипт какой-то вообще странный, он перелопачивает весь лог. Рекомендую как миниум ограничить глубину используя tail. hint: первое число в логе — время, оно равномерно увеличивается, можно легко подобрать нужную глубину, если вдруг не нашли.
Но вообще эти танцы с бубнами не нужны, пишите в mysql или для параноиков в sqlite.
Вот здесь, к примеру, описано. www.voip-info.org/asterisk-queuelog-on-mysql
ps nagios — не падает
aharu Автор
Спасибо за комментарии. Действительно, хранить логи очередей и искать по ним удобнее в xSQL. Но за ту же минуту может нападать несколько событий ABANDON.
Проще комбинировать эти способы — обработку появления ABANDON делать через MONIT и текстовый лог, а поиск ENTERQUEUE по xSQL.
arheops
Не понял как вам это помешает. Во первых, вы можете добавить любое количество колонок в таблицу. Например id serial или informed int.
Во вторых, там будет дата и вы можете тупо выбирать раз минуту за прошлую минуту. Индекс не забудьте.
Слишком у вас все переусложнено.