# Глава 21. Системный мониторинг и журналирование

> Хаос присущ всем сложным вещам. Стремитесь дальше с усердием.
>
> -- Будда

Asterisk поставляется с несколькими подсистемами, которые позволяют получить подробную информацию о работе вашей системы. Как для устранения неполадок, так и для использования в целях выставления счетов или задач персонала, различные модули мониторинга Asterisk могут помочь вам следить за внутренней работой вашей системы.

## logger.conf

При устранении неполадок в системе Asterisk вам будет очень полезно обратиться к некоторым историческим записям того, что происходило в системе в то время, когда произошла указанная проблема. Параметры для хранения этой информации определены в файле _/etc/asterisk/logger.conf_.

В идеале, вы можете захотеть, чтобы система хранила запись каждой вещи что она делает. Однако у этого есть свои издержки. На занятой системе с включенным полным журналированием отладки будет создаваться большой объем данных. Хотя сегодня хранение данных намного дешевле, чем было в молодости Asterisk, возможно, все еще необходимо достичь баланса между детализацией и требованиями к хранению.

Файл _/etc/asterisk/logger.conf_ позволяет определить все виды различных уровней ведения журнала, а также несколько файлов журналов если это необходимо. Эта гибкость превосходна, но она также может сбивать с толку.

Формат записи в файле _logger.conf_ выглядит следующим образом:

```
filename => type[,type[,type[,...]]]
```

Мы уже работали с _logger.conf_, так что у вас уже будут записи в нем, похожие на следующие:

```
[general]
exec_after_rotate=gzip -9 ${filename}.2;

[logfiles]
;debug => debug
;console => notice,warning,error,verbose
console => notice,warning,error,debug
messages => notice,warning,error
full => notice,warning,error,debug,verbose,dtmf,fax
;full-json => [json]debug,verbose,notice,warning,error,dtmf,fax
;syslog keyword : This special keyword logs to syslog facility
;syslog.local0 => notice,warning,error
```

Если вы внесете какие-либо изменения в этот файл, вам нужно будет перезагрузить регистратор, выполнив следующую команду из командной консоли:

```
$ sudo touch full messages
$ chown asterisk:asterisk /var/log/asterisk/*
$ asterisk -rx 'logger reload'
```

или из интерфейса командной строки Asterisk:

```
*CLI> logger reload
```

<table border="1" width="100%" cellpadding="5">
  <tr>
    <td>
      <p align="center"><b>Детальность журналирования: полезно, но опасно</b></p>
      <p>Мы боролись с тем, чтобы рекомендовать добавление следующей строки в ваш файл <i>logger.conf</i>:</p>
      <p><code>verbose => notice,warning,error,verbose</code></p>
      <p>Это, вполне возможно, один из самых полезных инструментов отладки, которые вы имеете при настройке и устранении неисправностей диалплана, и поэтому настоятельно рекомендуется. Опасность заключается в том, что если вы забудете отключить его когда закончите отладку - вы оставите бомбу замедленного действия в своей системе, которая медленно заполнит жесткий диск и однажды убьет вашу систему - через несколько месяцев или лет, когда вы меньше всего этого ожидаете.</p>
      <p>Используйте его. Это просто фантастика. Просто помните, что вам нужно будет управлять своим хранилищем, чтобы гарантировать, что ваши файлы журналов не заполнят весь диск!</p>
    </td>
  </tr>
</table>

Вы можете указать любое имя файла, которое захотите, но специальное имя файла _console_ фактически выведет выходные данные в интерфейс командной строки Asterisk, а не в любой файл на жестком диске. Все остальные имена файлов будут сохранены в файловой системе в каталоге _/var/log/asterisk_. Типы _logger.conf_ описаны в Таблице 21-1.


_Таблица 21-1. Типы logger.conf_

