Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
⌘K
Up or down tonavigateEnter toselectEscape toclose
On this page

Monitor your app with OpenTelemetry and Deno Deploy

Deno Deploy includes built-in OpenTelemetry support that automatically capturestraces for HTTP requests, database queries, and other operations. This tutorialshows how to add custom OpenTelemetry instrumentation to your applications formore detailed observability.

PrerequisitesJump to heading

  1. AGitHub account
  2. Deno installedon your local machine
  3. Access to theDeno Deploy account
  4. Basic familiarity withOpenTelemetry concepts

Create a basic API applicationJump to heading

First, let's create a simple API server that we'll instrument withOpenTelemetry:

main.ts
const dataStore: Record<string,string>={};asyncfunctionhandler(req: Request):Promise<Response>{const url=newURL(req.url);// Simulate random latencyawaitnewPromise((resolve)=>setTimeout(resolve, Math.random()*200));try{// Handle product listingif(url.pathname==="/products"&& req.method==="GET"){returnnewResponse(JSON.stringify(Object.values(dataStore)),{        headers:{"Content-Type":"application/json"},});}// Handle product creationif(url.pathname==="/products"&& req.method==="POST"){const data=await req.json();const id= crypto.randomUUID();      dataStore[id]= data;returnnewResponse(JSON.stringify({ id,...data}),{        status:201,        headers:{"Content-Type":"application/json"},});}// Handle product retrieval by IDif(url.pathname.startsWith("/products/")&& req.method==="GET"){const id= url.pathname.split("/")[2];const product= dataStore[id];if(!product){returnnewResponse("Product not found",{ status:404});}returnnewResponse(JSON.stringify(product),{        headers:{"Content-Type":"application/json"},});}// Handle root routeif(url.pathname==="/"){returnnewResponse("Product API - Try /products endpoint");}returnnewResponse("Not Found",{ status:404});}catch(error){console.error("Error handling request:", error);returnnewResponse("Internal Server Error",{ status:500});}}console.log("Server running on http://localhost:8000");Deno.serve(handler,{ port:8000});

Save this file and run it locally:

deno run --allow-net main.ts

Test the API with curl or a browser to ensure it works:

# List products (empty at first)curl http://localhost:8000/products# Add a productcurl-X POST http://localhost:8000/products\-H"Content-Type: application/json"\-d'{"name": "Test Product", "price": 19.99}'

Add OpenTelemetry instrumentationJump to heading

Now, let's add custom OpenTelemetry instrumentation to our application. Create anew file calledinstrumented-main.ts:

instrumented-main.ts
import{ trace}from"npm:@opentelemetry/api@1";// Get the OpenTelemetry tracerconst tracer= trace.getTracer("product-api");const dataStore: Record<string,string>={};// Simulate a database operation with custom spanasyncfunctionqueryDatabase(  operation:string,  data?:unknown,):Promise<unknown>{returnawait tracer.startActiveSpan(`database.${operation}`,async(span)=>{try{// Add attributes to the span for better context      span.setAttributes({"db.system":"memory-store","db.operation": operation,});// Simulate database latencyconst delay= Math.random()*100;awaitnewPromise((resolve)=>setTimeout(resolve, delay));// Add latency information to the span      span.setAttributes({"db.latency_ms": delay});if(operation==="list"){return Object.values(dataStore);}elseif(operation==="get"){return dataStore[dataasstring];}elseif(operation==="insert"){const id= crypto.randomUUID();        dataStore[id]= dataasstring;return{ id, data};}returnnull;}catch(error){// Record any errors to the span      span.recordException(error);      span.setStatus({ code: trace.SpanStatusCode.ERROR});throw error;}finally{// End the span when we're done      span.end();}});}asyncfunctionhandler(req: Request):Promise<Response>{// Create a parent span for the entire requestreturnawait tracer.startActiveSpan(`${req.method}${newURL(req.url).pathname}`,async(parentSpan)=>{const url=newURL(req.url);// Add request details as span attributes      parentSpan.setAttributes({"http.method": req.method,"http.url": req.url,"http.route": url.pathname,});try{// Handle product listingif(url.pathname==="/products"&& req.method==="GET"){const products=awaitqueryDatabase("list");returnnewResponse(JSON.stringify(products),{            headers:{"Content-Type":"application/json"},});}// Handle product creationif(url.pathname==="/products"&& req.method==="POST"){// Create a span for parsing request JSONconst data=await tracer.startActiveSpan("parse.request.body",async(span)=>{try{const result=await req.json();return result;}catch(error){                span.recordException(error);                span.setStatus({ code: trace.SpanStatusCode.ERROR});throw error;}finally{                span.end();}},);const result=awaitqueryDatabase("insert", data);returnnewResponse(JSON.stringify(result),{            status:201,            headers:{"Content-Type":"application/json"},});}// Handle product retrieval by IDif(url.pathname.startsWith("/products/")&& req.method==="GET"){const id= url.pathname.split("/")[2];          parentSpan.setAttributes({"product.id": id});const product=awaitqueryDatabase("get", id);if(!product){            parentSpan.setAttributes({"error":true,"error.type":"not_found",});returnnewResponse("Product not found",{ status:404});}returnnewResponse(JSON.stringify(product),{            headers:{"Content-Type":"application/json"},});}// Handle root routeif(url.pathname==="/"){returnnewResponse("Product API - Try /products endpoint");}        parentSpan.setAttributes({"error":true,"error.type":"not_found"});returnnewResponse("Not Found",{ status:404});}catch(error){console.error("Error handling request:", error);// Record the error in the span        parentSpan.recordException(error);        parentSpan.setAttributes({"error":true,"error.type": error.name,"error.message": error.message,});        parentSpan.setStatus({ code: trace.SpanStatusCode.ERROR});returnnewResponse("Internal Server Error",{ status:500});}finally{// End the parent span when we're done        parentSpan.end();}},);}console.log("Server running with OpenTelemetry instrumentation on http://localhost:8000",);Deno.serve(handler,{ port:8000});

Run the instrumented version locally:

deno run --allow-net instrumented-main.ts

Test the API again with curl to generate some traces.

Create a GitHub repositoryJump to heading

  1. Go toGitHub and create a new repository.

  2. Initialize your local directory as a Git repository:

git initgitadd.git commit-m"Add OpenTelemetry instrumented API"
  1. Add your GitHub repository as a remote and push your code:
git remoteadd origin https://github.com/your-username/otel-demo-app.gitgit branch-M maingit push-u origin main

Deploy to Deno DeployJump to heading

  1. Navigate toconsole.deno.com

  2. Select your organization or create a new one if needed

  3. Click "+ New App"

  4. Select the GitHub repository you created earlier

  5. Configure the build settings:

    • Framework preset: No preset
    • Runtime configuration: Dynamic
    • Entrypoint:instrumented-main.ts
  6. Click "Create App" to start the deployment process

Generate sample trafficJump to heading

To generate sample traces and metrics, let's send some traffic to your deployedapplication:

  1. Copy your deployment URL from the Deno Deploy dashboard

  2. Send several requests to different endpoints:

# Store your app URL in a variableAPP_URL=https://your-app-name.your-org-name.deno.net# Get the root routecurl$APP_URL/# List products (empty at first)curl$APP_URL/products# Add some productscurl-X POST$APP_URL/products-H"Content-Type: application/json"-d'{"name": "Laptop", "price": 999.99}'curl-X POST$APP_URL/products-H"Content-Type: application/json"-d'{"name": "Headphones", "price": 129.99}'curl-X POST$APP_URL/products-H"Content-Type: application/json"-d'{"name": "Mouse", "price": 59.99}'# List products againcurl$APP_URL/products# Try to access a non-existent product (will generate an error span)curl$APP_URL/products/nonexistent-id

Explore OpenTelemetry traces and metricsJump to heading

Now let's explore the observability data collected by Deno Deploy:

  1. From your application dashboard, click "Traces" in the sidebar

    • You'll see a list of traces for each request to your application
    • You can filter traces by HTTP method or status code using the search bar
  2. Select one of your/products POST traces to see detailed information:

    • The parent span for the entire request
    • Child spans for database operations
    • The span for parsing the request body

    Trace waterfall view

  3. Click on individual spans to see their details:

    • Duration and timing information
    • Attributes you set likedb.operation anddb.latency_ms
    • Any recorded exceptions
  4. Click "Logs" in the sidebar to see console output with trace context:

    • Notice how logs emitted during a traced operation are automatically linkedto the trace
    • Click "View trace" on a log line to see the associated trace
  5. Click "Metrics" to view application performance metrics:

    • HTTP request counts by endpoint
    • Error rates
    • Response time distributions

🦕 The automatic instrumentation in Deno Deploy combined with your custominstrumentation provides comprehensive visibility into your application'sperformance and behavior.

For more information about OpenTelemetry in Deno, check out these resources:

Did you find what you needed?

What can we do to improve this page?

If provided, you'll be @mentioned in the created GitHub issue

Privacy policy

[8]ページ先頭

©2009-2025 Movatter.jp