Al depurar sistemas distribuidos, es común partir de una traza y necesitar las entradas de registro correspondientes, o viceversa. Si inyecta los ID de traza y los ID de span de OpenTelemetry en los registros de su aplicación, podrá saltar de un span de traza a las líneas exactas del registro generadas durante esa operación. Esto acelera el diagnóstico de fallas y el análisis de rendimiento.
Este tema aborda la correlación entre trazas y registros para Java, Go y Python. Java y Python admiten la inyección automática mediante la instrumentación automática de OpenTelemetry. En Go, la inyección se hace de forma manual.
Requisitos previos
Antes de empezar, asegúrese de contar con lo siguiente:
Su aplicación supervisada por ARMS con el rastreo de OpenTelemetry habilitado.
El agente de Java, el SDK de Go o el SDK de Python de OpenTelemetry instalado, según el lenguaje que utilice.
Cómo funciona
OpenTelemetry utiliza Mapped Diagnostic Context (MDC) para inyectar trace_id y span_id en cada entrada de registro generada dentro de un span activo. Con la instrumentación automática (Java y Python), el agente se encarga de la inyección automáticamente; no se requieren cambios en el código. Sin instrumentación automática (Go), extraiga estos valores del contexto del span y adjúntelos manualmente a los campos del registro.
Una vez que el contexto de traza aparezca en sus registros, busque por ID de traza en Simple Log Service para localizar todas las entradas correspondientes a una solicitud específica.
Java
Frameworks de registro compatibles
|
Framework de registro |
Compatibilidad con instrumentación automática |
Dependencia para instrumentación manual |
|
Log4j 1 |
1.2+ |
N/A |
|
Log4j 2 |
2.7+ |
|
|
Logback |
1.0+ |
Para más detalles sobre el funcionamiento de la instrumentación automática de MDC, consulte Logger MDC auto-instrumentation.
Configurar Log4j 2
-
Agregue la dependencia de OpenTelemetry para Log4j 2 en su archivo
pom.xml. ReemplaceOPENTELEMETRY_VERSIONpor la versión más reciente.<dependencies> <dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-log4j-context-data-2.17-autoconfigure</artifactId> <version>OPENTELEMETRY_VERSION</version> <scope>runtime</scope> </dependency> </dependencies> -
Agregue
%X{trace_id}y%X{span_id}al patrón en el archivolog4j2.xml. La sintaxis%X{key}lee los valores del MDC, el cual el agente de OpenTelemetry llena automáticamente cuando hay un span activo.<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} trace_id=%X{trace_id} span_id=%X{span_id} trace_flags=%X{trace_flags} - %msg%n"/> </Console> </Appenders> <Loggers> <Root> <AppenderRef ref="Console" level="All"/> </Root> </Loggers> </Configuration>
Configurar Logback
-
Agregue la dependencia de OpenTelemetry para Logback en su archivo
pom.xml. ReemplaceOPENTELEMETRY_VERSIONpor la versión más reciente.<dependencies> <dependency> <groupId>io.opentelemetry.instrumentation</groupId> <artifactId>opentelemetry-logback-mdc-1.0</artifactId> <version>OPENTELEMETRY_VERSION</version> </dependency> </dependencies> -
Actualice el archivo
logback.xmlpara incluir%X{trace_id}y%X{span_id}en el patrón. Además, envuelva su appender conOpenTelemetryAppender.<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} trace_id=%X{trace_id} span_id=%X{span_id} trace_flags=%X{trace_flags} %msg%n</pattern> </encoder> </appender> <!-- Wrap your logging appender with OpenTelemetryAppender --> <appender name="OTEL" class="io.opentelemetry.instrumentation.logback.mdc.v1_0.OpenTelemetryAppender"> <appender-ref ref="CONSOLE"/> </appender> <!-- Use the wrapped "OTEL" appender instead of the original "CONSOLE" one --> <root level="INFO"> <appender-ref ref="OTEL"/> </root> </configuration>
Configurar Logback en Spring Boot
Spring Boot usa Logback de forma predeterminada. En lugar de editar el XML, agregue una sola línea al archivo application.properties:
logging.pattern.level=trace_id=%mdc{trace_id} span_id=%mdc{span_id} %5p
Salida de ejemplo:
2024-06-26 10:56:31.200 trace_id=8f7ebd8a73f9a8f50e6a00a87a20952a span_id=1b08f18b8858bb9a INFO 53724 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-06-26 10:56:31.201 trace_id=8f7ebd8a73f9a8f50e6a00a87a20952a span_id=1b08f18b8858bb9a INFO 53724 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-06-26 10:56:31.209 trace_id=8f7ebd8a73f9a8f50e6a00a87a20952a span_id=1b08f18b8858bb9a INFO 53724 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms
2024-06-26 10:56:31.296 trace_id=8f7ebd8a73f9a8f50e6a00a87a20952a span_id=5743699405074f4e INFO 53724 --- [nio-8081-exec-1] com.example.httpserver.ot.OTServer : hello world
Go
OpenTelemetry en Go no admite la inyección automática del contexto de traza en los registros. Extraiga los ID de traza y los ID de span del contexto del span de forma manual.
Configurar logrus
-
Importe los paquetes obligatorios.
import ( oteltrace "go.opentelemetry.io/otel/trace" "github.com/sirupsen/logrus" ) -
Cree una función auxiliar que extraiga los ID de traza y los ID de span de un span, y los devuelva como campos de logrus.
func LogrusFields(span oteltrace.Span) logrus.Fields { return logrus.Fields{ "trace_id": span.SpanContext().TraceID().String(), "span_id": span.SpanContext().SpanID().String(), } } -
Utilice la función auxiliar después de crear un span para registrar la información con el contexto de traza.
_, span := tracer.Start(ctx, "spanName") defer span.End() logEntry := logrus.WithFields(LogrusFields(span)) logEntry.Info("This is an info message with trace and span ID")
Python
OpenTelemetry en Python admite la inyección automática del contexto de traza en los registros. Para más detalles, consulte OpenTelemetry Logging Instrumentation.
Configurar el módulo logging
-
Habilite la inyección automática al establecer la siguiente variable de entorno:
export OTEL_PYTHON_LOG_CORRELATION=true -
Agregue
%(otelTraceID)sy%(otelSpanID)sal formato de sus registros. OpenTelemetry reemplaza estos marcadores de posición con el ID de traza y el ID de span reales durante la ejecución.Ejemplo de formato de registro:
formatter = logging.Formatter( '%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(lineno)d] [trace_id=%(otelTraceID)s span_id=%(otelSpanID)s resource.service.name=%(otelServiceName)s] - %(message)s' )Salida de ejemplo:
2024-06-25 10:00:55,494 INFO [app] [test.py:80] [trace_id=70561de6a164ac991bfff2281b7f**** span_id=4b7f3c798460**** resource.service.name=ot-python-demo] - hello world
Ejemplo integral con Flask
Este ejemplo muestra una configuración completa: cree una aplicación Flask, instruméntela con OpenTelemetry y compruebe que los ID de traza aparecen en los registros.
Requisitos previos:
Python y pip instalados (este ejemplo usa Python 3.12.4 y pip 24.1.1).
Paso 1: Instalar las dependencias
Instale Flask:
pip3 install flask
Instale la distribución de OpenTelemetry y las bibliotecas de instrumentación automática:
pip3 install opentelemetry-distro \
opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
Paso 2: Crear la aplicación
Guarde el siguiente código en el archivo test.py:
import logging
from logging.handlers import RotatingFileHandler
from flask import Flask
app = Flask(__name__)
# Create a formatter that includes OpenTelemetry trace context
formatter = logging.Formatter(
'%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(lineno)d] [trace_id=%(otelTraceID)s span_id=%(otelSpanID)s resource.service.name=%(otelServiceName)s] - %(message)s'
)
# Write logs to a file with rotation
# Replace <log-file-path> with the actual path, for example: /var/log/app.log
file_handler = RotatingFileHandler('<log-file-path>', maxBytes=10000, backupCount=1)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)
app.logger.addHandler(file_handler)
@app.route('/')
def hello_world():
app.logger.info('Hello World!!!')
return 'Hello, World!'
if __name__ == '__main__':
app.run()
Paso 3: Ejecutar la aplicación con la instrumentación de OpenTelemetry
Establezca las variables de entorno e inicie la aplicación con el contenedor de instrumentación automática de OpenTelemetry:
export OTEL_PYTHON_LOG_CORRELATION=true
export OTEL_SERVICE_NAME=ot-python-demo
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=none
# Replace test.py with your actual filename if different
opentelemetry-instrument python3 test.py
Si la aplicación se inicia correctamente, aparecerá una salida similar a la siguiente:
* Running on http://127.0.**.**:5000
Paso 4: Comprobar la salida del registro
Envíe una solicitud a la aplicación y revise el archivo de registro. Cada entrada ahora incluye el ID de traza y el ID de span:
2024-06-25 10:00:55,494 INFO [app] [test.py:80] [trace_id=70561de6a164ac991bfff2281b7f**** span_id=4b7f3c798460**** resource.service.name=ot-python-demo] - hello world
Pasos siguientes
Associate logs with traces -- Navegue desde las entradas de registro hasta las trazas distribuidas en la consola de ARMS.
Associate application logs with trace IDs in Simple Log Service -- Configure la correlación bidireccional entre las trazas de ARMS y los registros de Simple Log Service.