| Тип       | Описание |
| :-------- | :------- |
| `notice`  | Вы увидите много таких во время перезагрузки, но они также будут появляться во время обычного потока вызовов. Уведомление - это просто любое событие, о котором Asterisk хочет Вам сообщить. |
| `warning` | Предупреждение представляет проблему, которая может быть достаточно серьезной чтобы повлиять на вызов (включая обрыв вызова, поскольку поток вызовов не может продолжаться). Предупреждения должны быть устранены. |
| `error`   | Ошибки представляют собой значительные проблемы в системе, которые должны быть решены немедленно. |
| `debug`   | Отладка полезна только в том случае, если вы устраняете неполадки с самим кодом Asterisk. Вы не должны использовать отладку для устранения неполадок вашего диалплана, но можете использовать её, если разработчики Asterisk попросят вас предоставить журналы для проблемы, о которой вы сообщали. Не используйте отладку в продакшене, так как количество предоставляемых деталей, может заполнить жесткий диск в течение нескольких дней.<sup><a href="#snt1-a">a</a></sup> |
| `verbose` | Это один из самых полезных типов ведения журнала, но он также является одним из наиболее рискованных, чтобы оставлять его без присмотра, из-за возможности заполнения выводом вашего жесткого диска.<sup><a href="#snt1-b">b</a></sup> |
| `dtmf`    | Регистрация DTMF может быть полезна если вы получаете жалобы на то, что вызовы не маршрутизируются от автосекретаря правильно. |
| `fax`     | Этот тип ведения журнала вызывает сообщения, связанные с факсом, из серверной части технологии факса (`res_fax_spandsp` или `res_fax_digium`) для регистрации в системе факсов. |
| `*`       | Будет регистрировать все (и мы имеем в виду все). Не используйте его, если не понимаете последствий хранения такого количества данных. Это не закончится хорошо. |

<sup><a name="snt1-a">a</a></sup>Это не теория. Это случилось и с нами и было это совсем невесело.

<sup><a name="snt1-b">b</a></sup>Это не так рискованно, как `debug`, так как займет месяцы, чтобы заполнить жесткий диск, но опасность заключается в том, что это произойдет, скажем, через год, когда вы находитесь на летних каникулах, и сразу не будет очевидно, в чем проблема. Совсем не весело.

<table border="1" width="100%" cellpadding="5">
  <tr>
    <td>
    <p><img src="pics/note.png" height="100" align="left">В системе ведения журнала Asterisk существует особенность, которая вызовет у вас некоторое замешательство, если вы о ней не знаете. Уровень ведения журнала для типов <code>verbose</code> и <code>debug</code> привязаны к детализации, заданной в консоли. Это означает, что если вы ведете журнал типа <code>verbose</code> или <code>debug</code> и кто-то входит в CLI и выдает команду <code>core set verbose 0</code>, или <code>core set debug 0</code> - регистрация этих данных в вашем лог-файле будет остановлена.</p>
    </td>
  </tr>
</table>

### Просмотр журналов Asterisk

Поиск по журнальным файлам может быть проблемой. Хитрость заключается в том, чтобы иметь возможность фильтровать вывод, чтобы выводилась  только та информация, которая имеет отношение к тому, что вы ищете.

Для начала вам нужно иметь приблизительное представление о том, когда произошла неприятность, которую вы ищете. Как только вы сориентируетесь на приблизительное время - вам нужно будет найти подсказки, которые помогут идентифицировать данный звонок. Очевидно, что чем больше информации у вас есть о вызове - тем быстрее вы сможете его зафиксировать.

В Asterisk 11 появилась функция ведения журнала, которая помогает отлаживать определенный вызов. Записи журнала, связанные с вызовом, теперь включают идентификатор вызова. Этот идентификатор вызова можно использовать с командой `grep` чтобы найти все записи журнала, связанные с этим вызовом. В следующем примере записи журнала идентификатором вызова является `C-00000004`:

```
[Dec  4 08:22:32] WARNING[14199][C-00000004]: app_voicemail.c:6286
leave_voicemail: No entry in voicemail config file for '234123452'
```

В более ранних версиях Asterisk есть еще один трюк, который вы можете использовать. Если, например, вы выполняете подробное логирование - следует отметить, что каждый отдельный вызов имеет идентификатор потока, который при использовании с командой `grep`, часто может помочь вам отфильтровать все, что не относится к вызову, который вы пытаетесь отладить. Например, в следующем подробном журнале у нас есть несколько вызовов и поскольку вызовы происходят одновременно, это может оказаться очень запутанным для отслеживания одного вызова:

```
$ tail -1000 verbose
[Mar 11 …] VERBOSE[31362] logger.c:     -- IAX2/shifteight-4 answered Zap/1-1
[Mar 11 …] VERBOSE[2973] logger.c:     -- Starting simple switch on 'Zap/1-1'
[Mar 11 …] VERBOSE[31362] logger.c:   == Spawn extension (shifteight, s, 1)
exited non-zero on 'Zap/1-1'
[Mar 11 …] VERBOSE[2973] logger.c:     -- Hungup 'Zap/1-1'
[Mar 11 …] VERBOSE[3680] logger.c:     -- Starting simple switch on 'Zap/1-1'
[Mar 11 …] VERBOSE[31362] logger.c:     -- Hungup 'Zap/1-1'
```

Чтобы отфильтровать один конкретный вызов - мы могли бы использовать команду grep на ID потока. Например:

