Dynatrace Provider¶
The Dynatrace provider exports telemetry to Dynatrace using OTLP via HTTP.
Installation¶
import (
"github.com/plexusone/omniobserve/observops"
_ "github.com/plexusone/omniobserve/observops/dynatrace"
)
Configuration¶
Dynatrace SaaS¶
provider, err := observops.Open("dynatrace",
observops.WithEndpoint("https://{environment-id}.live.dynatrace.com/api/v2/otlp"),
observops.WithAPIKey("dt0c01.XXXXXXXX.YYYYYYYY"),
observops.WithServiceName("my-service"),
)
Dynatrace Managed¶
provider, err := observops.Open("dynatrace",
observops.WithEndpoint("https://{your-domain}/e/{environment-id}/api/v2/otlp"),
observops.WithAPIKey("dt0c01.XXXXXXXX.YYYYYYYY"),
observops.WithServiceName("my-service"),
)
Via ActiveGate¶
provider, err := observops.Open("dynatrace",
observops.WithEndpoint("https://{activegate-address}:9999/e/{environment-id}/api/v2/otlp"),
observops.WithAPIKey("dt0c01.XXXXXXXX.YYYYYYYY"),
observops.WithServiceName("my-service"),
)
Full Configuration¶
provider, err := observops.Open("dynatrace",
observops.WithEndpoint("https://abc12345.live.dynatrace.com/api/v2/otlp"),
observops.WithAPIKey("dt0c01.XXXXXXXX.YYYYYYYY"),
observops.WithServiceName("my-service"),
observops.WithServiceVersion("1.0.0"),
observops.WithBatchTimeout(5*time.Second),
observops.WithResource(&observops.Resource{
DeploymentEnv: "production",
Attributes: map[string]string{
"host.name": "server-01",
},
}),
)
Endpoint Formats¶
| Deployment | Endpoint Format |
|---|---|
| SaaS | https://{environment-id}.live.dynatrace.com/api/v2/otlp |
| Managed | https://{your-domain}/e/{environment-id}/api/v2/otlp |
| ActiveGate | https://{activegate}:9999/e/{environment-id}/api/v2/otlp |
API Token Setup¶
Create an API token in Dynatrace with the following scopes:
| Scope | Purpose |
|---|---|
openTelemetryTrace.ingest |
Traces |
metrics.ingest |
Metrics |
logs.ingest |
Logs |
Creating a Token¶
- Go to Settings > Integration > Dynatrace API
- Click Generate token
- Name your token (e.g., "OmniObserve OTLP Ingest")
- Select the required scopes
- Click Generate
- Copy the token (starts with
dt0c01.)
Environment Variables¶
| Variable | Description |
|---|---|
DT_API_TOKEN |
Dynatrace API token |
OTEL_EXPORTER_OTLP_ENDPOINT |
Dynatrace OTLP endpoint |
OTEL_SERVICE_NAME |
Service name |
Capabilities¶
- Metrics (counters, gauges, histograms)
- Traces (distributed tracing)
- Logs (structured logging)
- Batching
- Sampling
- Resource Detection
Protocol Notes¶
Unlike the OTLP and Datadog providers which use gRPC, the Dynatrace provider uses HTTP for OTLP ingestion. This is because Dynatrace's OTLP endpoints are HTTP-based.
The provider automatically:
- Strips the
/api/v2/otlpsuffix from your endpoint - Appends the correct paths (
/v1/traces,/v1/metrics) - Sets the
Authorization: Api-Token {token}header
Troubleshooting¶
401 Unauthorized¶
- Verify your API token is correct
- Check that the token has the required scopes
- Ensure the token hasn't expired
403 Forbidden¶
- Verify the environment ID in your endpoint is correct
- Check that your token has access to that environment
Connection Refused¶
- Verify the endpoint URL is correct
- For ActiveGate, ensure port 9999 is accessible
- Check firewall rules
Example: Full Application¶
package main
import (
"context"
"log"
"log/slog"
"os"
"time"
"github.com/plexusone/omniobserve/observops"
_ "github.com/plexusone/omniobserve/observops/dynatrace"
)
func main() {
provider, err := observops.Open("dynatrace",
observops.WithEndpoint(os.Getenv("DT_ENDPOINT")),
observops.WithAPIKey(os.Getenv("DT_API_TOKEN")),
observops.WithServiceName("my-service"),
observops.WithServiceVersion("1.0.0"),
)
if err != nil {
log.Fatal(err)
}
defer provider.Shutdown(context.Background())
// Set up logging
handler := provider.SlogHandler(
observops.WithSlogLocalHandler(slog.NewTextHandler(os.Stdout, nil)),
)
logger := slog.New(handler)
// Create a trace
ctx, span := provider.Tracer().Start(context.Background(), "main")
defer span.End()
// Log with trace correlation
logger.InfoContext(ctx, "Application started")
// Record a metric
counter, _ := provider.Meter().Counter("requests_total")
counter.Add(ctx, 1)
time.Sleep(100 * time.Millisecond)
logger.InfoContext(ctx, "Application finished")
}