OpenTelemetry Go (otelc)¶
OpenTelemetry Go Compile-Time Instrumentation uses otelc to automatically inject OpenTelemetry SDK initialization and component instrumentation logic during the Go compilation phase. The application does not need to modify business code; simply replace the original go build with go tool otelc go build to send telemetry data via OTLP to DataKit, which then forwards it to TrueWatch.
This document uses otelc v1.1.0, a host-installed DataKit, and OTLP/gRPC as an example to complete Trace integration for a Go HTTP service:
Note: The "zero-code" in
otelcmeans that business code does not need to manually import and initialize the OpenTelemetry SDK; it does not mean that rebuilding is unnecessary. A normal Go binary that has already been built cannot be directly instrumented after the fact; you must recompile usingotelcand deploy the new artifact.
Prerequisites¶
- Go 1.25 or higher;
- The project uses Go Modules and can be compiled normally with a plain
go build; - DataKit is installed and connected to the target TrueWatch workspace;
- The Go application has network reachability to DataKit: OTLP/gRPC uses port
4317by default, OTLP/HTTP uses DataKit HTTP port9529; - The framework or components used by the application are supported by
otelc v1.1.0; - The application does not initialize the OpenTelemetry SDK more than once. Projects that need to manage the SDK lifecycle themselves should use the OpenTelemetry Go SDK integration approach.
This document uses a Linux host and a net/http service for explanation; it does not cover Kubernetes deployment.
1. Enable the OpenTelemetry Collector¶
Navigate to the DataKit OpenTelemetry collector directory. If the configuration file does not yet exist, copy the sample configuration:
Ensure that opentelemetry.conf contains at least the following configuration:
[[inputs.opentelemetry]]
# Whitelist of custom attributes to retain as TrueWatch tags.
customer_tags = ["team", "project"]
[inputs.opentelemetry.http]
http_status_ok = 200
trace_api = "/otel/v1/traces"
metric_api = "/otel/v1/metrics"
[inputs.opentelemetry.grpc]
addr = "127.0.0.1:4317"
The above configuration corresponds to the following receive endpoints:
| Protocol | Data Type | DataKit Receive Address |
|---|---|---|
| OTLP/gRPC | Trace, Metric | http://<DataKit-IP>:4317 |
| OTLP/HTTP + Protobuf | Trace | http://<DataKit-IP>:9529/otel/v1/traces |
| OTLP/HTTP + Protobuf | Metric | http://<DataKit-IP>:9529/otel/v1/metrics |
When the application and DataKit are not on the same host, adjust the gRPC addr to a listen address reachable by the application, for example 0.0.0.0:4317, and configure the firewall or other network access controls accordingly. Do not expose the OTLP receive port directly to the public network.
Restart DataKit for the configuration to take effect:
Check DataKit and the gRPC port:
2. Integrate the Application with OpenTelemetry¶
Pre-instrumentation Check¶
Navigate to the Go Module root directory of the application and first confirm that the original project can be built normally:
If the current directory does not yet have a go.mod, initialize the Module:
Check whether the project already directly depends on the OpenTelemetry SDK or Contrib instrumentation libraries:
otelc injects the SDK initialization logic. If the project already has another set of SDK initialization or duplicate HTTP instrumentation, it may cause duplicate spans, provider overwrites, or dependency version conflicts. This document recommends that business code does not directly integrate the SDK.
Install otelc¶
Use the Go tool directive to install and pin otelc v1.1.0:
Verify the tool version:
Expected output:
In production builds, pin the version in go.mod and go.sum; do not use an unpinned @latest.
Compile with otelc¶
Keep the original build parameters unchanged, only prepend go tool otelc before go build:
Example with common build flags:
mkdir -p ./bin
go tool otelc go build \
-trimpath \
-ldflags="-s -w" \
-o ./bin/my-service \
./cmd/my-service
otelc go currently supports go build, go install, and go test. The first instrumentation build needs to download and compile OpenTelemetry dependencies, which is usually noticeably slower than a normal go build; when the command prompt reappears in the terminal, the build is complete.
After the build finishes, the matched rules are recorded in .otelc-build/matched.json. Check for the HTTP server hook:
jq -e '[.. | objects | .name?] | index("server_hook") != null' \
.otelc-build/matched.json >/dev/null
Note: The release process must deploy the binary produced by
go tool otelc go build. If the artifact is later overwritten by a plaingo build, the runtime will not include automatic instrumentation.
Configure OTLP/gRPC and Start¶
The following configuration enables only net/http Trace and reports to the local DataKit via OTLP/gRPC:
export OTEL_SERVICE_NAME="my-service"
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=prod,service.version=1.0.0,team=backend"
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="none"
export OTEL_LOGS_EXPORTER="none"
export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4317"
export OTEL_EXPORTER_OTLP_INSECURE="true"
export OTEL_GO_ENABLED_INSTRUMENTATIONS="nethttp"
./my-service
The runtime parameters must be set in the actual runtime environment of the instrumented binary, not just on the build host. After the application starts, request an endpoint handled by a supported component to generate a verifiable span.
In production, use TLS endpoints and manage certificates and authentication headers via Secrets. http://127.0.0.1:4317 is only suitable for localhost access.
Use OTLP/HTTP¶
If you want to switch to OTLP/HTTP + Protobuf, replace the protocol and endpoint:
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:9529/otel"
export OTEL_EXPORTER_OTLP_INSECURE="true"
The exporter appends /v1/traces or /v1/metrics based on the data type. When setting only the Trace endpoint, you can also use:
3. Data Reporting Parameters¶
Resource and Exporter Parameters¶
| Environment Variable | Description | Suggested Value or Example |
|---|---|---|
OTEL_SERVICE_NAME |
Core field for APM service attribution in TrueWatch | my-service, must be set explicitly |
OTEL_RESOURCE_ATTRIBUTES |
Resource attributes, multiple key=value separated by commas |
deployment.environment.name=prod,service.version=1.0.0 |
OTEL_TRACES_EXPORTER |
Trace exporter | Set to otlp when reporting to DataKit |
OTEL_METRICS_EXPORTER |
Metric exporter | Set to none when not collecting metrics |
OTEL_LOGS_EXPORTER |
Log exporter | Set to none when not collecting application logs via OTLP |
OTEL_EXPORTER_OTLP_PROTOCOL |
Common OTLP protocol | grpc or http/protobuf |
OTEL_EXPORTER_OTLP_ENDPOINT |
Common endpoint for all OTLP signals | gRPC: http://datakit-host:4317 |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
Trace-only endpoint, takes precedence over the common value | HTTP: http://datakit-host:9529/otel/v1/traces |
OTEL_EXPORTER_OTLP_INSECURE |
Whether to use non-TLS connection | Set to true for local plaintext connection |
OTEL_EXPORTER_OTLP_HEADERS |
OTLP request authentication headers | Injected via Secret, not written into code or image |
Instrumentation, Sampling, and Debug Parameters¶
| Environment Variable | Description | Suggested Value or Example |
|---|---|---|
OTEL_GO_ENABLED_INSTRUMENTATIONS |
Runtime instrumentation whitelist | Use nethttp for HTTP services |
OTEL_GO_DISABLED_INSTRUMENTATIONS |
Runtime instrumentation blacklist | Disable as needed, e.g. redis |
OTEL_TRACES_SAMPLER |
Trace sampler | Use parentbased_always_on for integration verification |
OTEL_TRACES_SAMPLER_ARG |
Proportional sampling parameter | e.g. 0.10, used with parentbased_traceidratio |
OTEL_PROPAGATORS |
Trace context propagation format | tracecontext,baggage |
OTEL_LOG_LEVEL |
Log level of the otelc injected runtime |
Default info, use debug for troubleshooting |
OTEL_GO_SIMPLE_SPAN_PROCESSOR |
Whether to export spans immediately one by one | Set to true only for local troubleshooting |
OTEL_SDK_DISABLED |
Whether to disable the injected SDK | true stops collection and reporting |
OTELC_DEBUG |
Whether to record detailed build logs | Set to 1 for troubleshooting |
OTEL_GO_ENABLED_INSTRUMENTATIONS and OTEL_GO_DISABLED_INSTRUMENTATIONS only control the instrumentation that was already compiled into the binary. When both variables are present, the whitelist is applied first, then the blacklist is excluded.
In production, set the sampling rate based on traffic and data budget. When application-side sampling and DataKit-side sampling are both enabled, the final retention rate is compounded and reduced; plan the sampling location uniformly.
Supported Components¶
otelc v1.1.0 includes built-in rules covering the following common components:
| Type | Components |
|---|---|
| HTTP | net/http client and server, Gin |
| RPC | gRPC client and server |
| Database | database/sql, Redis v9, MongoDB |
| Message Queue | Kafka Go |
| Cloud and Infrastructure | Kubernetes client-go, AWS SDK for Go v2, Linode Go v2 |
| GenAI | OpenAI Go v1/v2/v3, Anthropic Go SDK |
| Log Correlation | Standard library log, log/slog, Logrus |
Actual support scope may be affected by component versions and build methods. After upgrading application dependencies or otelc, re-check .otelc-build/matched.json and perform trace regression tests.
Field Mapping¶
The DataKit OpenTelemetry collector maps common OpenTelemetry Span Attributes to TrueWatch trace fields:
| OpenTelemetry Attribute | DataKit Field |
|---|---|
http.request.method |
http_method |
http.response.status_code |
http_status_code |
network.protocol.name |
net_protocol_name |
network.protocol.version |
net_protocol_version |
db.system.name |
db_system |
db.operation.name |
db_operation |
db.query.text |
db_statement |
rpc.system.name |
rpc_system |
rpc.method |
rpc_method |
To retain other attributes as TrueWatch tags, configure customer_tags in the DataKit opentelemetry.conf. Do not promote high-cardinality values (such as user IDs, order numbers) to tags in bulk, and do not report sensitive information such as passwords, tokens, or full database connection strings.
Verify Integration¶
- Confirm that the tool version and instrumentation build are both successful:
- Start the application and confirm that the following log entries appear, and there are no OTLP export errors:
trace provider initialized with auto-export
OpenTelemetry initialized
HTTP server instrumentation initialized
- Request an application endpoint to generate a trace:
- Check that the build rules include
server_hook:
- When using OTLP/gRPC, you can observe the receive count increase on the DataKit host:
curl -fsS http://127.0.0.1:9529/metrics \
| grep 'opentelemetry.proto.collector.trace.v1.TraceService/Export'
- Go to TrueWatch APM > Traces, search by
service:my-service, and verify that you can see the trace generated by the request.
Frequently Asked Questions¶
go.mod file not found¶
go get -tool must be executed within a Go Module. Go to the project root directory, or first run:
Build hangs at WORK=/tmp/go-build...¶
The first instrumentation build compiles many dependencies. As long as the go tool otelc go build process is still running, wait for it to finish; the build is complete only when the command prompt reappears in the terminal. Do not execute the application binary mid-build.
Connection failed to the request port¶
First confirm that the build has finished and the instrumented binary has been started, then check the listening port:
Application runs normally but no Trace in TrueWatch¶
Check, in order:
- Whether the deployed binary was produced by
go tool otelc go build; - Whether
OTEL_SERVICE_NAME, the exporter, protocol, and endpoint are configured in the actual running process; - Whether
.otelc-build/matched.jsoncontains the expected rules; - Whether
OTEL_GO_ENABLED_INSTRUMENTATIONSincludes the target component; - Whether the DataKit OpenTelemetry collector is enabled and restarted for the changes to take effect;
- Whether the network from the application to DataKit and ports
4317or9529are reachable.
For build issues, you can temporarily enable detailed logging:
Detailed logs are located at .otelc-build/debug.log. Disable debug after troubleshooting to avoid log growth.
Application does not exit after the first Ctrl+C¶
The runtime injected by otelc v1.1.0 listens for SIGINT and SIGTERM; the first signal is used to flush telemetry data, but the application is still responsible for its own exit flow. Simple applications that do not implement graceful shutdown may need a second signal. Production services should use the Go standard library to implement graceful HTTP server shutdown and reserve time for telemetry flushing.