```
$ grep 31362 verbose
```

дало бы нам:

```
[Mar 11 …] VERBOSE[31362] logger.c:     -- IAX2/shifteight-4 answered Zap/1-1
[Mar 11 …] VERBOSE[31362] logger.c:   == Spawn extension (shifteight, s, 1)
exited non-zero on 'Zap/1-1'
[Mar 11 …] VERBOSE[31362] logger.c:     -- Hungup 'Zap/1-1'
```

Этот метод не гарантирует, что вы увидите все относящееся к одному вызову, так как вызов может породить дополнительные потоки, но для основной отладки диалплана мы находим этот подход весьма полезным, когда ID вызовов из Asterisk 11 недоступны.

### Журналирование с помощью демона syslog

Linux содержит очень мощный механизм ведения журнала, которым Asterisk может воспользоваться. Хотя обсуждение всех разновидностей syslog и всех возможных способов ведения журнала Asterisk выходит за рамки этой книги - достаточно сказать, что если вы хотите, чтобы Asterisk отправлял журналы демону syslog - вам просто нужно указать следующее в вашем файле _/etc/asterisk/logger.conf_:

```
syslog.local0 => notice,warning,error ; или любой тип(ы), который вы хотите логировать
```

Вам понадобится обозначение в вашем файле конфигурации<sup><a href="#sn21-1">1</a></sup> _syslog_ с именем `local0`, которое должно выглядеть примерно так:

```
local0.*      /var/log/asterisk/syslog
```

<table border="1" width="100%" cellpadding="5">
  <tr>
    <td>
    <p><img src="pics/note.png" height="100" align="left">Вы можете использовать <code>local0</code> через <code>local7</code> для этого, но проверьте свой файл <i>syslog.conf</i> чтобы убедиться, что ничто другое не использует один из этих каналов <code>syslog</code>.</p>
    </td>
  </tr>
</table>

Использование `syslog`<sup><a href="#sn21-2">2</a></sup> позволяет гораздо более мощное ведение журнала, но также требует больше знаний, чем простое логирование Asterisk в файлы. Это в основном будет полезно, если вы уже собираете другие журналы в системе на какой-то централизованный сервер `syslog`.

### Проверка ведения журнала

Вы можете просмотреть состояние всех ваших параметров _logger.conf_ через CLI Asterisk, выполнив команду:

```
*CLI> logger show channels
```

Вы должны увидеть выходные данные, аналогичные:

```
Channel                     Type     Status  Configuration
-------                     ----     ------  -------------
syslog.local0               Syslog   Enabled  - NOTICE WARNING ERROR VERBOSE
/var/log/asterisk/verbose   File     Enabled  - NOTICE WARNING ERROR VERBOSE
/var/log/asterisk/messages  File     Enabled  - NOTICE WARNING ERROR
                            Console  Enabled  - NOTICE WARNING ERROR DTMF=
```

### Ротация лога

Существует некоторая поддержка ротации журналов, встроенная в Asterisk. Ротация логов будет производиться в следующих случаях:

* Если вы запустите команду `logger rotate` в CLI Asterisk:

```
*CLI> logger route
```

* Во время перезагрузки конфигурации, если размер любого существующего файла журнала превышает 1 ГБ
* Если Asterisk получает сигнал `SIGXFSZ`, указывающий на то, что файл, в который он записывался, слишком велик

## Call Detail Records - Записи деталей вызовов

Система CDR в Asterisk используется для регистрации истории вызовов в системе. В некоторых развертываниях эти записи используются для выставления счетов. В других случаях записи вызовов используются для анализа объемов вызовов с течением времени. Они также могут использоваться в качестве средства отладки администраторами Asterisk.

### Содержание CDR

CDR имеет ряд полей, которые включены по умолчанию. _Таблица 21-2_ перечисляет их.

_Таблица 21-2. Поля CDR по умолчанию_

