Skip to content

DDTrace Golang

There are two ways to instrument your Go application:

1. Compile-time Instrumentation

  • Ensures maximum coverage of your tracing instrumentation.
  • Does not require source code modifications, making it ideal for integrating at the CI/CD level.

2. Manual Instrumentation

Use dd-trace-go in conjunction with our integration packages to automatically generate spans for libraries of your choosing. This option:

  • Gives you complete control over which parts of your application are traced.
  • Requires modifying the application’s source code.

Requirements

  • Applications must be managed using Go modules. Module vendoring is supported.
  • Go Tracer requires Go 1.18+.

Install Orchestrion

go install github.com/DataDog/orchestrion@latest

If the installation fails, try cloning the project locally and compiling it again.

git clone https://github.com/DataDog/orchestrion.git
cd orchestrion/
go build
cp orchestrion $GOPATH/bin/

Register Orchestrion in your project’s go.mod:

orchestrion pin
# commit changelog
git add go.mod go.sum orchestrion.tool.go
git commit -m "chore: enable orchestrion"

Usage

Use one of these methods to enable Orchestrion in your build process:

1 Prepend orchestrion to your usual go commands:

orchestrion go build .
orchestrion go run .
orchestrion go test ./...

2 Add the -toolexec="orchestrion toolexec" argument to your go commands:

go build -toolexec="orchestrion toolexec" .
go run -toolexec="orchestrion toolexec" .
go test -toolexec="orchestrion toolexec" ./...

3 Modify the $GOFLAGS environment variable to inject Orchestrion, and use go commands normally:

# Make sure to include the quotes as shown below, as these are required for
# the Go toolchain to parse GOFLAGS properly!
export GOFLAGS="${GOFLAGS} '-toolexec=orchestrion toolexec'"
go build .
go run .
go test ./...

More Documentation


Manual instrumentation

Install the DDTrace Golang SDK:

go get gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer

Install the profiling library

go get gopkg.in/DataDog/dd-trace-go.v1/profiler

Other libraries related to components, as needed, for example:

go get gopkg.in/DataDog/dd-trace-go.v1/contrib/gorilla/mux
go get gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http
go get gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql

We can learn more about available tracing SDKs from the Github plugin library or Datadog's related support documentation.

Code Examples

Simple HTTP Server

http-server.go
package main

import (
  "log"
  "net/http"
  "time"

  httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
  "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
  "gopkg.in/DataDog/dd-trace-go.v1/profiler"
)

func main() {
  tracer.Start(
    tracer.WithService("test"),
    tracer.WithEnv("test"),
  )
  defer tracer.Stop()

  err := profiler.Start(
    profiler.WithService("test"),
    profiler.WithEnv("test"),
    profiler.WithProfileTypes(
      profiler.CPUProfile,
      profiler.HeapProfile,
      // The profiles below are disabled by
      // default to keep overhead low, but
      // can be enabled as needed.
      // profiler.BlockProfile,
      // profiler.MutexProfile,
      // profiler.GoroutineProfile,
    ),
  )
  if err != nil {
    log.Fatal(err)
  }
  defer profiler.Stop()

  // Create a traced mux router
  mux := httptrace.NewServeMux()
  // Continue using the router as you normally would.
  mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    time.Sleep(time.Second)
    w.Write([]byte("Hello World!"))
  })
  if err := http.ListenAndServe(":18080", mux); err != nil {
    log.Fatal(err)
  }
}

Compile and run

go build http-server.go -o http-server
DD_AGENT_HOST=localhost DD_TRACE_AGENT_PORT=9529 ./http-server
go build http-server.go -o http-server
$env:DD_AGENT_HOST="localhost"; $env:DD_TRACE_AGENT_PORT="9529"; .\http-server.exe

Manual Tracing

The following code demonstrates trace data collection for a file opening operation.

In the main() entry code, set the basic trace parameters and start tracing:

main.go
package main

import (
    "io/ioutil"
    "os"
    "time"

    "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
    "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
)

func main() {
    tracer.Start(
        tracer.WithEnv("prod"),
        tracer.WithService("test-file-read"),
        tracer.WithServiceVersion("1.2.3"),
        tracer.WithGlobalTag("project", "add-ddtrace-in-golang-project"),
    )

    // end of app exit, make sure tracer stopped
    defer tracer.Stop()

    tick := time.NewTicker(time.Second)
    defer tick.Stop()

    // your-app-main-entry...
    for {
        runApp()
        runAppWithError()

        select {
        case <-tick.C:
        }
    }
}

