В общем, проблема оказалась в настройках менеджера. Когда добавляю в секцию [general] происходят вот такие проблемы и в cdr пишется фигня какая-то, как я указал выше и сыпется ошибка
ERROR[734261]: cdr.c:3481 ast_cdr_getvar: Unable to find CDR for channel
[general]
channelvars=CDR(linkedid),CDR(src),CDR(dst),FullFname,CallMeDISPOSITION,CallMeDURATION,CALLFILENAME,DIALSTATUS,ANSWEREDTIME
Интересно почему!? Кто-нибудь может объяснить?
Проблема, с которой вы столкнулись, — известное ограничение Asterisk. Ошибка возникает из-за того, что директива channelvars пытается получить доступ к переменным CDR до того, как сам механизм CDR будет готов предоставить эти данные.
Давайте разберем это на уровне механики Asterisk.
? Почему возникает ошибка
1. Разное время жизни: Директива channelvars в manager.conf заставляет AMI генерировать события с указанными переменными на протяжении всего жизненного цикла канала (события вроде Newchannel). В то же время, механизм CDR создается немного позже и привязан к конкретному каналу. Запрашивая CDR(src) на старте канала, вы обращаетесь к сущности, которая еще не существует.
2. Синтаксический конфликт: Ожидая простые канальные переменные, channelvars пытается обработать выражение CDR(src) как обычную переменную. Сложный синтаксис с круглыми скобками может нарушить парсинг AMI-протокола, особенно при работе с именами каналов, содержащими специальные символы.
3. Высокая нагрузка: Как упоминалось в списке рассылки, в версиях Asterisk 12+ эта опция стала очень затратной с точки зрения производительности. Прямой доступ к CDR-полям на каждое событие создает значительную нагрузку на систему.
✅ Как правильно передавать CDR-поля в AMI
Вот три надежных способа решить эту задачу без ошибок и падения производительности.
1. Использовать Set(CDR(userfield)) (Рекомендуемый):
В диалплане перед вызовом Dial явно скопируйте нужные данные в специальное поле CDR(userfield), а в manager.conf укажите только его.
· Диалплан: exten => _X.,1,Set(CDR(userfield)=${CDR(src)} ${CDR(dst)})
· manager.conf: channelvars = userfield
· Результат: CDR создается тогда, когда нужно, поле userfield предназначено для хранения дополнительной информации, а его использование в channelvars абсолютно безопасно.
2. Использовать кастомные канальные переменные:
Запишите нужные данные в обычные канальные переменные, которые гарантированно будут существовать с момента создания канала.
· Диалплан: exten => _X.,1,Set(MY_SRC=${CDR(src)})
· manager.conf: channelvars = MY_SRC
· Результат: Канальные переменные доступны всегда, поэтому ошибка Unable to find CDR не возникнет.
3. Читать CDR постфактум через БД/файлы:
Если вам не нужны CDR-данные в реальном времени в AMI, самый надежный способ — просто настроить запись CDR в базу данных (MySQL/PostgreSQL) или CSV-файл и получать информацию оттуда после завершения вызова.
Надеюсь, это объяснение помогло прояснить ситуацию. Если останутся вопросы, мы рядом, чтобы помочь.