| Вариант       | Значение/пример    | Примечание                   |
| :------------ | :----------------- | :--------------------------- |
| `accountcode` | `12345`            | Идентификатор учетной записи. Это поле определяется пользователем и по умолчанию является пустым. |
| `src`         | `12565551212`      | Идентификационный номер вызывающего абонента. Он устанавливается автоматически и доступен только для чтения. |
| `dst`         | `102`              | Целевой добавочный номер для вызова. Это поле устанавливается автоматически и доступно только для чтения. |
| `dcontext`    | `PublicExtensions` | Контекст назначения для вызова. Это поле устанавливается автоматически и доступно только для чтения. |
| `clid`        | `"Big Bird"`       | Полный идентификатор вызывающего абонента, включая имя вызывающей стороны. Это поле устанавливается автоматически и доступно только для чтения. |
| `channel`     | `SIP/0004F2040808-a1bc23ef` | Канал вызывающей стороны. Это поле устанавливается автоматически и доступно только для чтения. |
| `dstchannel`  | `SIP/0004F2046969-9786b0b0` | Канал вызываемой стороны. Это поле устанавливается автоматически и доступно только для чтения. |
| `lastapp`     | `Dial`             | Последнее выполненное приложение диалплана. Это поле устанавливается автоматически и доступно только для чтения. |
| `lastdata`    | `SIP/0004F2046969,30,tT` | Аргументы, переданные на рассмотрение `lastapp`. Это поле устанавливается автоматически и доступно только для чтения. |
| `start`       | `2010-10-26 12:00:00`  | Время начала вызова. Это поле устанавливается автоматически и доступно только для чтения. |
| `answer`      | `2010-10-26 12:00:15`  | Время ответа на вызов. Это поле устанавливается автоматически и доступно только для чтения. |
| `end`         | `2010-10-26 12:03:15`  | Время окончания вызова. Это поле устанавливается автоматически и доступно только для чтения. |
| `duration`    | `195`                  | Количество секунд, прошедших между началом и концом вызова. Это поле устанавливается автоматически и доступно только для чтения. |
| `billsec`     | `180`                  | Количество секунд между ответом и концом вызова. Это поле устанавливается автоматически и доступно только для чтения. |
| `disposition` | `ANSWER`           | Указание на то, что случилось с вызовом. Это может быть так `NO ANSWER`, `FAILED`, `BUSY`, `ANSWER` или `UNKNOWN`. |
| `amaflags`    | `DOCUMENTATION`  | Флаг автоматического учета сообщений (AMA), связанный с этим вызовом. Может быть одно из следующих действий: `OMIT`, `BILLING`, `DOCUMENTATION` или `Unknown`. |
| `userfield`   | `PerMinuteCharge:0.02` | Поле пользователя общего назначения. Это поле пусто по умолчанию и может быть установлено в пользовательскую строку.<sup><a href="#snt21-2a">a</a></sup> |
| `uniqueid`    | `1288112400.1`  | Уникальный идентификатор для объекта канала `src`. Это поле устанавливается автоматически и доступно только для чтения. |

<sup><a name="snt21-2a">10</a></sup>Поле `userfield` сейчас это не так актуально, как раньше. Пользовательские переменные CDR - более гибкий способ получения пользовательских данных в CDRs.

Вы можете получить доступ ко всем полям записей CDR в диалплане Asterisk с помощью функции `CDR()`. Функция `CDR()` также используется для установки полей CDR, которые определены пользователем:

```
exten => 115,1,Verbose(Call start time: ${CDR(start)})
   same => n,Set(CDR(userfield)=zombie pancakes)
```

В дополнение к полям, которые всегда включены в CDR, можно добавить пользовательские поля. Это можно сделать в диалплане используя прилоежние `Set()` совместно с функцией `CDR()`:

```
exten => 115,1,NoOp()
   same => n,Set(CDR(mycustomfield)=coffee)
   same => n,Verbose(I need some more ${CDR(mycustomfield)})
```

<table border="1" width="100%" cellpadding="5">
  <tr>
    <td>
      <p><img src="pics/note.png" height="100" align="left">Если вы решите использовать пользовательские переменные CDR - убедитесь, что выбранный сервер CDR способен регистрировать их.</p>
    </td>
  </tr>
</table>

Чтобы Просмотреть встроенную документацию для функции `CDR()` - выполните следующую команду в консоли Asterisk:

```
*CLI> core show function CDR
```

В дополнение к функции `CDR()` некоторые приложения диалплана могут использоваться для влияния на записи CDR. Мы еще рассмотрим их.

### Приложения диалплана

Несколько приложений диалплана можно использовать для влияния на CDR текущего вызова. Чтобы получить список приложений CDR, загруженных в текущей версии Asterisk, можно использовать следующую команду CLI:

```
*CLI> core show applications like CDR
    -= Matching Asterisk Applications =-
               ForkCDR: Forks the Call Data Record.
                 NoCDR: Tell Asterisk to not maintain a CDR for the current call
              ResetCDR: Resets the Call Data Record.
    -= 3 Applications Matching =-
```

Каждое приложение имеет документацию, встроенную в Asterisk, которую можно просмотреть с помощью следующей команды:

```
*CLI> core show application <application name>
```

### cdr.conf

