Datadog Java APM (dd-trace-java)

repository·master·Indexed 20 days ago

https://github.com/datadog/dd-trace-java

A client library for instrumenting Java applications to provide distributed tracing, continuous profiling, and error tracking. The library includes the Datadog Java Agent for automatic APM instrumentation, IAST performance benchmarks for string operations, and specific instrumentation support for MongoDB drivers (versions 3.1 through 4.0) and Mule applications.

Tokens
43.6K
Snippets
99
Records
166
Agent score
70%

What's inside dd-trace-java

  1. Overview of Datadog Java APM

    master

    The dd-trace-java library is Datadog's APM client for Java applications. It provides APIs for both automatic and manual tracing and profiling.

    Key capabilities enabled by this library include:

    • Distributed Tracing: Using Automatic Instrumentation to track requests across services.
    • Continuous Profiling: Monitoring application performance and code hotspots.
    • Error Tracking: Identifying and visualizing application errors.
    • Continuous Integration Visibility: Monitoring CI/CD performance.
    • Deployment Tracking: Correlating deployments with performance changes.
  2. Overview of Datadog Smoke Tests

    master

    The Datadog Smoke Tests suite is designed to assert that various applications can start up with the Datadog JavaAgent without obvious ill effects. Each subproject within dd-smoke-tests represents a single smoke test case.

    Each test follows this lifecycle:

    1. Application Launch: The application is launched with both stdout and stderr redirected to $buildDir/reports/server.log.
    2. Validation: For web servers, a Spock test is executed which performs 200 requests to a server endpoint to exercise the application and assert on the expected response.
  3. Overview of MongoDB Driver 4.0 instrumentation

    master
    This instrumentation module provides tracing support for MongoDB driver version 4.0. It specifically addresses the mongodb-driver-reactivestreams module, which introduces its own work queue. Instrumentation of this queue is necessary to ensure trace information is correctly propagated across asynchronous boundaries during database operations.
  4. Datadog Java Agent for APM Overview

    master
    The Datadog Java Agent is an APM (Application Performance Monitoring) tool that provides automatic instrumentation for Java applications. It allows you to monitor your application's performance, trace requests across distributed systems, and collect metrics without requiring significant changes to your application code.
  5. Understand the scope of the mongo-test-core-3.7 project

    master

    This is a test-only project used for verifying Datadog instrumentation for older MongoDB client libraries. It does not contain new instrumentation code.

    It specifically targets the mongodb-driver and mongodb-driver-core libraries in the version range of 3.7 to 3.12.

    Note on MongoDB 4+: If you are looking for coverage for MongoDB 4 or newer, this project is not applicable. Versions for Mongo 4+ are covered by the driver-4.0-test project, as the mongodb-driver library is no longer used in those versions.

  6. What is the APM Test Agent?

    master

    The APM Test Agent emulates Datadog Agent APM endpoints. It runs alongside Java tracer Instrumentation Tests in CI to handle traces and perform Trace Checks.

    Key Features:

    • Trace Invariant Checks: Validates that traces meet expected standards.
    • Logging: Emits logs for received trace headers, spans, errors, and the status of trace checks.
    • Visibility: In GitLab, logs can be viewed within the Test-Agent container step for instrumentation test jobs (e.g., test_inst jobs).
  7. Understand the instrumentation directory structure

    master

    Instrumentations are stored in the following directory pattern:

    /dd-java-agent/instrumentation/$framework/$framework-$minVersion

    • $framework: The name of the framework (e.g., couchbase).
    • $minVersion: The minimum version of the framework supported by that specific instrumentation module.

    In some cases, a framework might have a submodule containing multiple version-specific instrumentations (e.g., hibernate), but most frameworks use a single version-specific module (e.g., akka-http-10.0).

    $ tree dd-java-agent/instrumentation/couchbase -L 2
    dd-java-agent/instrumentation/couchbase
    ├── couchbase-2.0
    │   ├── build.gradle
    │   └── src
    ├── couchbase-2.6
    │   ├── build.gradle
    │   └── src
    ├── couchbase-3.1
    │   ├── build.gradle
    │   └── src
    └── couchbase-3.2
        ├── build.gradle
        └── src
  8. Understand the core tracing engine components

    master

    The dd-trace-core module contains the central tracing logic:

    • CoreTracer: The implementation that creates spans, manages sampling, and drives the writer pipeline.
    • DDSpan / DDSpanContext: Concrete implementations containing Datadog-specific metadata.
    • PendingTrace: A collection of all spans in a trace, flushed when the root span finishes.
    • scopemanager/: Manages the active span per thread and handles async context propagation via ContinuableScope and ScopeContinuation.
    • propagation/: Handles trace context propagation using codecs for Datadog, W3C TraceContext, B3, Haystack, and X-Ray.
    • common/writer/: The pipeline that dispatches traces via DDAgentWriter (to the Datadog Agent /v0.4/traces endpoint) or DDIntakeWriter (direct API submission).
  9. Understand Gradle Configurations

    master

    In Gradle, a configuration is a named collection of dependencies used for a specific purpose in a build. They act as 'buckets' where you place dependencies based on how they should be used (e.g., for compilation, testing, or runtime).

    Configurations serve two primary roles:

    1. Declaring dependencies: Adding requirements to a configuration via a dependencies {} block.
    2. Resolving dependencies: Allowing Gradle to compute the full dependency graph and produce files (like JARs) for tasks to use.

    Most users interact with declarable configurations (like implementation), while Gradle internally manages resolvable (classpaths used by tasks) and consumable (elements exposed to other projects) configurations.

    dependencies {
        // "implementation" is a configuration
        implementation("com.google.guava:guava:32.1.2-jre")
    
        // "testImplementation" is another configuration
        testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
    }
  10. Compare Groovy DSL and Kotlin DSL in Gradle

    master

    Gradle builds can be written using either the Groovy DSL or the Kotlin DSL. While the project still relies on some Groovy-based script plugins, the Kotlin DSL is generally preferred due to its superior IDE support, type safety, and compile-time checking.

    Key Differences

    AspectGroovy DSLKotlin DSL
    File extension.gradle.gradle.kts
    String quotesSingle ' or double "Double " only
    Method callsParentheses optionalParentheses required
    Property assignment= optional= required (mostly)
    IDE supportLimitedFull auto-completion and refactoring
    Type safetyDynamic typingStatic typing with compile-time checks
    // Groovy DSL Example
    plugins {
        id 'java'
    }
    
    dependencies {
        implementation 'com.google.guava:guava:32.1.2-jre'
    }
    
    tasks.register('hello') {
        doLast {
            println 'Hello from Groovy DSL'
        }
    }
    
    // Kotlin DSL Example
    plugins {
        id("java")
    }
    
    dependencies {
        implementation("com.google.guava:guava:32.1.2-jre")
    }
    
    tasks.register("hello") {
        doLast {
            println("Hello from Kotlin DSL")
        }
    }
  11. How Datadog Java Agent instrumentations work

    master

    The Datadog Java Trace Agent provides auto-instrumentation for approximately 120 integrations (covering ~200 instrumentations).

    Auto-instrumentation works by using a Java agent to perform bytecode manipulation on compiled Java classes at runtime. This process matches classes against rules defined within an instrumentation to inject tracing logic, similar to what a developer would do manually.

    Instrumentations are organized within the repository under /dd-java-agent/instrumentation/ using a framework-specific directory structure.

  12. Design guidelines for Java agent premain phase

    master

    When developing code for the Java agent, you must distinguish between the premain phase (executed before the application's main method) and the post-main phase (executed after the application has started).

    Code in the premain phase is highly sensitive because loading certain classes too early can lock in incorrect system properties, initialize native libraries prematurely, or prevent applications from configuring their own runtimes.

    Core Principles:

    • Minimize Premain Footprint: Only execute code absolutely necessary for setting up the instrumentation framework and registering transformers.
    • Avoid Side Effects: Be cautious of class loading, as it triggers static initializers and can lock in system property values.
    • Manage Native Library Initialization: Be aware that certain classes (like java.nio.file) trigger native library loading (e.g., pthread on Linux), which can cause race conditions.