func runApp() {
    var err error
    // Start a root span.
    span := tracer.StartSpan("get.data")
    defer span.Finish(tracer.WithError(err))

    // Create a child of it, computing the time needed to read a file.
    child := tracer.StartSpan("read.file", tracer.ChildOf(span.Context()))
    child.SetTag(ext.ResourceName, os.Args[0])

    // Perform an operation.
    var bts []byte
    bts, err = ioutil.ReadFile(os.Args[0])
    span.SetTag("file_len", len(bts))
    child.Finish(tracer.WithError(err))
}

func runAppWithError() {
    var err error
    // Start a root span.
    span := tracer.StartSpan("get.data")

    // Create a child of it, computing the time needed to read a file.
    child := tracer.StartSpan("read.file", tracer.ChildOf(span.Context()))
    child.SetTag(ext.ResourceName, "somefile-not-found.go")

    defer func() {
        child.Finish(tracer.WithError(err))
        span.Finish(tracer.WithError(err))
    }()

    // Perform an error operation.
    if _, err = ioutil.ReadFile("somefile-not-found.go"); err != nil {
        // error handle
    }
}

Compile and run

go build main.go -o my-app
DD_AGENT_HOST=localhost DD_TRACE_AGENT_PORT=9529 ./my-app
go build main.go -o my-app.exe
$env:DD_AGENT_HOST="localhost"; $env:DD_TRACE_AGENT_PORT="9529"; .\my-app.exe

After running the program for a while, you can see trace data similar to the following in GuanceCloud:

Golang program trace data display

Supported Environment Variables

The following environment variables are supported to specify some configuration parameters of DDTrace when starting the program, and their basic form is:

DD_XXX=<env-value> DD_YYY=<env-value> ./my-app

For more environment variable support, see DDTrace-Go Documentation.

Attention

These environment variables will be overridden by the corresponding fields injected with WithXXX() in the code, so the configuration injected by the code has a higher priority. These ENVs only take effect when the corresponding fields are not specified in the code.

  • DD_VERSION

    Sets the application version, such as 1.2.3, 2022.02.13

  • DD_SERVICE

    Sets the application service name

  • DD_ENV

    Sets the current environment of the application, such as prod, pre-prod, etc.

  • DD_AGENT_HOST

    Default: localhost

    Sets the IP address of DataKit, and the trace data generated by the application will be sent to Datakit

  • DD_TRACE_AGENT_PORT

    Sets the DataKit trace data receiving port. Here you need to manually specify the DataKit HTTP port (usually 9529)

  • DD_DOGSTATSD_PORT

    Default value: 8125 If you want to receive StatsD data generated by DDTrace, you need to manually enable the StatsD collector on Datakit

  • DD_TRACE_SAMPLING_RULES

    Default: nil

    Here a JSON array is used to represent the sampling settings (sampling rate application is in array order), where sample_rate is the sampling rate, and the value range is [0.0, 1.0].

    Example 1: Set the global sampling rate to 20%: DD_TRACE_SAMPLING_RULES='[{"sample_rate": 0.2}]' ./my-app

    Example 2: Service name wildcard app1.*, and the span name is abc, set the sampling rate to 10%, otherwise, set the sampling rate to 20%: DD_TRACE_SAMPLING_RULES='[{"service": "app1.*", "name": "b", "sample_rate": 0.1}, {"sample_rate": 0.2}]' ./my-app

  • DD_TRACE_SAMPLE_RATE

    Default: nil

    Enable the above sampling rate switch

  • DD_TRACE_RATE_LIMIT

    Sets the number of span samples per second for each Golang process. If DD_TRACE_SAMPLE_RATE is already turned on, the default is 100

  • DD_TAGS

    Default: []

    Here you can inject a set of global tags, which will appear in each span and profile data. Multiple tags can be separated by spaces and commas, such as layer:api,team:intake, layer:api team:intake

  • DD_TRACE_STARTUP_LOGS

    Default: true

    Enable DDTrace-related configuration and diagnostic logs

  • DD_TRACE_DEBUG

    Default: false

    Enable DDTrace-related debug logs

  • DD_TRACE_ENABLED

    Default: true

    Enable trace switch. If this switch is manually turned off, no trace data will be generated

  • DD_SERVICE_MAPPING

    Default: null Dynamically rename service names, service name mappings can be separated by spaces and commas, such as mysql:mysql-service-name,postgres:postgres-service-name, mysql:mysql-service-name postgres:postgres-service-name


Feedback

Is this page helpful? ×