Файл _cdr.conf_ имеет a раздел `[general]`, содержащий параметры, применяемые ко всей системе CDR. Дополнительные необязательные разделы могут существовать в этом файле - они применяются к определенным модулям бэкэнда логирования CDR. Таблица 21-3 перечисляет параметры, доступные в разделе `[general]`.

_Таблица 21-3. cdr.conf раздел [general]_

| Параметр     | Значение/пример | Примечание   |
| :----------- | :-------------- | :----------- |
| `enable`     | `yes`           | Включение ведения журнала CDR. Значение по умолчанию: `yes`. |
| `unanswered` | `no`            | Регистрировать неотвеченные звонки. Обычно, только отвеченные вызовы пишутся в CDR. Регистрация всех попыток вызова может привести к большому количеству дополнительных записей вызовов, о которых большинство людей не заботятся. Значение по умолчанию: `no`. |
| `end before hexten` | `no`     | Закройте CDR перед запуском расширения `h` в диалплане Asterisk. Обычно CDR не закрывают до тех пор, пока диалплан не будет полностью завершен. Значение по умолчанию: `no`. |
| `initiated seconds` | `no`     | При расчете поля `billsec` всегда округляется. Например, если разница между временем ответа на вызов и временем его окончания составляет 1 секунду и 1 микросекунду, то `billsec` будет установлен равным 2 секундам. Это помогает гарантировать, что CDR Asterisk совпадает с поведением, используемым телекоммуникационными компаниями. Значение по умолчанию - `no`. |
| `batch`     | `no`             | Очередь записей CDR будет регистрироваться пакетами, а не синхронно в конце каждого вызова. Это предотвращает ведение журнала CDR от блокирования в конце вызова. Использование пакетного режима может быть невероятно полезно при работе с базой данных, которая может медленно обрабатывать запросы. Значение по умолчанию - `no, но мы рекомендуем включить его. <sup><a href="#snt21-3a">a</a></sup> |
| `size`      | `100`            | Количество записей CDR в очереди до их регистрации в пакетном режиме. Значение по умолчанию: `100`. |
| `time`      | `300`            | Установите максимальное количество секунд, в течение которых CDR будет ожидать очереди пакетной обработки перед регистрацией. Процесс пакетного ведения журнала CDR будет запущен в конце этого периода времени, даже если `size` ещё не накопился. Значение по умолчанию: `300` секунд. |
| `sheduler only` | `no`         | Установите, должна ли пакетная обработка CDR выполняться путем порождения нового потока или в контексте планировщика пакетной обработки CDR. Значение по умолчанию: `no`, и мы рекомендуем не менять его. |
| `safe shutdown` | `yes`        | Заблокируйте выключение Asterisk, чтобы убедиться, что все записи CDR из очереди зарегистрированы. Значение по умолчанию: `yes`, и мы рекомендуем оставить его таким, так как этот параметр предотвращает важную потерю данных. |

<sup><a name="snt21-3a">a</a></sup>Недостатком включения этой опции является то, что если Asterisk по какой-либо причине упадет или умрет - записи CDR будут потеряны, так как они хранятся только в памяти существуещего процесса Asterisk. Смотрите `safeshutdown` для дополнительной информации.

### Бэкэнды

Серверные модули Asterisk CDR предоставляют способ регистрации CDR. Большинство бэкендов CDR требуют определенной конфигурации, чтобы заставить их работать.

#### cdr_adaptive_odbc

Как следует из названия, модуль `cdr_adaptive_odbc` позволяет хранить CDR в базе данных через ODBC. "Адаптивная" часть названия относится к тому, что она работает для адаптации к структуре таблицы: нет статической структуры таблицы, которая должна использоваться с этим модулем. Когда модуль загружен (или перезагружен) - он считывает структуру таблицы. При регистрации CDR он ищет переменную CDR, которая соответствует имени каждого столбца. Это относится как ко встроенным переменным CDR, так и к пользовательским. Если вы хотите писать встроенную переменную `channel` - просто создайте столбец с именем `channel`.

Добавление пользовательского содержимого CDR так же просто, как и его настройка в диалплане. Например, если мы хотим записывать `User-Agent`, предоставляемый SIP-устройством - мы могли бы добавить его в качестве пользовательской переменной CDR:

```
exten => 105,n,Set(CDR(useragent)=${CHANNEL(useragent)})
```

Чтобы эта пользовательская переменная CDR была вставлена в базу данных с помощью `cdr_adaptive_odbc`, все, что нам нужно сделать - это создать столбец под названием `useragent`.

Несколько таблиц могут быть указаны в конфигурационном файле `cdr_adaptive_odbc`. Каждая должна быть в своем собственном разделе конфигурации. Название раздела может быть любым - модуль не использует его. Вот пример простой конфигурации таблицы:

```
[mytable]

