Подключение данных логов к трассировкам
Подключение данных журналов к трассировкам (Logs Classic)
Ключ-АСТРОМ может обогатить ваши загруженные данные журналов дополнительной информацией, которая помогает Ключ-АСТРОМ распознавать, сопоставлять и оценивать данные. Обогащение данных журналов приводит к более точному анализу ваших журналов.
Обогащение логов позволяет вам:
- Легко переключаться между контекстами и анализировать отдельные фрагменты кода, транзакции или целые рабочие нагрузки.
- Расширьте возможности команд разработчиков, упростив и ускорив процесс выявления и определения проблем.
Автоматическое обогащение журналов
Вы можете включить обогащение логов для конкретной технологии, используемой для создания данных логов, и позволить Ключ-АСТРОМ автоматически добавлять дополнительные атрибуты в каждую полученную запись лога. Этот метод рекомендуется для структурированных данных логов известных технологий.
Ограничение логарифмического обогащения
Используйте функцию переопределения группы процессов, чтобы ограничить обогащение журналов определенной группой процессов или процессом внутри группы процессов.
Включение/отключение обогащения журналов для конкретной технологии
Чтобы включить обогащение логов для конкретной технологии, можно использовать один из следующих подходов:
В глобальном масштабе
- Перейдите в Настройки > Предпочтения > Функции ЕдиногоАгента.
- Фильтр для обогащения.
- Включайте/отключайте каждый этап обогащения логов для каждой технологии, которую вы используете для генерации входных данных логов.
- Нажмите Сохранить изменения, чтобы сохранить конфигурацию.
Переопределение группы процессов в ЕдиномАгенте
- Откройте нужную группу процессов.
- Выберите Дополнительно (…) > Функции ЕдиногоАгента.
- Фильтр для обогащения.
- Включайте/отключайте каждый этап обогащения логов для каждой технологии, которую вы используете для генерации входных данных логов.
- Нажмите Сохранить изменения, чтобы сохранить конфигурацию.
Пространство имен Kubernetes
- Перейдите в раздел Наблюдение за инфраструктурой > Kubernetes.
- Выберите значение Namespaces для вашего кластера Kubernetes.
- Выберите интересующую вас запись в пространстве имен Kubernetes.
- В левом верхнем углу страницы перейдите в раздел Дополнительно (…) > Настройки > Функции ЕдиногоАгента.
- Выберите Добавить переопределение.
- Выберите технологию обогащения логов из раскрывающегося списка Функция и убедитесь, что переключатель Переопределение функции включен.
- Выберите Сохранить и закрыть.
Что делает автоматическое обогащение логов?
Функция обогащения логов изменяет полученные данные логов и добавляет следующую информацию к каждой обнаруженной записи лога:
dt.trace_iddt.span_iddt.entity.process_group_instance
Поддерживаемые платформы
Чтобы ознакомиться со списком поддерживаемых фреймворков для обогащения контекста журналов трассировки/пространства, перейдите в раздел «Техническая поддержка».
Структурированные данные журнала
Для структурированных данных журналов, таких как JSON, XML и общепринятые текстовые форматы, Ключ-АСТРОМ добавляет поле атрибута к записи журнала.
Пример обогащенных данных журнала в формате JSON.
Данные журнала в формате JSON обогащаются дополнительными свойствами <dt.trace_id>, <dt.span_id>, и dt.entity.process_group_instance.
{
"severity": "error",
"time": 1638957438023,
"pid": 1,
"hostname": "paymentservice-788946fdcd-42lgq",
"name": "paymentservice-charge",
"dt.trace_id": "d04b42bc9f4b6ecdbf6bc9f4b6ecdbc",
"dt.span_id": "9adc716eb808d428",
"dt.entity.process_group_instance": "PROCESS_GROUP_INSTANCE-27204EFED3D8466E",
"message": "Неподдерживаемый тип карты для cardNumber=************0454"
}
Пример обогащенных данных журнала в формате XML.
Данные журнала в формате XML дополняются дополнительными узлами <dt.trace_id>, <dt.span_id>, и <dt.entity.process_group_instance>.
<?xml version="1.0" encoding="windows-1252" standalone="no"?>
<record>
<date>2021-08-24T14:41:36.565218700Z</date>
<millis>1629816096565</millis>
<nanos>218700</nanos>
<sequence>0</sequence>
<logger>com.apm.testapp.logging.jul.XMLLoggingSample</logger>
<level>INFO</level>
<class>com.apm.testapp.logging.jul.BaseLoggingSample</class>
<method>info</method>
<thread>1</thread>
<message>Update successfully completed.</message>
<dt.trace_id>513fcd4e9b08792fcd4e9b08792</dt.trace_id>
<dt.span_id>125840e3125840e3</dt.span_id>
<dt.entity.process_group_instance>PROCESS_GROUP_INSTANCE-27204EFED3D8466E</dt.entity.process_group_instance>
</record>
Неструктурированные данные журналов
Перед использованием автоматического обогащения неструктурированных данных журналов проверьте, влияет ли функция обогащения журналов Ключ-АСТРОМ на существующий конвейер обработки данных журналов.
Неструктурированные данные журналов обычно представляют собой необработанный текст в простой текстовой форме, упорядоченный последовательно и предназначенный для чтения людьми. Ключ-АСТРОМ не обогащает неструктурированные данные журналов автоматически. Ключ-АСТРОМ способен обогащать неструктурированные данные журналов, но добавление дополнительной информации к данным журналов может повлиять на работу сторонних инструментов, которые обрабатывают эти же данные.
Пример обогащенных данных журнала в формате необработанного текста.
Данные журнала в необработанном текстовом виде дополняются дополнительной строкой [!dt dt.trace_id=$trace_id, dt.span_id=$span_id, dt.entity.process_group_instance=$dt.entity.process_group_instance] (атрибутами и их значениями).
127.0.0.1 - [21/Oct/2021:10:33:28 +0200] GET /index.htm HTTP/1.1 404 597 [!dt dt.trace_id=aa764ee37ebaa764ee37eaa764ee37e,dt.span_id=b93ede8b93ede8, dt.entity.process_group_instance=PROCESS_GROUP_INSTANCE-27204EFED3D8466E]
Обогащение журналов вручную
Версия ЕдиногоАгента 1.239+
Вы можете вручную обогатить данные журналов, поступающие в Ключ-АСТРОМ, определив шаблон журнала, включающий поля dt.span_id, dt.trace_id, dt.trace_sampled, и dt.entity.process_group_instance. Вы можете включить ручное обогащение журналов для конкретной технологии, выполнив действия, описанные в разделе «Обогащение журналов».
Обязательно соблюдайте следующие правила форматирования обогащенных полей в неструктурированном журнале:
- Поля должны быть заключены в квадратные скобки (
[]) с префиксом!dt. Например,[!dt dt.trace_id=$dt_trace_id,dt.span_id=$dt_span_id, dt.entity.process_group_instance=$dt.entity.process_group_instance]. - Поля должны быть отформатированы без двойных кавычек.
- Все недопустимые символы в поле и его значении должны быть экранированы.
- Любые управляющие символы, подобные
\n, должны быть исключены из определения обогащения.
Пример ручного обогащения данных журнала NGINX
Предположим, вы хотите вручную обогатить данные логов NGINX с помощью переменных dt.trace_id, dt.span_id и dt.trace_sampled. Файл конфигурации NGINX содержит множество стандартных переменных NGINX, поэтому определение формата логов должно находиться в разделе log_format.
log_format custom '$remote_addr - [$time_local] $request $status $body_bytes_sent [!dt dt.trace_id=$dt_trace_id,dt.span_id=$dt_span_id,dt.trace_sampled=$dt_trace_sampled]'; access_log logs/access.log custom;
Переменные $dt_trace_id, $dt_span_id, и $dt_trace_sampled внедряются ЕдинымАгентом во время выполнения. Если ЕдиныйАгент не сможет их внедрить, например, из-за неработающей инструментации или использования более старой версии ЕдиногоАгента, которая не поддерживает эту функцию, то команды проверки конфигурации NGINX, такие как nginx -t и nginx -s reload, завершатся с ошибкой. Это не влияет на работающий экземпляр NGINX и не является проблемой в производственной среде. В случае возникновения проблем обратитесь в службу поддержки Ключ-АСТРОМ.
В результате будет получен файл access.log, содержащий обогащенные записи журнала:
127.0.0.1 - [22/Mar/2022:08:50:45 +0100] GET /index.htm HTTP/1.1 200 30 [!dt dt.trace_id=b9e5c9ec08be5fab5071d76f427be7da,dt.span_id=43c5bb9432593963,dt.trace_sampled=true] 127.0.0.1 - [22/Mar/2022:08:50:45 +0100] GET /index.htm HTTP/1.1 200 30 [!dt dt.trace_id=01e52950b145d97bf22345e68c5e6c58,dt.span_id=de819d856eecb236,dt.trace_sampled=true]
Для версий ЕдиногоАгента 1.237 и более ранних используются другие переменные NGINX. Например:
log_format custom '$remote_addr - [$time_local] $request $status $body_bytes_sent [!dt dt.trace_id=$trace_id,dt.span_id=$span_id]'; access_log logs/access.log custom
В результате будет получен файл access.log, содержащий обогащенные записи журнала:
127.0.0.1 - [21/Oct/2021:10:33:28 +0200] GET /index.htm HTTP/1.1 404 597 [!dt dt.trace_id=e1c0afeb0b8a91d7748139aa764ee37e,dt.span_id=e5e6748fab93ede8] 127.0.0.1 - [21/Oct/2021:10:33:31 +0200] GET /index.html HTTP/1.1 200 1056 [!dt dt.trace_id=81fe7816ba6c38f7aa09aef3684cd941,dt.span_id=3bdacc466ae073cd]
Пример ручного обогащения данных логов Log4j
В Log4j PatternFormatter можно указать следующий шаблон для включения информации, обогащенной данными Ключ-АСТРОМ:
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} dt.trace_id=%X{dt.trace_id} dt.span_id=%X{dt.span_id} dt.entity.process_group_instance=%X{dt.entity.process_group_instance} - %msg%n" />
Пример ручного обогащения данных в кодировщике Logstash Logback
Logback — это преемник проекта log4j. Logstash Logback — это расширение, предоставляющее кодировщики, макеты и аппендеры Logback для записи логов в формате JSON и других форматах, поддерживаемых Jackson.
Ниже приведён пример ручного обогащения с использованием кодировщика Logstash. Обратите внимание на дополнительное свойство mdc в файле конфигурации, где можно указать переменные MDC.
<appender name="COMPOSITEJSONENCODER" class="ch.qos.logback.core.FileAppender">
<file>compositejsonencoder.log</file>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<fieldName>timestamp</fieldName>
<timeZone>UTC</timeZone>
</timestamp>
<loggerName>
<fieldName>logger</fieldName>
</loggerName>
<logLevel>
<fieldName>level</fieldName>
</logLevel>
<threadName>
<fieldName>thread</fieldName>
</threadName>
<mdc>
<includeMdcKeyName>dt.span_id</includeMdcKeyName>
<includeMdcKeyName>dt.trace_id</includeMdcKeyName>
<includeMdcKeyName>dt.entity.host</includeMdcKeyName>
</mdc>
<stackTrace>
<fieldName>stackTrace</fieldName>
<!-- maxLength - ограничивает длину трассировки стека -->
<throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter">
<maxDepthPerThrowable>200</maxDepthPerThrowable>
<maxLength>14000</maxLength>
<rootCauseFirst>true</rootCauseFirst>
</throwableConverter>
</stackTrace>
<message/>
<throwableClassName>
<fieldName>exceptionClass</fieldName>
</throwableClassName>
</providers>
</encoder>
</appender>
Пример ручного обогащения данных логов для Winston (Node.js)
Чтобы включить обогащение логов для Winston, активируйте функцию ЕдиногоАгента Node.js - Trace/span context enrichment for unstructured logs. Вы можете адаптировать транспорт Winston, чтобы точно определить место добавления обогащения, как показано в приведенном ниже примере кода.
const winston = require("winston");
const Transport = require("winston-transport");
class CustomTransport extends Transport {
log(info, next) {
let myLogLine = `MyLogLine: ${info.timestamp} level=${info.level}: ${info.message}`;
// Это важно, поскольку приведенная выше строка извлекает только метку времени, уровень и сообщение, но ничего больше из метаданных.
if (info["dt.trace_id"]) {
myLogLine = `[!dt dt.trace_id=${info["dt.trace_id"]},dt.span_id=${info["dt.span_id"]},dt.trace_sampled=${info["dt.trace_sampled"]}] ${myLogLine}`;
}
console.log(myLogLine);
next();
}
}
const logger = winston.createLogger({
level: "info",
format: winston.format.timestamp(),
transports: [
new CustomTransport(),
// Этот транспорт включает все метаданные (включая идентификатор трассировки, добавленный Ключ-АСТРОМ и т. д.).
new winston.transport.Console({
format: winston.format.simple()
})
]
})
Входящий трафик NGINX с использованием Kubernetes
Вы можете обогатить свои логи, используя NGINX Ingress в Kubernetes, в два этапа:
- Выполните инструкции инструментария ingress-nginx в Kubernetes.
- Добавьте в файл
configmap.yamlдля входящего трафика NGINX следующую команду.
Добавление строки main-snippet включает в себя загрузку данных в ЕдиныйАгент и является необязательным, если вы уже следовали инструкциям по ручной настройке.
main-snippet: load_module /opt/astromkey/oneagent/agent/bin/current/linux-musl-x86-64/liboneagentnginx.so; log-format-upstream: '$remote_addr - $remote_user [$time_local] "$request" [!dt dt.trace_id=$dt_trace_id,dt.span_id=$dt_span_id,dt.trace_sampled=$dt_trace_sampled] $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length'
Переменные $dt_trace_id, $dt_span_id, и $dt_trace_sampled внедряются ЕдинымАгентом во время выполнения. Если ЕдиныйАгент не сможет их внедрить — например, из-за неработающей инструментации или использования более старой версии ЕдиногоАгента, которая не поддерживает эту функцию, — то команды проверки конфигурации NGINX, такие как nginx -t и nginx -s reload, завершатся с ошибкой. Это не влияет на работающий экземпляр NGINX и не является проблемой в производственной среде. В случае возникновения проблем обратитесь в службу поддержки Ключ-АСТРОМ.
Пример файла configmap.yaml
apiVersion: v1
kind: Namespace
metadata:
name: prod-ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
---
# Источник: ingress-nginx/templates/controller-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
helm.sh/chart: ingress-nginx-4.0.6
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.0.4
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx
namespace: prod-ingress-nginx
automountServiceAccountToken: true
---
# Источник: ingress-nginx/templates/controller-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
labels:
helm.sh/chart: ingress-nginx-4.0.6
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.0.4
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: prod-ingress-nginx
data:
allow-snippet-annotations: 'true'
main-snippet: load_module /opt/astromkey/oneagent/agent/bin/current/linux-musl-x86-64/liboneagentnginx.so;
log-format-upstream: '$remote_addr - $remote_user [$time_local] "$request" [!dt dt.trace_id=$dt_trace_id,dt.span_id=$dt_span_id,dt.trace_sampled=$dt_trace_sampled] $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length'
...
Получение идентификаторов трассировки и пакетов данных
Чтобы Ключ-АСТРОМ сопоставлял журналы с соответствующими трассировками, вы можете включить идентификаторы сегмента и трассировки в сообщения журнала, используя нотацию [!dt].
В следующих примерах показано, как получить идентификаторы трассировки и пакетов данных с помощью OpenTelemetry или SDK ЕдиногоАгента.
Python с OpenTelemetry
В приведенном ниже примере создана функция dt_log для обогащения заданного сообщения журнала информацией trace_id и span_id. Вывод этого обогащенного сообщения в настроенный приемник журналов связывает сообщение журнала с текущим активным сегментом в веб-интерфейсе Ключ-АСТРОМ.
import logging
from opentelemetry import trace
def dt_log(self, record):
if (not self.disabled) and self.filter(record):
ctx = trace.get_current_span().get_span_context()
if ctx.is_valid:
trace_id = "{0:032X}".format(ctx.trace_id)
span_id = "{0:016X}".format(ctx.span_id)
record.msg = f"[!dt dt.trace_id={trace_id}, dt.span_id={span_id}] - {record.msg}"
self.callHandlers(record)
logging.Logger.handle = dt_log
def lambda_handler(event, context):
logger = logging.getLogger()
logger.warning("Hello world")
return {
"statusCode": 200,
"body": "Hello from lambda"
}
JavaScript (Node.js) с OpenTelemetry
const opentelemetry = require('@opentelemetry/api');
function dtLog(msg) {
const spanContext = opentelemetry.trace.getSpanContext(opentelemetry.context.active()) ?? opentelemetry.INVALID_SPAN_CONTEXT;
console.log(`[!dt dt.trace_id=${spanContext.traceId}, dt.span_id=${spanContext.spanId}] - ${msg}`);
}
exports.handler = function(event, context) {
const msg = "Hello World"
dtLog(msg);
context.success({
statusCode: 200,
body: msg
});
};
Java с OpenTelemetry
В приведенном ниже примере создан метод dtLog для обогащения заданного сообщения журнала информацией TraceId и SpanId. Вывод этого обогащенного сообщения с помощью System.out связывает сообщение журнала с текущим активным сегментом в веб-интерфейсе Ключ-АСТРОМ.
package com.amazonaws.lambda.demo;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
public class HelloJava implements RequestHandler<Object, String> {
private static void dtLog(final String msg) {
SpanContext spanContext = Span.current().getSpanContext();
System.out.printf(
"[!dt dt.trace_id=%s,dt.span_id=%s] - %s%n",
spanContext.getTraceId(),
spanContext.getSpanId(),
msg
);
}
@Override
public String handleRequest(Object input, Context context) {
String msg = "Hello World";
dtLog(msg);
return msg;
}
}
Используйте SDK ЕдиногоАгента (Go)
В приведенном ниже примере обработчик HTTP использует Printf() для вывода ответа в стандартный поток вывода и дополняет эту информацию идентификаторами трассировки и сегмента, полученными из oneagentsdk.GetTraceContextInfo(). Вывод этого дополненного сообщения связывает сообщение журнала с текущим активным сегментом в веб-интерфейсе Ключ-АСТРОМ.
package main
import (
"fmt"
"log"
"net/http"
"github.com/astromkey/OneAgent-SDK-for-Go/sdk"
)
func main() {
// Создание экземпляра API OneAgent SDK
var oneagentsdk = sdk.CreateInstance()
http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
// Получить TraceContextInfo из входящего HTTP-запроса
// для получения идентификатора трассировки (Trace ID) и идентификатора трассировки (Span ID) активного контекста распределенной трассировки
traceContext := oneagentsdk.GetTraceContextInfo()
msg := "Hello World"
// Вывести в консоль
fmt.Printf("[!dt dt.trace_id=%s,dt.span_id=%s] - %s\n", traceContext.GetTraceId(), traceContext.GetSpanId(), msg)
// Запись HTTP-тела
fmt.Fprintf(w, msg)
})
fmt.Println("Запуск HTTP-сервера на порту 8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Получить идентификатор экземпляра группы процессов
Получить поле dt.entity.process_group_instance можно с помощью команды Python OpenTelemetry, содержащей merged. Значение process_group_instance получается в виде одного из атрибутов, предоставляемых в merged, как показано в примере ниже.
С помощью ЕдиногоАгента вы можете просто указать локальную конечную точку без токена аутентификации, чтобы включить сбор трассировочных данных.
import json
from opentelemetry import trace as OpenTelemetry
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
OTLPSpanExporter,
)
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider, sampling
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
)
merged = dict()
for name in ["dt_metadata_e617c525669e072eebe3d0f08212e8f2.json", "/var/lib/astromkey/enrichment/dt_metadata.json"]:
try:
data = ''
with open(name) as f:
data = json.load(f if name.startswith("/var") else open(f.read()))
merged.update(data)
except:
pass
merged.update({
"service.name": "python-quickstart", #TODO Замените на название вашего приложения
"service.version": "1.0.1", #TODO Замените на версию вашего приложения
})
resource = Resource.create(merged)
tracer_provider = TracerProvider(sampler=sampling.ALWAYS_ON, resource=resource)
OpenTelemetry.set_tracer_provider(tracer_provider)
tracer_provider.add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(
endpoint="http://localhost:14499/otlp/v1/traces"
))
)
При использовании ЕдиногоАгента обязательно включите общедоступный контроллер выполнения расширений в настройках Ключ-АСТРОМ, иначе данные отправляться не будут.
Перейдите в Настройки > Предпочтения > Контроллер выполнения расширений. Переключатели Включить контроллер выполнения расширений и Включить локальный API для сбора метрик PIPE/HTTP и логов должны быть активны.