Você está na página 1de 22

Conectar Logs e Traces

A correlação entre o Datadog APM e o Gerenciamento de Logs do Datadog é


melhorada pela injeção de IDs de trace, IDs de span, env, service e version como
atributos em seus logs. Com esses campos, você pode encontrar os logs exatos
associados a um serviço e versão específicos ou todos os logs correlacionados a um
trace observado.

Recomenda-se configurar o tracer de sua aplicação com DD_ENV, DD_SERVICE e


DD_VERSION. Isso fornecerá a melhor experiência para adicionar env, service e version.
Consulte a documentação de marcação de serviço unificado para obter mais detalhes.

Observação: O PHP Tracer não suporta a configuração de marcação de serviço


unificado para logs.

Antes de correlacionar traces com logs, verifique se seus logs são enviados como JSON
ou são analisados pelo processador de log apropriado no nível de linguagem. Seus logs
de nível de linguagem devem ser convertidos em atributos do Datadog para que a
correlação de traces e logs funcione.

Para saber mais sobre a conexão automática ou manual de seus logs com seus traces,
selecione sua linguagem abaixo:

Conectando Logs e Traces em Java


Antes de começar

Verifique se a coleta de logs está configurada. Consulte as instruções de coleta de logs


para Java Log4j, Log4j 2 ou Logback.

Injeção automática

A partir da versão 0.74.0, o tracer do Java automaticamente injeta identificadores de


correlação de trace em logs. Para versões anteriores, habilite a injeção automática no
tracer do Java adicionando dd.logs.injection=true como uma propriedade do sistema
ou por meio da variável de ambiente DD_LOGS_INJECTION=true. Detalhes completos
de configuração podem ser encontrados na página de configuração do tracer do Java.

Observação: Se o attribute.path para o seu ID de trace não for dd.trace_id, verifique se


as configurações de atributos reservados do ID de trace levam em conta o
attribute.path. Para obter mais informações, consulte Logs correlacionados não
aparecem no painel de ID de trace.

Injeção manual

Se preferir correlacionar manualmente seus traces com seus logs, use a API do tracer
do Java para recuperar identificadores de correlação. Use os métodos
CorrelationIdentifier.getTraceId e CorrelationIdentifier.getSpanId para injetar
identificadores no início do span que está sendo registrado e remova os identificadores
quando o span estiver completo.

Log4j 2 - SLF4J e Logback

import org.apache.logging.log4j.ThreadContext;

import datadog.trace.api.CorrelationIdentifier;

// There must be spans started and active before this block.