connection = asterisk
table = asterisk_cdr
```

Более подробный пример настройки базы данных для ведения журнала CDR можно найти в разделе "Хранение записей деталей вызовов”.

Таблица 21-4 перечисляет параметры, которые могут быть указаны в разделе конфигурации таблицы в файле _cdr_adaptive_odbc.conf_.

_Таблица 21-4. cdr_adaptive_odbc.параметры конфигурации таблицы conf_

| Параметр     | Значение/пример | Примечание |
| :----------- | :-------------- | :--------- |
| `connection` | `pgsql1`        | Подключение к используемой базе данных. Это ссылка на настроенное соединение в _res_odbc.conf_. Это поле является обязательным.  |
| `table`      | `asterisk_cdr`  | Имя таблицы. Это поле является обязательным. |
| `usegmtime`  | `no`            | Указывает, следует ли регистрировать метки времени с помощью GMT вместо местного времени. Значением по умолчанию для этого параметра является `no`. |

В дополнение к полям пар ключ/значение, которые показаны в предыдущей таблице - _cdr_adaptive_odbc.conf_ позволяет использовать несколько других элементов конфигурации. Первый - это псевдоним (альяс) столбца. Обычно переменные CDR регистрируются в столбцах с тем же именем. `alias` позволяет сопоставить имя переменной со столбцом с другим именем. Синтаксис таков:

```
alias CDR variable => column name
```

Вот пример сопоставления столбцов с помощью параметра `alias`:

```
alias src => source
```

Также можно задать фильтр содержимого. Это позволяет задать критерии, которые должны совпадать, для записей, вставляемых в таблицу. Синтаксис таков:

```
filter CDR variable => content
```

Вот пример фильтра содержимого:

```
filter accountcode => 123
```

Наконец, _cdr_adaptive_odbc.conf_ позволяет определять статическое содержимое для столбца. Это может быть полезно в сочетании с набором `filters`. Это статическое содержимое может помочь дифференцировать записи, вставленные в одну и ту же таблицу, по различным разделам конфигурации. Синтаксис для статического содержимого является:

```
static "Static Content Goes Here" => column name
```

Ниже приведен пример указания статического содержимого, вставляемого с помощью CDR:

```
static "My Content" => my_identifier
```

#### cdr_csv

Модуль `cdr_csv` - это очень простой сервер CDR, записывающий CDR в файл CSV (значения разделенные запятыми). Этот файл называется _/var/log/asterisk/cdr-csv/Master.csv_. Пока ведение журнала CDR включено в _cdr.conf_ и этот модуль загружен - CDR будут зарегистрированы в файле _Master.csv_. Мы рекомендуем, чтобы независимо от любого другого бэкенда CDR, выбранного Вами для настройки, Вы также оставили настроенным и его, поскольку он будет служить отличной резервной копией, если вы потеряете другие данные CDR из-за сети или связанных с ней проблем.

Хотя для обеспечения работы этого модуля никакие параметры не требуются - есть некоторые параметры, настраивающие его поведение. Эти параметры перечислены в разделе Таблица 21-5 и помещаюися в раздел `[csv]` _cdr.conf_.


_Таблица 21-5. cdr.conf параметры раздела [csv]_

| Параметр | Значение/пример | Примечание  |
| :------- | :-------------- | :---------- |
| `usegmtime` | `no`         | Регистрация меток времени, используя GMT вместо местного времени. Значение по умолчанию: `no`. |
| `loguniqueid` | `no`       | Запись переменной CDR `uniqueid`. Значение по умолчанию: `no`. |
| `loguserfield` | `no`      | Запись переменной CDR `userfield`. Значение по умолчанию: `no`. |
| `accountlogs`  | `yes`     | Создание отдельного CSV-файла для каждого отдельного значения параметра переменной CDR `accountcode`. Значение по умолчанию: `yes`. |

Порядок переменных CDR в CSV файлах, созданных с помощью модуля `cdr_csv`:

```
<accountcode>,<src>,<dst>,<dcontext>,<clid>,<channel>,<dstchannel>,<lastapp>, \
    <lastadata>,<start>,<answer>,<end>,<duration>,<billsec>,<disposition>, \
    <amaflags>[,<uniqueid>][,<userfield>]
```

Поместите следующие строки в файл _/etc/asterisk/cdr.conf_:

```
[general]
enable=yes

