Guide
Traces and metrics with OpenTelemetry (any language)
Logthread accepts standard OpenTelemetry over OTLP, so a service written in any language that has OpenTelemetry instrumentation shows up in Traces, Metrics, and the Database and Endpoints views. You do not need a Logthread package for this: set four environment variables and start your app with the OpenTelemetry instrumentation for your language. For Node.js, Python and .NET, a Logthread package does the whole setup in one call and adds a cardinality guard; each section below shows both.
The settings every language uses#
Create an ingest key under Keys in the app (it is shown once and is write-only), then set:
export OTEL_SERVICE_NAME="checkout"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.logthread.com"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20<INGEST_KEY>"- Use the base endpoint only. The SDK adds
/v1/traces,/v1/metricsand/v1/logsitself, so one key and one endpoint carry all three signals. Bearer%20is a URL-encoded space. The OpenTelemetry specification requires header values in this variable to be URL-encoded, and the language SDKs decode it before sendingAuthorization: Bearer <INGEST_KEY>. Zero-code tools that read the same variable do not all decode it. OpenTelemetry eBPF Instrumentation does not, so write a plain space there (Authorization=Bearer <INGEST_KEY>), as the zero-code tracing guide does.OTEL_SERVICE_NAMEis the name you see in Logthread. Give each service its own.- Keep the key out of source control: read it from a secret store or your deployment's environment.
Add OTEL_TRACES_EXPORTER=otlp, OTEL_METRICS_EXPORTER=otlp and OTEL_LOGS_EXPORTER=otlp if your language does not default to them. The commands below follow the OpenTelemetry documentation for each language at opentelemetry.io; check it for newer versions.
Node.js#
With Logthread's package, one call. @logthread/node/otel configures the OpenTelemetry Node SDK for the same endpoint and ingest key as your logs: OTLP over HTTP with protobuf and gzip, traces and metrics, parent-based sampling, a cardinality guard and a flush on shutdown. Install the package from the download page, then the OpenTelemetry packages it uses (they are optional peers, so the logging SDK itself stays dependency-free):
npm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/sdk-metrics @opentelemetry/resources \
@opentelemetry/exporter-trace-otlp-proto @opentelemetry/exporter-metrics-otlp-proto \
@opentelemetry/auto-instrumentations-node
export LOGTHREAD_ENDPOINT="https://ingest.logthread.com"
export LOGTHREAD_INGEST_KEY="<INGEST_KEY>"// first lines of the entry file, before other imports load http, express, pg, ...
import { startTelemetry } from '@logthread/node/otel';
const telemetry = startTelemetry({ serviceName: 'checkout', environment: 'production' });
// on shutdown: await telemetry.shutdown();Or change no code: node --import @logthread/node/otel/register app.mjs (--require for CommonJS) reads everything from LOGTHREAD_*. The auto-instrumentation covers http, Express, Fastify, pg, mysql2, mongodb, redis, Prisma and more. Metric attributes that identify a request or a user (url.path, user.id, client.address and similar) are removed and each metric is capped at 500 series, so one busy label cannot create thousands of series. Options, environment variables and the sampling ratio are in the Node.js SDK page.
Without it, standard OpenTelemetry (the four variables above):
npm install --save @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.jsOr set NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" and run node app.js.
- Endpoints view:
http, Express, Fastify, Koa, NestJS and other HTTP server instrumentations. - Database view:
pg,mysql2,mongodb,redis,ioredisand other client instrumentations.
Send traces and metrics from Python#
With Logthread's package, one call. The otel extra of logthread configures opentelemetry-sdk for the same endpoint and ingest key as your logs: OTLP over HTTP with protobuf and gzip, traces and metrics, parent-based sampling, a cardinality guard and a flush on shutdown. Install it from the exact wheel on the download page:
pip install "logthread[otel] @ https://downloads.logthread.com/sdk/python/<version>/logthread-<version>-py3-none-any.whl"
pip install opentelemetry-distro && opentelemetry-bootstrap -a install # instrumentation for the libraries you use
export LOGTHREAD_ENDPOINT="https://ingest.logthread.com"
export LOGTHREAD_INGEST_KEY="<INGEST_KEY>"# first lines of the entry file, before the code you want traced is imported
from logthread.otel import start_telemetry
telemetry = start_telemetry(service_name="checkout", environment="production")
# telemetry.shutdown() flushes; it also runs when the interpreter exitsOr change no code: python -m logthread.otel app.py (or python -m logthread.otel -m uvicorn app:app) reads everything from LOGTHREAD_*. Metric attributes that identify a request or a user (url.path, user.id, client.address and similar) are removed and each metric is capped at 500 series per export. Options and environment variables are in the Python SDK page. Under gunicorn, uvicorn or Celery, call telemetry.shutdown() where you call logthread.shutdown(), because Python does not run exit hooks on SIGTERM.
Without it, standard OpenTelemetry (the four variables above):
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
opentelemetry-instrument python app.pyopentelemetry-bootstrap -a install installs the instrumentation for every library it finds in your environment.
- Endpoints view: Django, Flask, FastAPI, Starlette, aiohttp server.
- Database view: psycopg, psycopg2, asyncpg, mysql, PyMySQL, SQLAlchemy, pymongo, redis.
Java#
curl -fsSLO https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
java -javaagent:./opentelemetry-javaagent.jar -jar app.jarOr set JAVA_TOOL_OPTIONS="-javaagent:/path/to/opentelemetry-javaagent.jar". The agent also records JVM metrics.
- Endpoints view: Spring MVC and WebFlux, Servlet containers, Micronaut, Quarkus, Ktor and other HTTP servers.
- Database view: JDBC (every JDBC driver), Hibernate, R2DBC, MongoDB, Redis clients.
Go#
Go has no in-process agent. Either add the SDK and the instrumentation libraries to your code, or run the OpenTelemetry eBPF instrumentation (OBI) next to the process on Linux. For the SDK route:
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/otelhttpThe exporters read the OTEL_EXPORTER_OTLP_* variables above. Wrap your handler with otelhttp.NewHandler for the Endpoints view, and wrap your database client with an OpenTelemetry-instrumented driver such as github.com/XSAM/otelsql for the Database view. The Set up page in the app (source "OpenTelemetry SDK", language Go) shows a complete main.go. See the OpenTelemetry Go and OBI documentation for details.
.NET#
With Logthread's package, one line adds traces, metrics, EF Core and SqlClient queries, endpoints and a cardinality guard:
dotnet add package Logthread.OpenTelemetrybuilder.AddLogthread();See Logthread for .NET and .NET end to end. Without it, the OpenTelemetry automatic instrumentation works too: download the installer from the opentelemetry-dotnet-instrumentation releases, then in the shell that starts your app:
sh ./otel-dotnet-auto-install.sh
. $HOME/.otel-dotnet-auto/instrument.sh
./MyNetAppOn Windows, use the OpenTelemetry.DotNet.Auto.psm1 module from the same release (Install-OpenTelemetryCore, then Register-OpenTelemetryForCurrentSession). The OpenTelemetry docs recommend verifying the downloaded script with gh attestation verify.
- Endpoints view: ASP.NET Core.
- Database view: SqlClient, Entity Framework Core, Npgsql.
Ruby#
bundle add opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-instrumentation-all# config/initializers/opentelemetry.rb
require 'opentelemetry/sdk'
require 'opentelemetry/exporter/otlp'
require 'opentelemetry/instrumentation/all'
OpenTelemetry::SDK.configure do |c|
c.use_all # every available instrumentation; service name comes from OTEL_SERVICE_NAME
end- Endpoints view: Rails, Sinatra, Rack.
- Database view: ActiveRecord, pg, mysql2, trilogy, Redis.
PHP#
pecl install opentelemetryEnable it in php.ini with extension=opentelemetry.so, check with php -m | grep opentelemetry, then:
composer require open-telemetry/sdk open-telemetry/exporter-otlp \
open-telemetry/opentelemetry-auto-slim open-telemetry/opentelemetry-auto-psr18
export OTEL_PHP_AUTOLOAD_ENABLED=true
export OTEL_TRACES_EXPORTER=otlp
php app.phpAdd the auto-instrumentation package for your framework and database layer (for example open-telemetry/opentelemetry-auto-laravel and open-telemetry/opentelemetry-auto-pdo, listed in the OpenTelemetry registry).
- Endpoints view: Laravel, Slim, Symfony and other frameworks that have an instrumentation package.
- Database view: PDO, mysqli.
Any other language#
Any OpenTelemetry SDK works the same way: point its OTLP exporter at https://ingest.logthread.com with the Authorization header above, using http/protobuf. The OpenTelemetry Collector works too: use the otlphttp exporter with the same endpoint and header.
No code changes: eBPF auto-instrumentation (Linux)#
Beta. When you cannot change or redeploy a service's code, OpenTelemetry eBPF Instrumentation (OBI, an OpenTelemetry project) can trace it from the Linux kernel. It sends HTTP, gRPC, SQL, Redis and Kafka spans and request metrics to Logthread with your ingest key, and they appear in Traces, Endpoints, Database and the Service map like any other OpenTelemetry data. Logthread has tested OBI v0.15.2.
The zero-code tracing guide covers the requirements (Linux 5.8+ with BTF, root or specific capabilities), copy-paste installs for docker run, Docker Compose, a Kubernetes DaemonSet, systemd and the Logthread Agent's autotrace profile, how to check it works, troubleshooting and uninstall. In the app, Sources → Add source → eBPF (no code, Linux) fills in your endpoint and key.
Two things differ from the SDK settings above: the header is Authorization=Bearer <INGEST_KEY> with a space (OBI does not decode %20), and each service's name comes from its own OTEL_SERVICE_NAME. There is no Windows, IIS or macOS support: on Windows use the Logthread Agent and the .NET SDK. Some languages give single-span traces; the guide's limits section says when.
What the Database and Endpoints views read#
Both views are built from standard span attributes, in the older and the current semantic-convention names:
| View | Spans | Attributes read |
|---|---|---|
| Database | client spans of database calls | db.query.text or db.statement, db.system.name or db.system |
| Endpoints | server spans of HTTP requests | http.request.method or http.method, http.route, url.path or http.target |
Instrumentation that sets http.route gives one row per route (/orders/{id}) instead of one per URL, so prefer a framework instrumentation over a bare HTTP one. Logthread normalises statement text and shows no parameter values. If your driver puts values in the statement, use its parameterised form.
Logs#
Traces and metrics need no Logthread package (Node.js, Python and .NET have one that does the setup in one call). For logs with per-request correlation ids, use the SDKs: Node.js, Python and .NET. Other languages can send logs through the OpenTelemetry logs SDK with the same settings.
Check that data arrives#
Open Traces in the app a minute after your first request. If nothing appears, check that the endpoint has no path, that the header has the Bearer%20 prefix, and that your app is making requests that the instrumentation covers.
Next: link your logs to these traces in Correlate logs and traces.