try {

ThreadContext.put("dd.trace_id", CorrelationIdentifier.getTraceId());
ThreadContext.put("dd.span_id", CorrelationIdentifier.getSpanId());

// Log something

} finally {

ThreadContext.remove("dd.trace_id");

ThreadContext.remove("dd.span_id");

Observação: Se você não estiver usando uma Integração de Log do Datadog para
analisar seus logs, regras de análise de logs personalizadas precisam garantir que
dd.trace_id e dd.span_id estejam sendo analisados como strings. Para obter mais
informações, consulte Logs correlacionados não aparecem no painel de ID de trace.

Consulte a documentação de coleta de logs do Java para obter mais detalhes sobre a
implementação de loggers específicos e instruções para registro em formato JSON.

Instrumentação Personalizada do Java com a Biblioteca Datadog

Esta página detalha casos comuns de uso para adicionar e personalizar a


observabilidade com o Datadog APM.

Adicionando tags

Adicione tags personalizadas de span aos seus spans para personalizar a


observabilidade dentro do Datadog. As tags de span são aplicadas às suas traces de
entrada, permitindo correlacionar o comportamento observado com informações de
nível de código, como o nível do cliente, o valor do checkout ou o ID do usuário.
Adicionar tags de span personalizadas

Adicione tags personalizadas aos seus spans correspondentes a qualquer valor


dinâmico dentro do código da sua aplicação, como customer.id.

import org.apache.cxf.transport.servlet.AbstractHTTPServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import io.opentracing.Tracer;

import io.opentracing.util.GlobalTracer;

@WebServlet

class ShoppingCartServlet extends AbstractHttpServlet {

@Override

void doGet(HttpServletRequest req, HttpServletResponse resp) {

// Get the active span

final Span span = GlobalTracer.get().activeSpan();

if (span != null) {

// customer_id -> 254889

// customer_tier -> platinum

// cart_value -> 867


span.setTag("customer.id", customer_id);

span.setTag("customer.tier", customer_tier);

span.setTag("cart.value", cart_value);

// [...]

Adicionando tags globalmente a todos os spans

A propriedade dd.tags permite definir tags em todos os spans gerados por uma
aplicação. Isso pode ser útil para agrupar estatísticas para suas aplicações, datacenters
ou qualquer outra tag que você gostaria de ver dentro da interface do Datadog.

java -javaagent:<DD-JAVA-AGENT-PATH>.jar \

-Ddd.tags=datacenter:njc,<TAG_KEY>:<TAG_VALUE> \

-jar <YOUR_APPLICATION_PATH>.jar

Definindo erros em um span

Para personalizar um erro associado a um dos seus spans, defina a tag de erro no span
e use Span.log() para definir um "evento de erro". O evento de erro é um
Map<String,Object> contendo uma entrada Fields.ERROR_OBJECT->Throwable,
Fields.MESSAGE->String, ou ambos.

import io.opentracing.Span;

import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;

import io.opentracing.log.Fields;

...

// Get active span if not available in current method

final Span span = GlobalTracer.get().activeSpan();

if (span != null) {

span.setTag(Tags.ERROR, true);

span.log(Collections.singletonMap(Fields.ERROR_OBJECT, ex));

Nota: Span.log() é um mecanismo genérico do OpenTracing para associar eventos ao


carimbo de data/hora atual. O Java Tracer suporta apenas o registro de eventos de erro.
Alternativamente, você pode definir as tags de erro diretamente no span sem usar log():

import io.opentracing.Span;

import io.opentracing.tag.Tags;

import io.opentracing.util.GlobalTracer;

import datadog.trace.api.DDTags;

import java.io.PrintWriter;

import java.io.StringWriter;
...

final Span span = GlobalTracer.get().activeSpan();

if (span != null) {

span.setTag(Tags.ERROR, true);

span.setTag(DDTags.ERROR_MSG, ex.getMessage());

span.setTag(DDTags.ERROR_TYPE, ex.getClass().getName());

final StringWriter errorString = new StringWriter();

ex.printStackTrace(new PrintWriter(errorString));

span.setTag(DDTags.ERROR_STACK, errorString.toString());

Nota: Você pode adicionar qualquer metadado de erro relevante listado na


documentação da visualização de trace. Se o span atual não é o span raiz, marque-o
como um erro usando a biblioteca dd-trace-api para obter o span raiz com
MutableSpan e, em seguida, use setError(true). Consulte a seção definindo tags e erros
em um span raiz para obter mais detalhes.

Definir tags e erros em um span raiz a partir de um span filho

Quando um evento ou condição ocorre a jusante, pode ser desejável que o


comportamento ou valor correspondente seja refletido como uma tag no nível superior
ou span raiz. Isso pode ser útil para contabilizar um erro ou para medir o desempenho,
ou para definir uma tag dinâmica para observabilidade.
import java.util.Collections;

import io.opentracing.Span;

import io.opentracing.Scope;

import datadog.trace.api.interceptor.MutableSpan;

import io.opentracing.log.Fields;

import io.opentracing.util.GlobalTracer;

import io.opentracing.util.Tracer;

Tracer tracer = GlobalTracer.get();

final Span span = tracer.buildSpan("<OPERATION_NAME>").start();

// Note: The scope in the try with resource block below

// will be automatically closed at the end of the code block.

// If you do not use a try with resource statement, you need

// to call scope.close().

try (final Scope scope = tracer.activateSpan(span)) {

// exception thrown here

} catch (final Exception e) {

// Set error tag on span as normal


span.log(Collections.singletonMap(Fields.ERROR_OBJECT, e));

// Set error on root span

if (span instanceof MutableSpan) {

MutableSpan localRootSpan = ((MutableSpan) span).getLocalRootSpan();

localRootSpan.setError(true);

localRootSpan.setTag("some.other.tag", "value");

} finally {

// Close span in a finally block

span.finish();

Se você não estiver criando manualmente um span, ainda é possível acessar o span raiz
por meio do GlobalTracer:

import io.opentracing.Span;

import io.opentracing.util.GlobalTracer;

import datadog.trace.api.interceptor.MutableSpan;

...
final Span span = GlobalTracer.get().activeSpan();

if (span != null && (span instanceof MutableSpan)) {

MutableSpan localRootSpan = ((MutableSpan) span).getLocalRootSpan();

// do stuff with root span

Nota: Embora MutableSpan e Span compartilhem muitos métodos semelhantes, eles


são tipos distintos. MutableSpan é específico para o Datadog e não faz parte da API
OpenTracing.

Adicionando spans

Se você não estiver usando uma instrumentação de framework suportada, ou se


desejar maior profundidade nas traces do aplicativo, poderá adicionar uma
instrumentação personalizada ao seu código para obter gráficos de chamas completos
ou para medir os tempos de execução de trechos de código.

Se não for possível modificar o código do aplicativo, use a variável de ambiente


dd.trace.methods para detalhar esses métodos.

Se você tiver anotações @Trace existentes ou similares, ou preferir usar anotações para
completar quaisquer traces incompletas no Datadog, use as Anotações de Trace.

Métodos de trace do Datadog

Usando a propriedade do sistema dd.trace.methods, você pode obter visibilidade em


frameworks não suportados sem alterar o código do aplicativo.

java -javaagent:/path/to/dd-java-agent.jar -Ddd.env=prod -Ddd.service.name=db-app -


Ddd.trace.methods=store.db.SessionManager[saveSession] -jar path/to/application.jar

A única diferença entre esta abordagem e o uso de anotações @Trace são as opções de
personalização para os nomes de operação e recurso. Com os Métodos de Trace do DD,
operationName é trace.annotation e resourceName é SessionManager.saveSession.
Anotações de trace

Adicione @Trace a métodos para que eles sejam rastreados quando executados com
dd-java-agent.jar. Se o agente não estiver anexado, esta anotação não terá efeito no
seu aplicativo.

A anotação Trace do Datadog é fornecida pela dependência dd-trace-api.

As anotações @Trace têm o nome de operação padrão trace.annotation e o nome de


recurso do método rastreado. Eles podem ser definidos como argumentos da anotação
@Trace para refletir melhor o que está sendo instrumentado. Esses são os únicos
argumentos possíveis que podem ser definidos para a anotação @Trace.

import datadog.trace.api.Trace;

public class SessionManager {

@Trace(operationName = "database.persist", resourceName =


"SessionManager.saveSession")

public static void saveSession() {

// your method implementation here

Observe que, por meio da propriedade do sistema dd.trace.annotations, outras


anotações de método de rastreamento podem ser reconhecidas pelo Datadog como
@Trace. Você pode encontrar uma lista aqui se tiver decorado previamente o seu
código.
Criando manualmente um novo span

Além da instrumentação automática, a anotação @Trace e as configurações


dd.trace.methods, você pode personalizar sua observabilidade criando
programaticamente spans ao redor de qualquer bloco de código. Os spans criados
dessa maneira se integram automaticamente com outros mecanismos de rastreamento.
Em outras palavras, se um rastreamento já foi iniciado, o span manual terá o span pai
como seu chamador. Da mesma forma, quaisquer métodos rastreados chamados a
partir do bloco de código encapsulado terão o span manual como seu pai.

import datadog.trace.api.DDTags;

import io.opentracing.Scope;

import io.opentracing.Span;

import io.opentracing.Tracer;

import io.opentracing.util.GlobalTracer;

class SomeClass {

void someMethod() {

Tracer tracer = GlobalTracer.get();

// Service and resource name tags are required.

// You can set them when creating the span:

Span span = tracer.buildSpan("<OPERATION_NAME>")


.withTag(DDTags.SERVICE_NAME, "<SERVICE_NAME>")

.withTag(DDTags.RESOURCE_NAME, "<RESOURCE_NAME>")

.start();

// Note: The scope in the try with resource block below

// will be automatically closed at the end of the code block.

// If you do not use a try with resource statement, you need

// to call scope.close().

try (Scope scope = tracer.activateSpan(span)) {

// Alternatively, set tags after creation

span.setTag("my.tag", "value");

// The code you're tracing

} catch (Exception e) {

// Set error on span

} finally {

// Close span in a finally block

span.finish();
}

Extendendo os rastreadores

As bibliotecas de rastreamento são projetadas para serem extensíveis. Os clientes


podem considerar escrever um pós-processador personalizado chamado
TraceInterceptor para interceptar Spans e ajustá-los ou descartá-los de acordo (por
exemplo, com base em expressões regulares). O exemplo a seguir implementa dois
interceptadores para alcançar uma lógica de pós-processamento complexa.

import java.util.List;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Map;

import datadog.trace.api.interceptor.TraceInterceptor;

import datadog.trace.api.interceptor.MutableSpan;

class FilteringInterceptor implements TraceInterceptor {

@Override

public Collection<? extends MutableSpan> onTraceComplete(

Collection<? extends MutableSpan> trace) {


List<MutableSpan> filteredTrace = new ArrayList<>();

for (final MutableSpan span : trace) {

String orderId = (String) span.getTags().get("order.id");

// Drop spans when the order id starts with "TEST-"

if (orderId == null || !orderId.startsWith("TEST-")) {

filteredTrace.add(span);

return filteredTrace;

@Override

public int priority() {

// some high unique number so this interceptor is last

return 100;

}
}

class PricingInterceptor implements TraceInterceptor {

@Override

public Collection<? extends MutableSpan> onTraceComplete(

Collection<? extends MutableSpan> trace) {

for (final MutableSpan span : trace) {

Map<String, Object> tags = span.getTags();

Double originalPrice = (Double) tags.get("order.price");

Double discount = (Double) tags.get("order.discount");

// Set a tag from a calculation from other tags

if (originalPrice != null && discount != null) {

span.setTag("order.value", originalPrice - discount);

}
return trace;

@Override

public int priority() {

return 20; // some unique number

Próximo ao início do seu aplicativo, registre os interceptores com o seguinte:

datadog.trace.api.GlobalTracer.get().addTraceInterceptor(new FilteringInterceptor());
datadog.trace.api.GlobalTracer.get().addTraceInterceptor(new PricingInterceptor());

Configuração do cliente de rastreamento e do agente

Existem configurações adicionais possíveis tanto para o cliente de rastreamento quanto


para o agente Datadog para a propagação de contexto, bem como para excluir
recursos específicos do envio de traces para o Datadog no caso em que esses traces
não são desejados para contabilizar em métricas calculadas, como Health Checks.

Propagando contexto com extração e injeção de cabeçalhos

Você pode configurar a propagação de contexto para traces distribuídos através da


injeção e extração de cabeçalhos. Leia Trace Context Propagation para obter mais
informações.

Filtragem de recursos

Os traces podem ser excluídos com base em seus nomes de recursos, para remover
tráfego sintético, como verificações de saúde, do relatório de traces para o Datadog.
Essas e outras configurações de segurança e ajuste fino podem ser encontradas na
página de Segurança ou em Ignorando recursos indesejados.

Conectando logs e traces em Python

Injeção

Biblioteca padrão de logging

Para correlacionar seus traces com seus logs, atualize o formato do seu log para
incluir os atributos necessários do registro de log e chame
ddtrace.patch(logging=True).

Inclua os atributos dd.env, dd.service, dd.version, dd.trace_id e dd.span_id para o


registro de log na string de formato.

Aqui está um exemplo usando logging.basicConfig para configurar a injeção de


log:

from ddtrace import patch; patch(logging=True)

import logging

from ddtrace import tracer

FORMAT = ('%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(lineno)d] '

'[dd.service=%(dd.service)s dd.env=%(dd.env)s dd.version=%(dd.version)s


dd.trace_id=%(dd.trace_id)s dd.span_id=%(dd.span_id)s] '

'- %(message)s')

logging.basicConfig(format=FORMAT)

log = logging.getLogger(__name__)
log.level = logging.INFO

@tracer.wrap()

def hello():

log.info('Hello, World!')

hello()

Sem biblioteca padrão de logging

Se você não estiver usando o módulo de logging da biblioteca padrão, pode


usar o seguinte trecho de código para injetar informações do tracer em seus
logs:

from ddtrace import tracer

span = tracer.current_span()

correlation_ids = (span.trace_id, span.span_id) if span else (None, None)

Como ilustração desta abordagem, o exemplo a seguir define uma função como
um processador em structlog para adicionar campos de tracer à saída do log:

import ddtrace

from ddtrace import tracer


import structlog

def tracer_injection(logger, log_method, event_dict):

# get correlation ids from current tracer context

span = tracer.current_span()

trace_id, span_id = (span.trace_id, span.span_id) if span else (None, None)

# add ids to structlog event dictionary

event_dict['dd.trace_id'] = str(trace_id or 0)

event_dict['dd.span_id'] = str(span_id or 0)

# add the env, service, and version configured for the tracer

event_dict['dd.env'] = ddtrace.config.env or ""

event_dict['dd.service'] = ddtrace.config.service or ""

event_dict['dd.version'] = ddtrace.config.version or ""

return event_dict
structlog.configure(

processors=[

tracer_injection,

structlog.processors.JSONRenderer()

log = structlog.get_logger()

Depois que o logger estiver configurado, a execução de uma função rastreada


que registra um evento gera as informações de tracer injetadas:

>>> traced_func()

{"event": "In tracer context", "dd.trace_id": 9982398928418628468, "dd.span_id":


10130028953923355146, "dd.env": "dev", "dd.service": "hello", "dd.version":
"abc123"}

Observação: Se você não estiver usando uma Integração de Log Datadog para
analisar seus logs, as regras personalizadas de análise de log devem garantir
que dd.trace_id e dd.span_id estejam sendo analisados como strings e
remapeados usando o Trace Remapper. Para obter mais informações, consulte
Correlated Logs Not Showing Up in the Trace ID Panel.

Consulte a documentação de logging do Python para garantir que a Integração


de Log

Você também pode gostar