[csv]
usegmtime=yes     ; писать время в формате GMT. По умолчанию 'no'
loguniqueid=yes   ; писать uniqueid. По умолчанию 'no'
loguserfield=yes  ; писать пользовательское поле. По умолчанию 'no'
accountlogs=yes   ; создавать отдельный файл журнала для каждой учетной записи. По умолчанию 'yes'
;newcdrcolumns=yes ; включить ведение жунрала в формате столбцов CDR после-1.8 (peeraccount,linkedid,sequence)
                   ; По умолчанию 'no'.
```

Сохраните его, смените владельца и перезагрузите модуль CDR.

```
$ chown asterisk: asterisk /etc/asterisk/cdr.conf
$ sudo asterisk-rx 'module reload cdr'
```

#### cdr_custom

Этот сервер CDR позволяет выполнять пользовательское форматирование записей CDR в файле журнала. Этот модуль наиболее обыкновенно использован для подгоняемого выхода CSV. Файл конфигурации, используемый для этого модуля - это _/etc/asterisk/cdr_custom.conf_. Единственный необходимый раздел `[mappings]` должен существовать в этом файле. Раздел `[mappings]` содержит сопоставления между именем файла и пользовательским шаблоном для CDR. Шаблон задается с помощью функций диалплана Asterisk.

В следующем примере показан пример конфигурации для `cdr_custom` позволяющий использовать один CDR-файл журнала - _Master.csv_. Этот файл будет создан как _/var/log/asterisk/cdr-custom/Master.csv_. Шаблон, который был определен, использует обе функции диалплана `CDR()` и `CSV_QUOTE()`. `CDR()` извлекает значения из регистрируемого CDR-файла. `CSV_QUOTE()` гарантирует что значения правильно экранированы для формата CSV:

```
[mappings]
Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},
${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},
${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},
${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},
${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},
${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},
${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},
${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},
${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})}
```

<table border="1" width="100%" cellpadding="5">
  <tr>
    <td>
    <p><img src="pics/note.png" height="100" align="left">В файле фактической конфигурации, значения для сопоставления в <i>Master.csv</i> должны быть на одной строке.</p>
    </td>
  </tr>
</table>

#### cdr_manager

Бэкэнд `cdr_manager` выдает CDR в виде событий на Asterisk Manager Interface (AMI), который мы подробно обсудили в разделе [Глава 17](glava-17.md). Этот модуль сконфигурирован в файле _/etc/asterisk/cdr_manager.conf_. Первый раздел в этом файле - это `[general]` раздел, который содержит один параметр для включения этого модуля (значение по-умолчанию - `no`):

```
[general]

enabled = yes
```

Другой раздел в _cdr_manager.conf_ - это `[mappings]`. Он позволяет добавлять пользовательские переменные CDR в события менеджера. Синтаксис таков:

```
CDR variable => Header name
```

Вот пример добавления двух пользовательских переменных CDR:

```
[mappings]

rate => Rate
carrier => Carrier
```

С этой конфигурацией на месте, записи CDR появятся как события на интерфейсе менеджера. Чтобы создать пример события менеджера - мы будем использовать следующий пример диалплана:

```
exten => 110,1,Answer()
    same => n,Set(CDR(rate)=0.02)
    same => n,Set(CDR(carrier)=BS&S)
    same => n,Hangup()
```

Эта команда используется для выполнения данного расширения и создания примера события диспетчера:

```
*CLI> console dial 110@testing
```

Наконец, вот пример события менеджера, созданного в результате этого тестового вызова:

```
Event: Cdr
Privilege: cdr,all
AccountCode:
Source:
Destination: 110
DestinationContext: testing
CallerID:
Channel: Console/dsp
DestinationChannel:
LastApplication: Hangup
LastData:
StartTime: 2010-08-23 08:27:21
AnswerTime: 2010-08-23 08:27:21
EndTime: 2010-08-23 08:27:21
Duration: 0
BillableSeconds: 0
Disposition: ANSWERED
AMAFlags: DOCUMENTATION
UniqueID: 1282570041.3
UserField:
Rate: 0.02
Carrier: BS&S
```

#### cdr_odbc

Этот модуль включает устаревший интерфейс ODBC для ведения журнала CDR. Новые установки должны использовать `cdr_adaptive_odbc` вместо него.

#### cdr_sqlite

Этот модуль позволяет отправлять CDR в базу данных SQLite с помощью SQLite версии 2. Если у вас нет особой необходимости в SQLite версии 2 в отличие от версии 3, мы рекомендуем использовать для новых установок `cdr_sqlite3_custom`.

Этот модуль не требует никакой конфигурации для работы. Если модуль был скомпилирован и загружен в Asterisk - он вставит CDR в таблицу под названием `cdr` в базе данных, расположенной по адресу _/var/log/asterisk/cdr.db_.

#### cdr_sqlite3_custom

Этот сервер CDR вставляет CDR в базу данных SQLite с помощью SQLite версии 3. База данных, созданная этим модулем, находится в каталоге _/var/log/asterisk/master.db_. Для этого модуля требуется файл конфигурации _/etc/asterisk/cdr_sqlite3_custom.conf_. Файл конфигурации определяет имя таблицы, а также настраивает, какие переменные CDR будут вставлены в базу данных.

#### cdr_syslog

Этот модуль позволяет вести журнал CDR используя `syslog`. Чтобы включить эту функцию, сначала добавьте запись в файл конфигурации _syslog_ - _/etc/syslog.conf_. Например:

```
local4.*  /var/log/asterisk/asterisk-cdr.log
```

Модуль Asterisk также имеет файл конфигурации. Добавьте следующий раздел в файл _/etc/asterisk/cdr_syslog.conf_:

```
[cdr]

