OpenTelemetry Tracing API for JavaScript

TIP

This document teaches how to use OpenTelemetry JavaScript API. To learn how to install and configure OpenTelemetry JS SDK, see Getting started with OpenTelemetry Node.JSopen in new window.

OpenTelemetry-JS

OpenTelemetry-JSopen in new window is the JavaScript implementation of OpenTelemetry. It provides OpenTelemetry Tracing API which you can use to instrument your application with traces.

npm:

npm install @opentelemetry/api --save

yarn:

yarn add @opentelemetry/api --save

Quickstart

Step 1. Let's instrument the following function:

async function redisGet(key) {
  return await client.get('key')
}

Step 2. Wrap the operation with a span:

const otel = require('@opentelemetry/api')

const tracer = otel.trace.getTracer('app_or_package_name', '1.0.0')

async function redisGet(key) {
  return await tracer.startActiveSpan('redisGet', async (span) => {
    const value = await client.get('key')
    span.end()
    return value
  })
}
 

 


 
 
 



Step 3. Record errors and set status code:

async function redisGet(key) {
  return await tracer.startActiveSpan('redisGet', async (span) => {
    let value
    try {
      value = await client.get('key')
    } catch (exc) {
      span.recordException(exc)
      span.setStatus({ code: otel.SpanStatusCode.ERROR, message: String(exc) })
    } finally {
      span.end()
    }
    return value
  })
}





 
 
 






Step 4. Record contextual information with attributes:

async function redisGet(key) {
  return await tracer.startActiveSpan('redisGet', async (span) => {
    if (span.isRecording()) {
      span.setAttribute('redis.key', key)
    }

    let value
    try {
      value = await client.get('key')
    } catch (exc) {
      span.recordException(exc)
      span.setStatus({ code: otel.SpanStatusCode.ERROR, message: String(exc) })
    } finally {
      span.end()
    }
    return value
  })
}


 
 
 













And that's it! The operation is fully instrumented.

Tracer

To start creating spans, you need a tracer. You can create a tracer by providing the name and version of the library/application doing the instrumentation:

const otel = require('@opentelemetry/api')

const tracer = otel.trace.getTracer('app_or_package_name', '1.0.0')

You can have as many tracers as you want, but usually you need one tracer for an app or a library. You can use tracer names to identify the library that produces the spans.

Creating spans

Once you have a tracer, creating spans is easy:

// Create a span with name "operation-name" and kind="server".
tracer.startActiveSpan('operation-name', { kind: otel.SpanKind.SERVER }, (span) => {
  doSomeWork()
  span.end()
})

Adding span attributes

To record contextual information, you can annotate spans with attributes. For example, an HTTP endpoint may have such attributes as http.method = GET and http.route = /projects/:id.

// To avoid expensive computations, check that span is recording
// before setting any attributes.
if (span.isRecording()) {
  span.setAttribute('http.method', 'GET')
  span.setAttribute('http.route', '/projects/:id')
}

You can name attributes as you want, but for common operations you should use semantic attributes convention.

Adding span events

You can annotate spans with events, for example, you can use events to record log messages:

span.addEvent('log', {
  'log.severity': 'error',
  'log.message': 'User not found',
  'enduser.id': '123',
})

Setting status code

You can set error status code to indicate that the operation contains an error:

} catch (err) {
  span.setStatus({ code: otel.SpanStatusCode.ERROR, message: String(err) })
}

Recording exceptions

OpenTelemetry provides a shortcut to record exceptions which is usually used together with setStatus:

} catch (exc) {
  # Record the exception and update the span status.
  span.recordException(exc)
  span.setStatus({ code: otel.SpanStatusCode.ERROR, message: String(exc) })
}

Context

OpenTelemetry stores the active span in a context and saves the context in a pluggable context storage. You can nest contexts inside each other and OpenTelemetry will automatically activate the parent span context when you end the span.

The following code creates a new context and saves the span in it:

otel.context.with(otel.trace.setSpan(otel.context.active(), span), () => {
    # span is active inside this method
})

To get the active span from the current context:

const span = otel.trace.getSpan(otel.context.active())

Spans storage

Uptrace is an open source DataDog competitoropen in new window with an intuitive query builder, rich dashboards, alerting rules, and integrations for most languages and frameworks. It can process billions of spans and metrics on a single server and allows to monitor your applications at 10x lower cost.

Uptrace uses ClickHouse database to store traces, metrics, and logs. You can use it to monitor applications and set up automatic alerts to receive notifications via email, Slack, Telegram, and more.

You can get startedopen in new window with Uptrace by downloading a DEB/RPM package or a pre-compiled Go binary.

What's next?

Last Updated: