ansible_playbooks/roles/filebeat_install/templates/filebeat.yml.j2
2026-02-24 11:30:35 +03:00

472 lines
16 KiB
Django/Jinja
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

filebeat.inputs:
- type: log
enabled: true
id: nginx-access
paths:
- /var/log/ptaf_nginx/*/*/*access.log
- /var/log/ptaf_nginx/*/*/*access.log.1
json:
keys_under_root: true
overwrite_keys: true
add_error_key: true
fields:
log_type: access
fields_under_root: true
- type: filestream
id: nginx-error
enabled: true
paths:
- /var/log/ptaf_nginx/*/*/*error.log
- /var/log/ptaf_nginx/*/*/*error.log.1
fields:
log_type: "error"
fields_under_root: true
- type: filestream
id: angie-error
enabled: true
paths:
- /var/log/angie/*error.log
- /var/log/angie/*error.log.1
fields:
log_type: "angie-error"
fields_under_root: true
setup.ilm.enabled: false
setup.template.enabled: false
setup.template.name: "ptaf"
setup.template.pattern: "ptaf-*"
# Отключаем автоматическое создание индексов
setup.dashboards.enabled: false
output.elasticsearch:
enabled: true
# Array of hosts to connect to.
hosts: ["https://10.10.10.23:9200", "https://10.10.10.24:9200"]
username: "vector"
password: {{ filebeat_install_filebeat_password }}
#Вывод в консоль
#output.console:
# codec.json:
# pretty: true
#SSL configuration for HTTPS
ssl:
verification_mode: none # Отключаем проверку сертификата
# Индексы для разных типов логов
indices:
- index: "ptaf-access-%{+yyyy.MM.dd}"
when:
equals:
log_type: "access"
- index: "ptaf-error-%{+yyyy.MM.dd}"
when:
equals:
log_type: "error"
- index: "ptaf-angie-error-%{+yyyy.MM.dd}"
when:
equals:
log_type: "angie-error"
seccomp:
enabled: false
processors:
- script:
lang: javascript
source: |
function process(event) {
// Обработка upstream_response_time
var responseTime = event.Get("upstream_response_time");
if (responseTime && typeof responseTime === 'string') {
var values = responseTime.split(",");
if (values.length > 0) {
var lastValue = values[values.length - 1].trim();
var numValue = parseFloat(lastValue);
if (!isNaN(numValue)) {
event.Put("upstream_response_time_digital", numValue);
}
}
}
// Обработка upstream_status
var upstreamStatus = event.Get("upstream_status");
if (upstreamStatus && typeof upstreamStatus === 'string') {
var statusValues = upstreamStatus.split(",");
if (statusValues.length > 0) {
var lastStatus = statusValues[statusValues.length - 1].trim();
var intStatus = parseInt(lastStatus, 10);
if (!isNaN(intStatus)) {
event.Put("upstream_status_digital", intStatus);
}
}
}
// Обработка upstream_response_length
var responseLength = event.Get("upstream_response_length");
if (responseLength && typeof responseLength === 'string') {
var lengthValues = responseLength.split(",");
if (lengthValues.length > 0) {
var lastLength = lengthValues[lengthValues.length - 1].trim();
var intLength = parseInt(lastLength, 10);
if (!isNaN(intLength)) {
event.Put("upstream_response_length_digital", intLength);
}
}
}
// Обработка upstream_bytes_sent (ДОБАВЛЕНО)
var bytesSent = event.Get("upstream_bytes_sent");
if (bytesSent && typeof bytesSent === 'string') {
var bytesValues = bytesSent.split(",");
if (bytesValues.length > 0) {
var lastBytes = bytesValues[bytesValues.length - 1].trim();
var intBytes = parseInt(lastBytes, 10);
if (!isNaN(intBytes)) {
event.Put("upstream_bytes_sent_digital", intBytes);
}
}
}
}
- drop_fields:
fields: ["agent","ecs.version","log.offset","input.type","type"]
ignore_missing: true
- dissect:
tokenizer: "/var/log/ptaf_nginx/%{TENANT}/%{}"
field: "log.file.path"
target_prefix: ""
- rename:
fields:
- from: "host.name"
to: "node_name"
ignore_missing: true
fail_on_error: false
# Процессор для составной переменной agent_name
- script:
lang: javascript
source: |
function process(event) {
var tenant = event.Get("TENANT");
var nodeName = event.Get("node_name");
var logPath = event.Get("log.file.path");
if (!tenant || !nodeName || !logPath) return;
// Извлекаем AZ часть
var azMatch = nodeName.match(/(AZ\d+)/);
var azPart = azMatch ? azMatch[1] : "AZ0";
// Извлекаем имя хоста (последняя часть после дефиса)
var parts = nodeName.split('-');
var nodePart = parts[parts.length - 1];
// Извлекаем agent (ищем "ptaf-agent001")
var agentName = "agent000";
var agentMatch = logPath.match(/ptaf-(agent\d+)/);
if (agentMatch) {
agentName = agentMatch[1];
}
// Преобразуем nodePart: test01 → t01
var shortNodePart = "t00";
if (nodePart) {
// Ищем первую букву и цифры
var nodeMatch = nodePart.match(/^([a-zA-Z])[a-zA-Z]*(\d+)$/);
if (nodeMatch) {
var letter = nodeMatch[1]; // первая буква
var digits = nodeMatch[2]; // цифры
shortNodePart = letter.toLowerCase() + digits;
} else {
// Если не нашли буквы, берем только цифры
var digitsOnly = nodePart.match(/(\d+)/);
if (digitsOnly) {
shortNodePart = "t" + digitsOnly[1];
}
}
}
// Преобразуем agentName: agent001 → a001
var shortAgentName = "a000";
if (agentName) {
// Ищем первую букву и цифры
var agentMatch = agentName.match(/^([a-zA-Z])[a-zA-Z]*(\d+)$/);
if (agentMatch) {
var letter = agentMatch[1]; // первая буква
var digits = agentMatch[2]; // цифры
shortAgentName = letter.toLowerCase() + digits;
} else {
// Если не нашли буквы, берем только цифры
var digitsOnly = agentName.match(/(\d+)/);
if (digitsOnly) {
shortAgentName = "a" + digitsOnly[1];
}
}
}
// Создаем composite_id в новом формате
event.Put("agent_name", tenant + "_" + azPart + "_" + shortNodePart + "_" + shortAgentName);
}
ignore_failure: true
# Процессор для nginx-error: парсинг timestamp из сообщения
- dissect:
tokenizer: "%{error_timestamp} [%{log_level}] %{rest}"
field: "message"
target_prefix: ""
ignore_failure: true
when:
equals:
log_type: "error"
# Преобразование timestamp для nginx-error
- timestamp:
field: "error_timestamp"
layouts:
- "2006-01-02 15:04:05.000"
timezone: "Europe/Moscow"
target_field: "@timestamp"
ignore_failure: true
when:
equals:
log_type: "error"
# Удаление временных полей для nginx-error
- drop_fields:
fields: ["error_timestamp", "log_level", "rest"]
ignore_missing: true
when:
equals:
log_type: "error"
- drop_fields:
fields: ["agent","ecs.version","log.offset","input.type","type"]
ignore_missing: true
- dissect:
field: "log.file.path"
tokenizer: '/var/log/angie/%{extracted_sid}_%{rest}'
target_prefix: ""
overwrite_keys: false # Не перезаписывать существующие поля
ignore_failure: true
# 2. Копируем extracted_sid в SID, если SID не существует
- script:
lang: javascript
source: |
function process(event) {
var extractedSid = event.Get("extracted_sid");
var existingSid = event.Get("SID");
// Если SID уже существует, оставляем его
if (existingSid !== null && existingSid !== undefined && existingSid !== "") {
// Удаляем временное поле extracted_sid
event.Delete("extracted_sid");
return;
}
// Если извлекли SID из пути и SID еще не существует
if (extractedSid && !existingSid) {
event.Put("SID", extractedSid);
// Удаляем временное поле
event.Delete("extracted_sid");
}
}
ignore_failure: true
# 3. Удаляем временное поле rest
- drop_fields:
fields: ["rest"]
ignore_missing: true
# Процессор для angie-error: парсинг timestamp из сообщения
# 1. Первичный разбор error-лога с помощью dissect
- dissect:
when:
and:
- equals:
log_type: "angie-error"
- contains:
message: "client:"
field: "message"
tokenizer: '%{error_date} %{error_time} [%{error_level}] %{pid_worker}: *%{connection_id} %{rest}'
target_prefix: "error"
overwrite_keys: true
ignore_failure: true
# 2. Расширенная обработка оставшейся части в script
- script:
when:
and:
- equals:
log_type: "angie-error"
- has_fields: ['error.rest']
lang: javascript
source: |
function process(event) {
var rest = event.Get("error.rest");
if (!rest) return;
// Разделяем текст ошибки и дополнительные поля
// Ищем первое вхождение ", client:" чтобы отделить текст ошибки
var clientIndex = rest.indexOf(", client:");
if (clientIndex === -1) {
// Если нет client:, значит это простое сообщение
event.Put("error.message_text", rest);
return;
}
// Извлекаем текст ошибки (все до ", client:")
var errorMessage = rest.substring(0, clientIndex);
event.Put("error.message_text", errorMessage.trim());
// Извлекаем ключ-значение пары
var kvString = rest.substring(clientIndex + 2); // +2 чтобы пропустить ", "
// Разбираем пары ключ:значение
parseKeyValuePairs(kvString, event);
// Дополнительно разбираем PID#worker
var pidWorker = event.Get("error.pid_worker");
if (pidWorker && pidWorker.includes("#")) {
var parts = pidWorker.split("#");
event.Put("error.pid", parts[0]);
event.Put("error.worker", parts[1]);
}
}
// Функция для разбора строки с key:value парами
function parseKeyValuePairs(kvString, event) {
var regex = /(\w+):\s*(?:"([^"]*)"|([^,]*))/g;
var match;
var fields = {};
while ((match = regex.exec(kvString)) !== null) {
var key = match[1];
var value = match[2] || match[3];
// Очищаем значение от лишних пробелов
if (value) {
value = value.trim();
}
// Сохраняем поле с соответствующим префиксом
var fieldName = "error." + key;
event.Put(fieldName, value);
}
}
ignore_failure: true
# 3. Для notice логов (без полей client, server и т.д.)
- dissect:
when:
and:
- equals:
log_type: "angie-error"
- not:
contains:
message: "client:"
field: "message"
tokenizer: '%{error_date} %{error_time} [%{error_level}] %{pid_worker}: %{error_message}'
target_prefix: "error"
overwrite_keys: true
ignore_failure: true
# 4. Создание единого поля datetime
- script:
when:
equals:
log_type: "angie-error"
lang: javascript
source: |
function process(event) {
var date = event.Get("error.error_date");
var time = event.Get("error.error_time");
if (date && time) {
// Преобразуем дату из 2026/01/29 в 2026-01-29
var isoDate = date.replace(/\//g, "-");
// Создаем строку в формате ISO 8601
var dateTime = isoDate + "T" + time;
event.Put("error.datetime", dateTime);
}
}
ignore_failure: true
# 5. Установка timestamp из лога
- timestamp:
when:
equals:
log_type: "angie-error"
field: "error.datetime"
layouts:
- "2006-01-02T15:04:05"
timezone: "Europe/Moscow"
ignore_failure: true
# 6. Дополнительная обработка специальных полей
- script:
when:
and:
- equals:
log_type: "angie-error"
- has_fields: ['error.request']
lang: javascript
source: |
function process(event) {
// Разбираем поле request на метод, путь и версию
var request = event.Get("error.request");
if (request) {
var parts = request.split(" ");
if (parts.length >= 3) {
event.Put("error.http_method", parts[0]);
event.Put("error.http_path", parts[1]);
event.Put("error.http_version", parts[2].replace("HTTP/", ""));
}
}
// Разбираем upstream URL
var upstream = event.Get("error.upstream");
if (upstream && upstream.startsWith("http")) {
try {
var url = upstream.match(/^(\w+):\/\/([^:/]+)(?::(\d+))?(\/.*)?$/);
if (url) {
event.Put("error.upstream_protocol", url[1]);
event.Put("error.upstream_host", url[2]);
event.Put("error.upstream_port", url[3] || "80");
event.Put("error.upstream_path", url[4] || "/");
}
} catch(e) {
// Игнорируем ошибки парсинга
}
}
}
ignore_failure: true
# 7. Удаление промежуточных полей
- drop_fields:
when:
equals:
log_type: "angie-error"
fields: [
"error_date", "error_time", "error.error_date", "error.error_time",
"error.datetime", "error.rest", "error.pid_worker",
"error.request", "error.message", "tags"
]
ignore_missing: true
# Общий drop_fields для всех логов
- drop_fields:
fields: ["agent","ecs.version","log.offset","input.type","type","log.flags"]
ignore_missing: true
...