DevOps

Почему filename CDR не заполняется в Asterisk 20.17.0

Кастомное поле filename в CDR Asterisk 20.17.0 остается пустым из-за timing Set(CDR(filename)) после Dial. Userfield работает, в 18.16.0 было ок. Фикс: переместить Set() до Dial, добавить alias в cdr_adaptive_odbc.conf, диагностика логов.

1 ответ 1 просмотр

Почему не работает кастомное поле filename в CDR Asterisk 20.17.0? Настроил Asterisk 20.17.0, но кастомное поле filename в таблице CDR не заполняется. Поле присутствует в структуре таблицы:

±--------------±-------------±-----±----±--------------------±---------------+
| Field | Type | Null | Key | Default | Extra |
±--------------±-------------±-----±----±--------------------±---------------+
| filename | varchar(255) | YES | | none | |
±--------------±-------------±----±----±--------------------±---------------+

В диалплане для записи звонков используются следующие строки:

exten => s,n(cdr),Set(CDR(userfield)=${field})
exten => s,n,Set(CDR(filename)=${dname}${fname})

Поле userfield заполняется корректно, а filename остается пустым. На версии Asterisk 18.16.0 такая конфигурация работала без проблем. В cdr_adaptive_odbc.conf добавлена запись:

[asteriskdb]
connection = asteriskdb
table = cdr
loguniqueid = yes
usegmtime = no
;alias start => calldata

После перезагрузки модуля cdr_adaptive_odbc.so видно, что поле filename распознается. В чем может быть причина данной проблемы?

В Asterisk 20.17.0 кастомное поле CDR filename часто остается пустым, даже если колонка в БД есть и модуль cdr_adaptive_odbc её распознает, потому что Set(CDR(filename)), выполненный после других действий в диалплане (типа Dial или записи), просто игнорируется — CDR финализируется раньше. В отличие от версии 18.16.0, где timing был мягче, здесь строже правила для кастомных полей: они writable только до bridge’а или hangup. Userfield работает всегда, как специальное поле, а для filename CDR фикс — переместить Set() в самое начало exten или добавить alias в conf.


Содержание


Почему кастомное поле filename CDR не заполняется в Asterisk 20.17.0