facility = local4
priority = info
template = "We received a call from ${CDR(src)}"
```

Вот пример записи системного журнала, использующего эту конфигурацию:

```
$ cat /var/log/asterisk/asterisk-cdr.log

Aug 12 19:17:36 pbx cdr: "We received a call from 2565551212"
```

### Пример записей деталей вызова

Мы будем использовать модуль `cdr_custom` для иллюстрации некоторых примеров записей CDR для различных сценариев вызовов. Конфигурация, используемая для файла _/etc/asterisk/cdr_custom.conf_ представлена в "[cdr_custom](glava-21.md#cdr_custom)”.

#### Односторонний вызов

В этом примере мы покажем, как выглядит CDR для простого одностороннего вызова:

```
exten => 227,1,VoiceMailMain(@${GLOBAL(VOICEMAIL_CONTEXT)})
```

Вот запись CDR из _/var/log/asterisk/cdr-custom/Master.csv_, которая была создана в результате вызова этого расширения:

```
"","SOFTPHONE_A","227","sets","""101"" <SOFTPHONE_A>","PJSIP/SOFTPHONE_A-00000002",
"","Playback","hear-odd-noise",
"2019-03-04 02:31:39","2019-03-04 02:31:39","2019-03-04 02:31:42",
3,3,"ANSWERED","DOCUMENTATION","1551666699.4",""
```

Откройте его в электронной таблице, и он будет аккуратно выстроен.

### Предостережения

Система CDR в Asterisk очень хорошо работает для довольно простых сценариев вызовов. Однако, поскольку сценарии вызовов становятся более сложными - включая звонки нескольким сторонам, трансферы, парковку и другие подобные функции — система CDR начинает отставать. Многие пользователи сообщают, что записи не отображают всю информацию, которую они ожидают. Многие исправления ошибок были сделаны для решения некоторых проблем, но стоимость регрессий или изменений в поведении при внесении изменений в этой области очень высока, так как эти записи используются для биллинга.

В результате команда разработчиков Asterisk становится все более устойчивой к внесению дополнительных изменений в систему CDR. Вместо этого была разработана новая система, Channel event logging (CEL), которая предназначена для решения проблемы ведения журнала более сложных сценариев вызовов. Имейте в виду, что записи деталей вызовов являются более простыми и легкими в использовании - именно  поэтому мы все еще рекомендуем использовать CDR, если они удовлетворяют вашим потребностям.

## Регистрация событий канала

Регистрация событий канала (CEL) предоставляет более гибкие средства регистрации деталей сложных сценариев вызова. Вместо сворачивания вызова до одной записи журнала регистрируется ряд событий для вызова. Это дает более точную картину того, что произошло с вызовом, за счет более сложного лога.

Для получения более подробной информации о CEL, ознакомьтесь с [wiki Asterisk](https://wiki.asterisk.org).

## Вывод

Asterisk очень хорошо позволяет отслеживать множество различных аспектов его работы - от простых записей детализации вызовов до полной отладки выполняемого кода. Загляните в каталоги исходного кода, и вы найдете гораздо больше компонентов, чем у нас было места для освещения здесь. Эти различные механизмы помогут вам в усилиях по управлению вашей АТС Asterisk и они представляют собой один из способов, которым Asterisk значительно превосходит большинство (если не все) традиционных АТС.

<ol>
  <li id="sn21-1">Который обычно находится в <i>/etc/syslog.conf</i>.</li>
  <li id="sn21-2">И <code>rsyslog</code>, <code>syslog-ng</code> и всего-остального тоже.</li>
</ol>
