Формат CSV и отправка пакета
Формат запроса
Запрос
Маршрут: POST /v2/tasks/{task_id}/logs. Параметр task_id в URL должен быть UUID. Передаётся непосредственно тело CSV, без JSON-обёртки и без multipart-загрузки. Для клиента следует указывать Content-Type: text/csv; charset=utf-8; сам обработчик разбирает тело как CSV и отдельно не проверяет этот заголовок. Авторизация подключена общими зависимостями маршрута v2.
Требования к сериализации:
Кодировка UTF-8. Входной BOM допускается, поскольку используется
utf-8-sig.Строки заголовка нет. Первая строка уже содержит сообщение лога.
В каждой записи строго 11 полей в указанном ниже порядке. Пустые поля не исключаются; пустое последнее поле также должно присутствовать.
Разделитель — запятая
,, символ кавычек — двойная кавычка". Точка с запятой и табуляция не являются альтернативными разделителями.Поле с запятой, кавычками или переводом строки заключается в двойные кавычки. Внутренняя двойная кавычка удваивается:
"превращается в"". Это CSV-экранирование; оно не заменяет экранирование строк внутри JSON.Перевод строки внутри правильно заключённого в кавычки поля допускается. Поэтому физическая строка файла не всегда равна одной записи CSV.
Для формирования пакета клиенту следует использовать LF между записями и завершать последнюю запись переводом строки. Сервер после разбора сам пересобирает пакет с LF и завершающим переводом строки.
Пустые записи и записи, все поля которых пустые или состоят из пробелов, пропускаются. Пакет без содержательных записей отклоняется.
Порядок полей:
id_connector,id_project,id_task,id_line,level,message_id,data,segment,count,timestamp,count_type
Эта строка показывает схему и не включается в тело запроса.
Допустимые level, с учётом регистра:
Emergency Alert Critical Error Warning Notice Informational Debug
Значения Info, INFO, Warn не являются допустимыми заменами. id_log, ecc_dt и is_deleted клиент не передаёт: их назначает загрузчик. timestamp — время сообщения от клиента, ecc_dt — время записи в БД.
Проверка идентификаторов внутри CSV отличается от проверки UUID в URL: текущий CSV-валидатор проверяет непустоту обязательных строк, но не проверяет формат UUID каждого идентификатора, существование проекта или соответствие непустого id_task параметру URL. Клиент должен передавать согласованные идентификаторы. Нельзя считать эти связи подтверждёнными только фактом HTTP 201.
Пустое поле и текст NULL — разные значения. Например, пустой count становится SQL NULL, а строка NULL в count не является числом. JSON null в поле data является JSON-значением и отличается от пустого поля, преобразуемого в SQL NULL.
Пример пакета
Ниже условные идентификаторы, не относящиеся к реальной базе. В обеих записях id_task и id_line пустые. Последняя запятая сохраняет пустое одиннадцатое поле count_type.
11111111-1111-4111-8111-111111111111,22222222-2222-4222-8222-222222222222,,,Informational,log-20261020-000001,"{""text"":""Выгрузка начата""}",,0,2026-10-20T10:15:00+03:00, 11111111-1111-4111-8111-111111111111,22222222-2222-4222-8222-222222222222,,,Error,log-20261020-000002,"{""text"":""Ошибка, требуется повтор""}",,,2026-10-20T10:15:01+03:00,
Пример первой записи после разбора:
{ "id_connector": "11111111-1111-4111-8111-111111111111", "id_project": "22222222-2222-4222-8222-222222222222", "id_task": "значение UUID из URL запроса", "id_line": "", "level": "Informational", "message_id": "log-20261020-000001", "data": {"text": "Выгрузка начата"}, "segment": null, "count": 0, "timestamp": "2026-10-20T10:15:00+03:00", "count_type": null }
Это пояснение содержимого, а не альтернативный формат тела CSV-маршрута.
Проверка пакета и ответы
Весь запрос проверяется до передачи в буфер. Невалидная содержательная запись отклоняет весь входящий пакет: частичного принятия корректных соседних записей нет. Проверяются число колонок, обязательные поля, уровень, JSON, диапазон count и разбираемость timestamp. Максимальный размер тела задаёт V2_MAX_REQUEST_BYTES, по умолчанию 64 МиБ. Лимит числа записей V2_MAX_LOG_BATCH относится к JSON-маршруту; CSV-обработчик его не вызывает.
Ошибки авторизации обрабатываются зависимостями v2 до выполнения приёма. При повторной доставке того же сообщения сохраняется прежний message_id. Ответ 201 CSV-маршрута не содержит подтверждения долговременного хранения каждого message_id.
Отправка из PowerShell
Сохраните пакет из примера в файл logs.csv в UTF-8. Для запроса используйте JWT DCC, полученный при авторизации. Пример читает токен из окружения процесса:
$apiRoot = 'https://dcc.example.ru/api' $taskId = '33333333-3333-4333-8333-333333333333' $headers = @{ Authorization = "Bearer $env:DCC_ACCESS_TOKEN" } Invoke-RestMethod -Method Post ` -Uri "$apiRoot/v2/tasks/$taskId/logs" ` -Headers $headers ` -ContentType 'text/csv; charset=utf-8' ` -InFile '.\logs.csv'
Замените адрес и идентификаторы на значения своей инсталляции. Если публикация не использует /api, уберите этот префикс из apiRoot.
После 201 записи появятся в API чтения логов после обработки очереди. При сетевом таймауте исход приёма неизвестен: повторяйте прежние сообщения с теми же message_id. При 503 учитывайте Retry-After, если он присутствует. При 400 исправьте пакет, при 413 разделите его на меньшие пакеты.
Идентификатор сообщения уникален в пределах коннектора. Повтор с тем же (id_connector, message_id) пропускается при загрузке, а не обновляет ранее записанные данные. Не используйте один идентификатор для разных сообщений.