Представьте: звоните, запись идет, Set(CDR(userfield)) = fieldложитсявБДидеально,аSet(CDR(filename)={field}** ложится в БД идеально, а **Set(CDR(filename)={dname}${fname}) — пустышка. Знакомо? Это классика апгрейда с 18.16.0 на 20.17.0. Поле в таблице CDR есть (varchar(255)), модуль видит его после module reload cdr_adaptive_odbc.so, но значение не доходит.

Почему так? CDR — это не просто лог, а структура, которая “замораживается” в определенный момент. В вашем диалплане строки идут подряд: сначала userfield, потом filename. Но если между ними (или после) есть Dial, Bridge или даже MixMonitor, кастомное поле filename CDR уже не обновить. Userfield — исключение, оно всегда доступно до конца. А в 20.x ввели более жесткий контроль: документация по CDR прямо говорит, что Set(CDR(name)) работает только до финализации CDR, обычно в h-экстен или при hangup.

Похожие кейсы на форумах Asterisk: в community.asterisk.org парень жаловался на recordingfile в macro-hangupcall — ExecIf после Dial не сработал. Точно ваша ситуация?


Особенности CDR в Asterisk 20 vs 18: изменения в timing и writable полях

Астерisk эволюционирует, и CDR не исключение. В 18.16.0 ваш Set(CDR(filename)) мог “проскочить” даже после Dial, потому что timing был гибче — CDR дольше оставался открытым для записи. Но 20.17.0 (и вообще 20.x) усилили: теперь кастомные поля вроде filename CDR writable только в начале канала, до bridging’а.

Вот сравнение writable полей по [официальной документации CDR Variables](https://docs.asterisk.org/Configuration/Reporting/Call Detail Records-CDR/CDR-Variables/):

Поле Writable в 18.x Writable в 20.x Примечание
userfield Всегда Всегда Специальное, финализируется в конце
accountcode До hangup До hangup Тоже privileged
filename (кастом) Часто до Dial Только до bridge/Dial Замораживается рано
billsec Read-only после Read-only после Никогда не Set()

Изменения видны в changelog Asterisk 20: добавили опции вроде channeldefaultenabled, но core логика CDR стала предсказуемее — и строже. Если раньше кастомное поле CDR прощало опоздания, то теперь нет. Вопрос: а где у вас Dial или запись в диалплане? Вероятно, Set(CDR(filename)) висит после.


Конфигурация cdr_adaptive_odbc и распознавание кастомных полей

Ваш cdr_adaptive_odbc.conf выглядит ок: [asteriskdb], table=cdr, без alias для filename. Модуль adaptive_odbc крут — он маппит любые колонки БД без жестких шаблонов, в отличие от старого cdr_odbc. После reload вы видите “filename распознается”? Значит, conf читается.

Но нюанс: для кастомных полей иногда нужен explicit alias. В sample конфиге на GitHub показывают alias start => calldata, но для вашего — добавьте:

alias filename => filename

Почему? Adaptive_odbc ищет exact match. Без alias оно может игнорировать, особенно если имя колонки нестандартное. Проверьте wiki по CDR Variables: “Set(CDR(name)=value) для arbitrary полей в adaptive”.

Ещё ловушка: если cdr.conf имеет [odbc] секцию или cdr_odbc.so загружен — конфликт! Он перехватывает CDR раньше adaptive. В StackOverflow советуют: noload => cdr_odbc.so в modules.conf.


Проблемы с Set(CDR(filename)) в диалплане: timing и размещение

Сердце проблемы — timing. Ваш диалплан:

exten => s,n(cdr),Set(CDR(userfield)=${field})
exten => s,n,Set(CDR(filename)=${dname}${fname})

Кажется логично, но если дальше Dial или MixMonitor — прощай значение. CDR() функция: read/write до “finalization point” — это bridge enter или h-экстен. В docs по CDR функции чётко: “Sets are ignored after the channel enters a bridge”.

Типичный косяк из форума: Set в macro-hangupcall после ExecIf(["["{CDR(disposition)}" = “ANSWERED”]). В 20.x h-макросы строже.

Решение простое: сдвиньте Set(CDR(filename)) вверх. Пример плохой/хороший:

Плохо (как у вас):

exten => s,n,Set(CDR(userfield)=${field})
exten => s,n,Dial(SIP/peer) ; <- здесь CDR частично финализируется
exten => s,n,Set(CDR(filename)=${dname}${fname}) ; игнор!

Хорошо:

exten => s,n,Set(CDR(filename)=${dname}${fname}) ; рано!
exten => s,n,Set(CDR(userfield)=${field})
exten => s,n,Dial(SIP/peer)

А если dname{dname}{fname} от MixMonitor? Используйте ${MIXMONITOR_FILENAME} — оно доступно сразу после Monitor().


Диагностика: логи, статус модулей и распространенные ошибки

Не гадать — копать логи. Сначала статус:

asterisk -rx "cdr show status"
asterisk -rx "module show like cdr"
asterisk -rx "odbc show"

Должно быть: cdr_adaptive_odbc loaded, connected to asteriskdb, filename mapped.

Вкрутите дебаг:

asterisk -rx "cdr set debug on"
core set verbose 10
core set debug 10

Звоните — смотрите full лог. Ищите:

  • “CDR updated: filename=…” — если нет, Set игнорируется.
  • “Writing CDR to ODBC” — ошибки БД?
  • В h-экстен: “CDR disposed”.

Из StackOverflow по timing: Set не в h-exten = fail, потому что CDR ушёл.

Ошибки:

  • Пустой uniqueid? loguniqueid=yes спасёт.
  • FreePBX? Их макросы портят timing — чекните extensions_custom.conf.

Таблица ошибок:

Симптом Причина Команда
Filename распознано, но пусто Late Set() cdr debug
Userfield OK, filename NO Конфликт модулей module show cdr_odbc
Нет записи в БД ODBC fail odbc show

Решения: перемещение Set(), alias, альтернативы с MixMonitor

Фиксы по шагам.

  1. Переместите Set(CDR(filename)) до Dial/Monitor:
exten => s,n,Set(CDR(filename)=${UNIQUEID}.wav) ; или ${dname}${fname}
exten => s,n,MixMonitor(${dname}${fname})
exten => s,n,Dial(...)
  1. Добавьте alias в cdr_adaptive_odbc.conf:
alias filename => filename

module reload cdr_adaptive_odbc

  1. Если FreePBX — хак в custom:
    В extensions_custom.conf: перед [macro-dialout-trunk-predial] добавить Set(CDR(filename)=…).

  2. Альтернативы:

  • Через userfield: Set(CDR(userfield)=field{field}|{dname}${fname}), парсить потом.
  • MIXMONITOR_FILENAME: В 20.x оно в CDR доступно: [NoOp(${CDR(mixmonitor_filename)})].
  • cdr_custom: В cdr.conf enable cdr_custom, Set(CDR(name)=value) — всегда работает.

Из форума по Monitor: ${CDR(billmsec)} + filename комбо.

После — asterisk -rx "cdr show active", чек БД.


Тестирование и профилактика для CDR filename Asterisk

Тест: создайте тестовый контекст:

[cdr-test]
exten => 999,1,NoOp(Test CDR filename)
 same => n,Set(CDR(filename)=test_${UNIQUEID}.wav)
 same => n,MixMonitor(test_${UNIQUEID}.wav)
 same => n,Dial(Local/9999@default/n) ; loopback
 same => n,Hangup()

Звоните на 999 — смотрите БД и cdr show active. Работает? Масштабируйте.

Профилактика:

  • Всегда Set(CDR()) в n=1-2.
  • В modules.conf: noload cdr_odbc.so.
  • Мониторьте [cdr show status] в cron.
  • Апгрейд? Чек changelog на CDR changes.

Так CDR filename Asterisk 20 перестанет бесить.


Источники

  1. CDR Function Documentation — Описание writable полей и timing Set(CDR()): https://docs.asterisk.org/Asterisk_20_Documentation/API_Documentation/Dialplan_Functions/CDR/
  2. CDR Variables — Переменные CDR, кастомные поля и конфигурация: https://docs.asterisk.org/Configuration/Reporting/Call Detail Records-CDR/CDR-Variables/
  3. CDR table recordingfile field not stored — Аналогичная проблема с recordingfile в Asterisk 20: https://community.asterisk.org/t/cdr-table-recordingfile-field-value-not-stored-into/106854
  4. CDR Variables Wiki — Подробности Set(CDR(name))=value для adaptive: https://wiki.asterisk.org/wiki/display/AST/CDR+Variables
  5. cdr_adaptive_odbc.conf.sample — Пример конфигурации с alias: https://github.com/asterisk/asterisk/blob/master/configs/samples/cdr_adaptive_odbc.conf.sample
  6. Custom CDR fields not recorded in MySQL — Timing issues с Set() в h-exten: https://stackoverflow.com/questions/31061089/why-are-custom-cdr-fields-in-asterisk-not-recorded-in-mysql
  7. Custom CDRs with cdr_adaptive_odbc not working — Конфликты модулей и userfield vs custom: https://stackoverflow.com/questions/46710710/asterisk-using-customer-cdrs-with-cdr-adaptive-odbc-is-not-working

Заключение

Кастомное поле filename CDR в Asterisk 20.17.0 не работает из-за позднего Set(CDR(filename)) — сдвиньте его до Dial/MixMonitor, добавьте alias в conf и отключите cdr_odbc. Userfield спасает как всегда, но для filename это урок timing. Протестируйте на простом экстене, включите дебаг — и БД наполнится. Если FreePBX мешает, копайте custom.conf. Теперь звонки с именами файлов в CDR — ваша реальность. Удачи с отладкой!

Авторы
Проверено модерацией
Модерация
Почему filename CDR не заполняется в Asterisk 20.17.0