#datadog #tracing-subscriber #tracing #layer

datadog-formatting-layer

A crate providing a tracing-subscriber layer for formatting events so Datadog can parse them

8 stable releases

3.0.0 Sep 3, 2024
2.2.1 May 30, 2024
2.1.0 Mar 6, 2024
1.1.0 Sep 18, 2023
1.0.1 Jun 21, 2023

#591 in Debugging

Download history 136/week @ 2024-07-22 119/week @ 2024-07-29 26/week @ 2024-08-05 46/week @ 2024-08-12 93/week @ 2024-08-19 17/week @ 2024-08-26 159/week @ 2024-09-02 7/week @ 2024-09-09 77/week @ 2024-09-16 49/week @ 2024-09-23 101/week @ 2024-09-30 39/week @ 2024-10-07 11/week @ 2024-10-14 41/week @ 2024-10-21 30/week @ 2024-10-28 40/week @ 2024-11-04

124 downloads per month

Apache-2.0

32KB
526 lines

Datadog Formatting Layer

A crate providing a tracing-subscriber layer for formatting events so Datadog can parse them.

Release Test License Crates.io

Features

  • Provides a layer for tracing-subscriber
  • Generates parsable "logs" for datadog and prints them to stdout
  • Enables log correlation between spans and "logs" (see datadog docs)

Why not just tracing_subscriber::fmt().json() ?

The problem is, that datadog expects the "logs" to be in a specific (mostly undocumented) json format.

This crates tries to mimic this format.

Usage

Simple

use datadog_formatting_layer::DatadogFormattingLayer;
use tracing::info;
use tracing_subscriber::prelude::*;

tracing_subscriber::registry()
    .with(DatadogFormattingLayer::default())
    .init();

info!(user = "Jack", "Hello World!");

Running this code will result in the following output on stdout:

{
  "timestamp": "2023-06-21T10:36:50.364874878+00:00",
  "level": "INFO",
  "fields.user": "Jack",
  "message": "Hello World user=Jack",
  "target": "simple"
}

With Opentelemetry

use datadog_formatting_layer::DatadogFormattingLayer;
use opentelemetry::global;
use opentelemetry_datadog::ApiVersion;
use opentelemetry_sdk::{
    runtime::Tokio,
    propagation::TraceContextPropagator,
    trace::{config, RandomIdGenerator, Sampler},
};
use tracing::{debug, error, info, instrument, warn};
use tracing_subscriber::{prelude::*, util::SubscriberInitExt};

// the tracer needs async to run
#[tokio::main]
async fn main() {
    // Just some otel boilerplate
    global::set_text_map_propagator(TraceContextPropagator::new());

    let tracer = opentelemetry_datadog::new_pipeline()
        .with_service_name("my-service")
        .with_trace_config(
            config()
                .with_sampler(Sampler::AlwaysOn)
                .with_id_generator(RandomIdGenerator::default()),
        )
        .with_api_version(ApiVersion::Version05)
        .with_env("rls")
        .with_version("420")
        .install_batch(Tokio)
        .unwrap();

    // Use both the tracer and the formatting layer
    tracing_subscriber::registry()
        .with(DatadogFormattingLayer::default())
        .with(tracing_opentelemetry::layer().with_tracer(tracer))
        .init();

    // Here no span exists
    info!(user = "Jack", "Hello World!");
    some_test("fasel");
}

// This will create a span and a trace id which is attached to the "logs"
#[instrument(fields(hello = "world"))]
fn some_test(value: &str) {
    // Here some span exists
    info!(ola = "salve", value, "Bla {value}");
}

When running this code with an datadog agent installed the logs will be sent to datadog and parsed there.

Otherwise the following output will be printed to stdout (fields are excluded for readability)

{"timestamp":"2023-06-21T10:36:50.363224217+00:00","level":"INFO","message":"Hello World! user=Jack","target":"otel"}
{"timestamp":"2023-06-21T10:36:50.363384118+00:00","level":"INFO","message":"Bla fasel user=Jack ola=salve value=Fasel hello=world","target":"otel","dd.trace_id":0,"dd.span_id":10201226522570980512}

Supported Opentelemetry versions:

OpenTelemetry DatadogFormattingLayer
0.23.* 3.*
0.22.* 2.1.*, 2.2.*
0.20.* 1.1.*, 2.0.*
0.19.* 1.0.*

Dependencies

~7–9MB
~157K SLoC