examples/tutorials/basic_opentelemetry.md
OpenTelemetry provides powerful observability tools for your applications. With Deno's built-in OpenTelemetry support, you can easily instrument your code to collect metrics, traces, and logs.
This tutorial will walk you through setting up a simple Deno application with OpenTelemetry instrumentation.
Let's start by creating a basic HTTP server that simulates a small web application:
import { metrics, trace } from "npm:@opentelemetry/api@1";
// Create a tracer and meter for our application
const tracer = trace.getTracer("my-server", "1.0.0");
const meter = metrics.getMeter("my-server", "1.0.0");
// Create some metrics
const requestCounter = meter.createCounter("http_requests_total", {
description: "Total number of HTTP requests",
});
const requestDuration = meter.createHistogram("http_request_duration_ms", {
description: "HTTP request duration in milliseconds",
unit: "ms",
});
// Start the server
Deno.serve({ port: 8000 }, (req) => {
// Record the start time for measuring request duration
const startTime = performance.now();
// Create a span for this request
return tracer.startActiveSpan("handle_request", async (span) => {
try {
// Extract the path from the URL
const url = new URL(req.url);
const path = url.pathname;
// Add attributes to the span
span.setAttribute("http.route", path);
span.setAttribute("http.method", req.method);
span.updateName(`${req.method} ${path}`);
// Add an event to the span
span.addEvent("request_started", {
timestamp: startTime,
request_path: path,
});
// Simulate some processing time
const waitTime = Math.random() * 100;
await new Promise((resolve) => setTimeout(resolve, waitTime));
// Add another event to the span
span.addEvent("processing_completed");
// Create the response
const response = new Response(`Hello from ${path}!`, {
headers: { "Content-Type": "text/plain" },
});
// Record metrics
requestCounter.add(1, {
method: req.method,
path,
status: 200,
});
const duration = performance.now() - startTime;
requestDuration.record(duration, {
method: req.method,
path,
});
span.setAttribute("request.duration_ms", duration);
return response;
} catch (error) {
// Record error in span
if (error instanceof Error) {
span.recordException(error);
span.setStatus({
code: trace.SpanStatusCode.ERROR,
message: error.message,
});
}
return new Response("Internal Server Error", { status: 500 });
} finally {
// Always end the span
span.end();
}
});
});
This server:
To run the server with OpenTelemetry, use these flags:
OTEL_DENO=true OTEL_SERVICE_NAME=my-server deno run --allow-net server.ts
Let's create a simple client to send requests to our server:
// Send 10 requests to different paths
for (let i = 0; i < 10; i++) {
const path = ["", "about", "users", "products", "contact"][i % 5];
const url = `http://localhost:8000/${path}`;
console.log(`Sending request to ${url}`);
try {
const response = await fetch(url);
const text = await response.text();
console.log(`Response from ${url}: ${text}`);
} catch (error) {
console.error(`Error fetching ${url}:`, error);
}
}
In a separate terminal, run the client:
deno run --allow-net client.ts
By default, Deno exports telemetry data to http://localhost:4318 using the
OTLP protocol. You'll need an OpenTelemetry collector to receive and visualize
this data.
The quickest way to get started is with a local LGTM stack (Loki, Grafana, Tempo, Mimir) in Docker:
docker run --name lgtm -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti \
-v "$PWD"/lgtm/grafana:/data/grafana \
-v "$PWD"/lgtm/prometheus:/data/prometheus \
-v "$PWD"/lgtm/loki:/data/loki \
-e GF_PATHS_DATA=/data/grafana \
docker.io/grafana/otel-lgtm:0.8.1
Then access Grafana at http://localhost:3000 (username: admin, password: admin).
In Grafana, you can:
In the Traces view, you'll see spans for:
Click on any span to see its details, including:
In the Metrics view, you can query for:
http_requests_total - The counter tracking the number of HTTP requestshttp_request_duration_ms - The histogram of request durationsYou can also see built-in Deno metrics like:
http.server.request.durationhttp.server.active_requestsIn the Logs view, you'll see all console logs from your application with correct trace context.
If you're not seeing data in your collector:
OTEL_DENO=trueOTEL_EXPORTER_OTLP_ENDPOINT to a different URLRemember that OpenTelemetry support in Deno is still marked as unstable and may change in future versions.
š¦ This tutorial provides a simple starting point for users who want to experiment with OpenTelemetry in Deno without diving into more complex concepts immediately.
This basic example can be extended in many ways:
For more advanced usage, see our Distributed Tracing with Context Propagation tutorial.