154 lines
22 KiB
Plaintext
154 lines
22 KiB
Plaintext
Отличная ошибка! Вы столкнулись с особенностью языка VRL (Vector Remap Language) — он fail-safe (отказоустойчивый). Это значит, что программа не скомпилируется, если в ней есть хотя бы один необработанный потенциальный сбой. Ошибка 103 говорит именно об этом: выражение merge(., parsed) может упасть, и вы должны явно указать, что делать в случае ошибки.
|
||
|
||
Вот исправленная секция transforms для вашего vector.yaml, которая учитывает все возможные проблемы:
|
||
|
||
```yaml
|
||
transforms:
|
||
add_nomad_metadata:
|
||
type: remap
|
||
inputs: ["docker_logs"]
|
||
source: |-
|
||
# 1. БЕЗОПАСНО добавляем метаданные Nomad (они всегда есть)
|
||
.nomad = {
|
||
"job_id": "${NOMAD_JOB_ID}",
|
||
"job_name": "${NOMAD_JOB_NAME}",
|
||
"task_name": "${NOMAD_TASK_NAME}",
|
||
"alloc_id": "${NOMAD_ALLOC_ID}",
|
||
"node_id": "${NOMAD_NODE_ID}",
|
||
"node_name": "${NOMAD_NODE_NAME}",
|
||
"datacenter": "${NOMAD_DC}"
|
||
}
|
||
|
||
# 2. БЕЗОПАСНО парсим JSON, ЕСЛИ поле .message - строка
|
||
if is_string(.message) {
|
||
# Пытаемся распарсить. В случае ошибки parsed будет null, а err - описанием ошибки.
|
||
parsed, err = parse_json(.message)
|
||
|
||
if err == null {
|
||
# Если парсинг прошел успешно И результат - объект (не массив, не строка)
|
||
if is_object(parsed) {
|
||
# Используем "паникующий" merge! потому что мы УВЕРЕНЫ в типах на 100%
|
||
# . - это объект (весь лог), parsed - тоже объект (результат парсинга)
|
||
. = merge!(., parsed)
|
||
} else {
|
||
# Если внутри .message был валидный JSON, но это массив или строка,
|
||
# сохраняем его в отдельное поле, чтобы не сломать структуру.
|
||
.parsed_json = parsed
|
||
}
|
||
} else {
|
||
# Логируем ошибку парсинга (опционально, для отладки)
|
||
.parse_error = err
|
||
}
|
||
}
|
||
|
||
# 3. (Опционально) Удаляем временное поле с ошибкой, если оно пустое
|
||
if is_null(.parse_error) {
|
||
del(.parse_error)
|
||
}
|
||
```
|
||
|
||
🔍 Что было исправлено и почему
|
||
|
||
1. Ошибка 103 (Unhandled fallible assignment) — исправлена заменой merge(., parsed) на конструкцию с обработкой ошибки. Теперь программа не "упадет", если parsed окажется не объектом.
|
||
2. Проверка типа parsed — добавлена проверка if is_object(parsed). Функция parse_json может вернуть не только объект ({...}), но и массив ([...]), строку или число, если JSON верхнего уровня — это примитив или массив. Слияние (merge) работает только с объектами. Без этой проверки вы бы получили новую ошибку на этапе выполнения.
|
||
3. Использование merge! — внутри блока if is_object(parsed) мы на 100% уверены, что parsed — это объект, а . (исходный лог) — всегда объект. Поэтому можно использовать "паникующий" вариант merge!, который не требует обработки ошибок (так как их просто не может быть из-за наших проверок).
|
||
4. Обработка краевых случаев:
|
||
· Если поле message не строка — JSON не парсится (это нормально для бинарных логов).
|
||
· Если внутри message был JSON-массив (например, ["log1", "log2"]), он сохранится в поле .parsed_json, а структура основного события не сломается.
|
||
· Если произошла ошибка парсинга, она сохранится в поле .parse_error (потом удаляется для чистоты).
|
||
|
||
📝 Полный исправленный конфиг для вашего шаблона Nomad
|
||
|
||
Замените содержимое вашего template в задании Nomad на этот исправленный YAML:
|
||
|
||
```yaml
|
||
data_dir: "${NOMAD_ALLOC_DIR}/vector/data"
|
||
|
||
api:
|
||
enabled: true
|
||
address: "0.0.0.0:${NOMAD_PORT_api}"
|
||
|
||
sources:
|
||
docker_logs:
|
||
type: docker_logs
|
||
include_containers: ["*"]
|
||
|
||
transforms:
|
||
add_nomad_metadata:
|
||
type: remap
|
||
inputs: ["docker_logs"]
|
||
source: |-
|
||
.nomad = {
|
||
"job_id": "${NOMAD_JOB_ID}",
|
||
"job_name": "${NOMAD_JOB_NAME}",
|
||
"task_name": "${NOMAD_TASK_NAME}",
|
||
"alloc_id": "${NOMAD_ALLOC_ID}",
|
||
"node_id": "${NOMAD_NODE_ID}",
|
||
"node_name": "${NOMAD_NODE_NAME}",
|
||
"datacenter": "${NOMAD_DC}"
|
||
}
|
||
|
||
if is_string(.message) {
|
||
parsed, err = parse_json(.message)
|
||
|
||
if err == null {
|
||
if is_object(parsed) {
|
||
. = merge!(., parsed)
|
||
} else {
|
||
.parsed_json = parsed
|
||
}
|
||
} else {
|
||
.parse_error = err
|
||
}
|
||
}
|
||
|
||
if is_null(.parse_error) {
|
||
del(.parse_error)
|
||
}
|
||
|
||
sinks:
|
||
openobserve:
|
||
type: http
|
||
inputs: ["add_nomad_metadata"]
|
||
uri: "http://openobserve.service.consul:5080/api/default/default/_json"
|
||
method: "post"
|
||
compression: "gzip"
|
||
encoding:
|
||
codec: "json"
|
||
timestamp_format: "rfc3339"
|
||
auth:
|
||
strategy: "basic"
|
||
user: "{{ key "openobserve/user" }}"
|
||
password: "{{ key "openobserve/password" }}"
|
||
buffer:
|
||
type: "disk"
|
||
max_size: 268435488
|
||
when_full: "drop_newest"
|
||
healthcheck:
|
||
enabled: false
|
||
```
|
||
|
||
🚀 После исправления
|
||
|
||
1. Перезапустите задание:
|
||
```bash
|
||
nomad job stop vector
|
||
nomad job run vector.nomad
|
||
```
|
||
2. Проверьте логи: Ошибка компиляции VRL должна исчезнуть. В OpenObserve будут приходить обогащенные логи, а если внутри message был валидный JSON, его поля "поднимутся" на верхний уровень события для удобной фильтрации.
|
||
|
||
Такой подход делает трансформацию устойчивой к любым нестандартным данным в логах, что критически важно для production-сред.
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} |