Language guides

How to send from each language with standard OpenTelemetry, today, without a Flowhawk package.

The Flowhawk SDKs aren't published to the public package registries yet. Until they are, use each language's OpenTelemetry SDK as shown below. You get traces, logs and metrics, and Flowhawk matches requests to your flows on our side by service and route. Once the Flowhawk SDKs are out, switching to them adds exact flow tags across services and sampling per flow. Nothing else changes.

The same settings everywhere

Every OpenTelemetry SDK reads these environment variables. Create an Ingest key in Settings > API keys first.

OTEL_SERVICE_NAME=orders
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.flowhawk.dev
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20<ingest key>
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.version=1.4.2

The space in the header is written %20. If your SDK sends that literally and telemetry is refused, use Authorization=<ingest key> without Bearer. Flowhawk accepts both. Set service.version to your release, so deploys show as changes next to your flows. Keep the key out of your repository, like any other secret.

Node.js

npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.js

This instruments HTTP, Express, Fastify, the common database clients and more, with no code change.

Python

pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install     # adds instrumentation for the libraries you use
opentelemetry-instrument python app.py

Works the same with gunicorn or uvicorn after opentelemetry-instrument. Set OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true to send logs too.

Java and Kotlin

curl -LO https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
java -javaagent:opentelemetry-javaagent.jar -jar app.jar

The agent covers Spring, servlet containers, JDBC, Kafka and most HTTP clients, and sends logs from Logback and Log4j.

Go

go get go.opentelemetry.io/otel go.opentelemetry.io/otel/sdk \
  go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
  go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
exp, err := otlptracehttp.New(ctx) // reads the OTEL_ variables above
if err != nil { log.Fatal(err) }
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exp))
defer tp.Shutdown(ctx)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.TraceContext{})

http.ListenAndServe(":8080", otelhttp.NewHandler(mux, "server"))

Use http.Handle("/orders/{id}", otelhttp.WithRouteTag("/orders/{id}", h)) or your router's OpenTelemetry middleware so spans carry the route.

.NET

dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
builder.Services.AddOpenTelemetry()
    .WithTracing(t => t.AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddOtlpExporter())
    .WithMetrics(m => m.AddAspNetCoreInstrumentation().AddOtlpExporter());
builder.Logging.AddOpenTelemetry(l => l.AddOtlpExporter());

Ruby

bundle add opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-instrumentation-all
# config/initializers/opentelemetry.rb (or before your app loads)
require "opentelemetry/sdk"
require "opentelemetry/exporter/otlp"
require "opentelemetry/instrumentation/all"
OpenTelemetry::SDK.configure { |c| c.use_all }

PHP

pecl install opentelemetry          # the extension that auto-instrumentation needs
composer require open-telemetry/sdk open-telemetry/exporter-otlp \
  open-telemetry/opentelemetry-auto-laravel   # or -slim, -symfony, -psr15

Then set OTEL_PHP_AUTOLOAD_ENABLED=true with the settings above.

Browser and mobile

For web and mobile apps, keep or add a Sentry SDK and point its DSN at Flowhawk with a Browser key. That key is meant to be public and can only send data. The DSN looks like https://<browser key>@api.flowhawk.dev/1. Errors, page loads, web vitals and replays arrive as the same data the Flowhawk browser and mobile SDKs send. See Sending data.

Through an OpenTelemetry Collector

exporters:
  otlphttp/flowhawk:
    endpoint: https://ingest.flowhawk.dev
    headers:
      Authorization: Bearer ${env:FLOWHAWK_API_KEY}
service:
  pipelines:
    traces:  { receivers: [otlp], exporters: [otlphttp/flowhawk] }
    logs:    { receivers: [otlp], exporters: [otlphttp/flowhawk] }
    metrics: { receivers: [otlp], exporters: [otlphttp/flowhawk] }

Check it arrived

Open Setup in the app. It lists each service that sent data in the last 15 minutes. If nothing shows, Help and troubleshooting says why telemetry is refused (a wrong key, an empty balance) and how to see it.