From 5682ae2c40b407dc849f99fd0165ff587638657e Mon Sep 17 00:00:00 2001 From: Jo Franchetti Date: Thu, 20 Mar 2025 13:57:50 +0000 Subject: [PATCH 1/5] adding datadog tut --- examples/tutorials/datadog.md | 333 ++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 examples/tutorials/datadog.md diff --git a/examples/tutorials/datadog.md b/examples/tutorials/datadog.md new file mode 100644 index 000000000..38bfa89d6 --- /dev/null +++ b/examples/tutorials/datadog.md @@ -0,0 +1,333 @@ +--- +title: Using Deno with Datadog +description: "Learn how to monitor your Deno applications with Datadog using OpenTelemetry. This tutorial covers setup, configuration, and sending traces, metrics, and logs to Datadog." +--- + +# Using Deno with Datadog + +This tutorial will guide you through integrating your Deno applications with +Datadog for monitoring and observability using OpenTelemetry. + +## Prerequisites + +- A Datadog account with an API key +- Deno installed on your system +- Basic knowledge of Deno and OpenTelemetry concepts + +## Overview + +Deno has built-in support for [OpenTelemetry](https://opentelemetry.io/), which +makes it possible to send telemetry data (traces, metrics, and logs) to Datadog. +This enables you to: + +1. Monitor the performance of your Deno applications +2. Track and troubleshoot errors +3. Gain insights into application behavior and user patterns +4. Set up alerts for critical issues + +## Setting Up Datadog with Deno + +### Step 1: Configure Deno to use OpenTelemetry + +To enable OpenTelemetry in Deno, you need to run your scripts with the +`--unstable-otel` flag and set the appropriate environment variables: + +```sh +OTEL_DENO=true deno run --unstable-otel your_app.ts +``` + +### Step 2: Configure the OpenTelemetry exporter for Datadog + +Datadog accepts data via the OpenTelemetry Protocol (OTLP). You'll need to +configure Deno to send data to Datadog's OTLP endpoint by setting the following +environment variables: + +```sh +# For US region (replace with your Datadog API key) +export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.datadoghq.com/api/v1/traces" +export OTEL_EXPORTER_OTLP_HEADERS="DD-API-KEY=" +export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" + +# For EU region +# export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.datadoghq.eu/api/v1/traces" +``` + +### Step 3: Configure service and resource information + +Set service name and resource attributes to properly organize your data in +Datadog: + +```sh +export OTEL_SERVICE_NAME="your-deno-service" +export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production,service.version=1.0.0" +``` + +### Step 4: Run your Deno application + +Run your application with all the required configurations: + +```sh +OTEL_DENO=true \ +OTEL_SERVICE_NAME="your-deno-service" \ +OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production,service.version=1.0.0" \ +OTEL_EXPORTER_OTLP_ENDPOINT="https://api.datadoghq.com/api/v1/traces" \ +OTEL_EXPORTER_OTLP_HEADERS="DD-API-KEY=" \ +OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" \ +deno run --unstable-otel your_app.ts +``` + +## Custom Instrumentation with Datadog + +While Deno automatically instruments certain operations like HTTP requests, you +can add custom instrumentation to track specific operations in your application. + +### Tracing with Custom Spans + +```ts +import { trace } from "npm:@opentelemetry/api@1"; + +// Create a tracer +const tracer = trace.getTracer("my-deno-app", "1.0.0"); + +// Create a custom span +function processOrder(orderId: string) { + return tracer.startActiveSpan("process_order", (span) => { + try { + // Add custom attributes to help filter and analyze in Datadog + span.setAttribute("order.id", orderId); + + // Your business logic here + const orderDetails = fetchOrderDetails(orderId); + const result = processPayment(orderDetails); + + // More attributes based on the result + span.setAttribute("payment.status", result.status); + span.setAttribute("payment.amount", result.amount); + + return result; + } catch (error) { + // Record errors to show them in Datadog + span.recordException(error); + span.setStatus({ + code: trace.SpanStatusCode.ERROR, + message: (error as Error).message, + }); + throw error; + } finally { + // Always end the span + span.end(); + } + }); +} +``` + +### Custom Metrics + +You can create custom metrics to track business-specific data: + +```ts +import { metrics } from "npm:@opentelemetry/api@1"; + +// Create a meter +const meter = metrics.getMeter("my-deno-app", "1.0.0"); + +// Create a counter for tracking orders +const orderCounter = meter.createCounter("orders.processed", { + description: "Number of orders processed", + unit: "1", +}); + +// Create a histogram for tracking order values +const orderValueHistogram = meter.createHistogram("orders.value", { + description: "Distribution of order values", + unit: "USD", +}); + +// Usage in code +function processOrder(order) { + // Increment counter with attributes for segmentation in Datadog + orderCounter.add(1, { + "order.type": order.type, + "customer.tier": order.customerTier, + }); + + // Record order value + orderValueHistogram.record(order.totalAmount, { + "order.type": order.type, + "payment.method": order.paymentMethod, + }); + + // Process the order... +} +``` + +## Example: HTTP Server with Datadog Monitoring + +Here's a complete example of a simple HTTP server with Datadog monitoring: + +```ts +import { metrics, trace } from "npm:@opentelemetry/api@1"; + +// Create instrumentations +const tracer = trace.getTracer("deno-web-server", "1.0.0"); +const meter = metrics.getMeter("deno-web-server", "1.0.0"); + +// Create metrics +const requestCounter = meter.createCounter("http.requests.total", { + description: "Total number of HTTP requests", + unit: "1", +}); + +const requestDuration = meter.createHistogram("http.requests.duration", { + description: "HTTP request duration", + unit: "ms", +}); + +// Define routes +const ROUTES = { + INDEX: new URLPattern({ pathname: "/" }), + USERS: new URLPattern({ pathname: "/users" }), + USER: new URLPattern({ pathname: "/users/:id" }), +}; + +// Start HTTP server +Deno.serve(async (req) => { + const url = new URL(req.url); + const startTime = performance.now(); + + // Get the active span (created automatically by Deno.serve) + const span = trace.getActiveSpan(); + + try { + // Route the request + if (ROUTES.INDEX.test(url)) { + // Update the span with route information + span.setAttribute("http.route", "/"); + span.updateName(`${req.method} /`); + + return new Response("Welcome to our API"); + } else if (ROUTES.USERS.test(url)) { + span.setAttribute("http.route", "/users"); + span.updateName(`${req.method} /users`); + + // Custom business logic span + return tracer.startActiveSpan("fetch_users", (childSpan) => { + try { + // Simulate database query + childSpan.setAttribute("db.operation", "SELECT"); + childSpan.setAttribute("db.table", "users"); + + const users = [{ id: 1, name: "User 1" }, { id: 2, name: "User 2" }]; + return new Response(JSON.stringify(users), { + headers: { "Content-Type": "application/json" }, + }); + } finally { + childSpan.end(); + } + }); + } else if (ROUTES.USER.test(url)) { + const match = ROUTES.USER.exec(url); + const userId = match?.pathname.groups.id; + + span.setAttribute("http.route", "/users/:id"); + span.updateName(`${req.method} /users/:id`); + span.setAttribute("user.id", userId); + + return new Response(`User ID: ${userId}`); + } else { + span.setAttribute("http.route", "not_found"); + return new Response("Not Found", { status: 404 }); + } + } catch (error) { + // Record the error + span.recordException(error); + span.setStatus({ + code: trace.SpanStatusCode.ERROR, + message: (error as Error).message, + }); + + return new Response("Internal Server Error", { status: 500 }); + } finally { + // Record metrics + const duration = performance.now() - startTime; + + requestCounter.add(1, { + "http.method": req.method, + "http.route": span.getAttribute("http.route") as string, + "http.status_code": 200, // Simplified for this example + }); + + requestDuration.record(duration, { + "http.method": req.method, + "http.route": span.getAttribute("http.route") as string, + }); + } +}); + +console.log("Server running on http://localhost:8000"); +``` + +## Viewing Data in Datadog + +After setting up your application and generating some telemetry data: + +1. Log in to your Datadog account +2. Navigate to APM > Traces to view distributed traces +3. Check APM > Services to see your service metrics +4. Use Metrics Explorer to create custom dashboards +5. Navigate to Logs if you've enabled log collection + +## Advanced Configuration + +### Sampling + +To control the volume of data sent to Datadog, you can adjust trace sampling: + +```sh +# Sample only 20% of traces +export OTEL_TRACES_SAMPLER=parentbased_traceidratio +export OTEL_TRACES_SAMPLER_ARG=0.2 +``` + +### Separate Endpoints for Different Telemetry Types + +You can configure separate endpoints for metrics, traces, and logs: + +```sh +export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://api.datadoghq.com/api/v1/traces" +export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT="https://api.datadoghq.com/api/v1/metrics" +export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="https://api.datadoghq.com/api/v1/logs" +``` + +### Console Logging Configuration + +Control how console logs are handled with OpenTelemetry: + +```sh +# Options: capture, replace, ignore +export OTEL_DENO_CONSOLE="capture" +``` + +## Troubleshooting + +### No Data in Datadog + +1. Verify your API key is correct +2. Check that your endpoint URLs match your Datadog region +3. Ensure `OTEL_DENO` is set to `true` +4. Verify you're using the `--unstable-otel` flag + +### Missing Spans or Metrics + +1. Check your service name is correctly set +2. Ensure spans are properly ended with `span.end()` +3. For metrics, ensure you're using the correct types (counter, histogram, etc.) + +🦕 Using Deno with Datadog via OpenTelemetry provides powerful monitoring +capabilities for your applications. By following this tutorial, you can set up +comprehensive observability for your Deno services, track performance metrics, +and quickly identify and resolve issues. + +The OpenTelemetry integration in Deno is still under development. Check the +[OTEL docs](/runtime/fundamentals/open_telemetry/) for updates and changes to +the API. From 4d9c67e69c3258871eaecc6d92440e2e7cece7e4 Mon Sep 17 00:00:00 2001 From: Jo Franchetti Date: Thu, 20 Mar 2025 14:03:36 +0000 Subject: [PATCH 2/5] datadog tutorial --- examples/_data.ts | 5 +++++ examples/tutorials/{datadog.md => datadog_otel_tutorial.md} | 0 2 files changed, 5 insertions(+) rename examples/tutorials/{datadog.md => datadog_otel_tutorial.md} (100%) diff --git a/examples/_data.ts b/examples/_data.ts index b3669f778..6c7ed92f5 100644 --- a/examples/_data.ts +++ b/examples/_data.ts @@ -795,6 +795,11 @@ export const sidebar = [ href: "/examples/openai_chat_completion/", type: "example", }, + { + title: "OpenTelemetry Tracing with Datadog", + href: "/examples/datadog_otel_tutorial/", + type: "tutorial", + }, { title: "User Data Processing with Deno Collections", href: "/examples/data_processing/", diff --git a/examples/tutorials/datadog.md b/examples/tutorials/datadog_otel_tutorial.md similarity index 100% rename from examples/tutorials/datadog.md rename to examples/tutorials/datadog_otel_tutorial.md From a4a963f61dbded7025afb9b9ac38e52f998860fe Mon Sep 17 00:00:00 2001 From: Jo Franchetti Date: Thu, 20 Mar 2025 14:18:32 +0000 Subject: [PATCH 3/5] fix broken link --- examples/tutorials/{datadog_otel_tutorial.md => datadog_otel.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/tutorials/{datadog_otel_tutorial.md => datadog_otel.md} (100%) diff --git a/examples/tutorials/datadog_otel_tutorial.md b/examples/tutorials/datadog_otel.md similarity index 100% rename from examples/tutorials/datadog_otel_tutorial.md rename to examples/tutorials/datadog_otel.md From 59e98742b64dea13dfa46c5cc2f6be30a37d07ed Mon Sep 17 00:00:00 2001 From: Jo Franchetti Date: Thu, 20 Mar 2025 14:38:49 +0000 Subject: [PATCH 4/5] fix data --- examples/_data.ts | 10 +++++----- examples/tutorials/datadog_otel.md | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/_data.ts b/examples/_data.ts index 6c7ed92f5..011856464 100644 --- a/examples/_data.ts +++ b/examples/_data.ts @@ -795,11 +795,6 @@ export const sidebar = [ href: "/examples/openai_chat_completion/", type: "example", }, - { - title: "OpenTelemetry Tracing with Datadog", - href: "/examples/datadog_otel_tutorial/", - type: "tutorial", - }, { title: "User Data Processing with Deno Collections", href: "/examples/data_processing/", @@ -810,6 +805,11 @@ export const sidebar = [ href: "/examples/exponential_backoff/", type: "example", }, + { + title: "OpenTelemetry Tracing with Datadog", + href: "/examples/datadog_otel_tutoral/", + type: "tutorial", + }, ], }, { diff --git a/examples/tutorials/datadog_otel.md b/examples/tutorials/datadog_otel.md index 38bfa89d6..27086a992 100644 --- a/examples/tutorials/datadog_otel.md +++ b/examples/tutorials/datadog_otel.md @@ -1,6 +1,7 @@ --- title: Using Deno with Datadog description: "Learn how to monitor your Deno applications with Datadog using OpenTelemetry. This tutorial covers setup, configuration, and sending traces, metrics, and logs to Datadog." +url: /examples/datadog_otel_tutorial --- # Using Deno with Datadog From 2eb2a91d2d057846c030ddf702b94cf37262750c Mon Sep 17 00:00:00 2001 From: Jo Franchetti Date: Thu, 20 Mar 2025 15:14:02 +0000 Subject: [PATCH 5/5] typo --- examples/_data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/_data.ts b/examples/_data.ts index 011856464..2ec16eb6b 100644 --- a/examples/_data.ts +++ b/examples/_data.ts @@ -807,7 +807,7 @@ export const sidebar = [ }, { title: "OpenTelemetry Tracing with Datadog", - href: "/examples/datadog_otel_tutoral/", + href: "/examples/datadog_otel_tutorial/", type: "tutorial", }, ],