CSV или JSON — выбирает расширение файла, а не директива

record serialisation
Формат задаётся именем файла

Форматов два, и выбор между ними не настраивается директивой. Его делает расширение в пути блока: .json даёт JSON, любое другое — CSV. Форма с каналом всегда пишет CSV.

CSV — по стандарту RFC 4180, в UTF-8, с заголовочной строкой. Первая колонка всегда вид записи — именно это позволяет держать несколько видов в одном файле. Плата за такую смесь: заголовок несёт все колонки всех выбранных видов, и каждая строка заполняет только свои.

JSON — по объекту на строку, без заголовка, формат NDJSON. Каждая запись самоописательна: в ней присутствуют все настроенные поля, даже пустые. Проблемы общего заголовка нет вовсе.

🔴 Расширение решает и заголовок типа содержимого у вебхука: .json — application/x-ndjson, всё остальное — text/csv. Значит, путь, изменённый по совсем другому поводу, молча меняет формат отправляемых данных, и приёмник сломается на данных, которые выглядят исправными.

Формат меток времени настраивается отдельно — iso-times, и он общий для обоих форматов.

Главная ловушка — смешивать виды записей в одном файле CSV. Заголовок начинает нести все колонки всех видов и растёт при каждом добавлении вида, а каждая строка заполняет лишь свою часть. Разбирающая программа при этом ломается не сразу, а на первом добавлении вида.
Что делает Хаб. Пользуется обоими — и по-разному.

Телеметрия идёт в .json, то есть NDJSON: приёмник разбирает пачку построчно, и каждая запись самоописательна. Расширение здесь часть протокола, а не украшение — в коде конфигуратора это отмечено комментарием, потому что с любым другим расширением придёт CSV и разбирать пачку будет нечем.

Страховочный файл — .csv, с умолчанием по видам (d,b), и смесь двух видов в нём терпима.

Рекомендуемые значения

Собственных значений у механизма нет: формат выбирает путь.

Путь заканчивается на Формат Тип содержимого у вебхука
.json NDJSON, без заголовка application/x-ndjson
что угодно другое CSV с заголовком text/csv
канал CSV —

Переопределить тип содержимого можно только файлом http-webhook-extra-headers.

Оба формата, правило выбора по расширению, заголовочная строка CSV и присутствие пустых полей в JSON — из руководства (§ 12.1.2). Замечание про молчаливую смену формата при правке пути — наше.
Пример в конфигурации
# расширение — часть протокола, а не украшение
<acct-file /var/log/pmta/mtahub-webhook.json>    records d, b, rb, t, feedback-loop
    http-webhook-url https://hub.example.com/api/telemetry/pmta/7
</acct-file>
Замените .json на .log — и приёмник получит CSV с типом text/csv вместо NDJSON. Конфигурация при этом останется синтаксически верной.
жёлтым — — имена директив, голубым — блоки. Так же они подсвечены и в тексте карточки.
▲

Типичные ошибки и проблемы

что делают не так и чем это кончается2 ошибки▶

Меняют путь файла и молча меняют формат

наш опыт

Чем чреватоРасширение решает и формат, и заголовок типа содержимого. Правка пути по совсем другому поводу ломает разбор на стороне приёмника, а конфигурация остаётся верной.
Как заметитьПриёмник отвечает ошибкой разбора сразу после правки пути.
Как правильноСчитать расширение частью протокола и отмечать это комментарием в самой конфигурации.

Держат много видов записей в одном файле CSV

§ 12.1.2.2

Чем чреватоЗаголовок несёт все колонки всех выбранных видов и растёт при добавлении каждого нового. Строки заполняют только свою часть, и разбирающая программа ломается на первом же добавлении.
Как заметитьВ заголовке десятки колонок, а в строках заполнена треть.
Как правильноРазвести виды по файлам либо перейти на формат JSON, где такой проблемы нет.
Совместимость
PowerMTA 6.0
описана в руководстве этой версии · платформа: любая
С какой версии директива доступна, вендор указывает не для всех — здесь пометки нет. Имя встречается и в издании руководства 5.0.
Наследование
Наследования у механизма нет: формат — свойство пути в каждом блоке <acct-file> по отдельности. Один и тот же поток событий можно писать в двух блоках разными форматами.
Как проверить на узле
Формат виден в первой строке файла:
head -1 "$(ls -t /var/log/pmta/acct-*.csv | head -1)"
Строка вида type,timeLogged,rcpt,… — это заголовок CSV. Строка, начинающаяся с фигурной скобки, — NDJSON. Для вебхука тип содержимого проверяют со стороны приёмника, в журнале его веб-сервера.
В Хабе
Цена ошибки
обратимо: вредит, пока стоит
Сценарии
Собрать телеметрию