Menu
Grafana Cloud Faro Web SDK Integrate OpenTelemetry-JS tracing

Integrate OpenTelemetry-JS tracing

The Grafana Faro Web SDK powers the fully managed Frontend Application Observability service in Grafana Cloud, which is in private beta and not yet publicly available.

Tracing is a mechanism to record paths taken by requests as they propagate through multiple services, for example, from front end app to back-end service to database. Although Faro does not have its own tracing implementation, it can be integrated with OpenTelemetry-JS to capture tracing data, send it to Grafana Cloud and automatically add tracing context to captured logs, exceptions, events, and measurements.

There are two ways to integrate OpenTelemetry-JS tracing with Faro. If you do not have OpenTelemetry-JS set up in your application, you can use Faro web tracing instrumentation which sets it up for you. If you already have OpenTelemetry-JS, you can configure it to export traces via Faro Web SDK.

Before you begin

Because the OpenTelemetry-JS packages are large, they are not included in the core or web packages of Grafana Faro Web SDK. You must manually install the Faro tracing package.

Run one of the following commands, depending on your package manager. The command installs the tracing package in your project.

# Using npm
npm install @grafana/faro-web-tracing

# Using yarn
yarn add @grafana/faro-web-tracing

# Using pnpm
pnpm add @grafana/faro-web-tracing

Set up OpenTelemetry-JS tracing via Faro instrumentation

If your application does not have OpenTelemetry-JS, you can use TracingInstrumentation included with the Faro web tracing package.

The following commands add OpenTelemetry-JS tracing to the list of instrumentations executed when you initialize Faro. Th commands initialize OpenTelemetry tracing with document load, fetch, xhr, and user interaction auto instrumentations.

import { TracingInstrumentation } from "@grafana/faro-web-tracing";
import { getWebInstrumentations, initializeFaro } from "@grafana/faro-web-sdk";

initializeFaro({
  // Mandatory, the URL of the Grafana Cloud collector with embedded application key.
  // Copy from the configuration page of your application in Grafana.
  url: "http://faro-collector-us-central-0.grafana.net/collect/{app-key}",

  // Mandatory, the identification label(s) of your application
  app: {
    name: "my-app",
    version: "1.0.0", // Optional, but recommended
  },

  instrumentations: [
    // Mandatory, overwriting the instrumentations array would cause the default instrumentations to be omitted
    ...getWebInstrumentations(),

    // Mandatory, initialization of the tracing package
    new TracingInstrumentation(),
  ],
});

Integrate existing OpenTelemetry-JS instrumentation with Faro Web SDK

If you already have OpenTelemetry-JS set up in your application, you can integrate it with Faro Web SDK by adding FaroSessionSpanProcessor to add Faro session id to spans, FaroTraceExporter to export spans via Faro and registers OpenTelemetry API with the Faro Web SDK instance.

import { trace, context } from "@opentelemetry/api";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
import { initializeFaro } from "@grafana/faro-web-sdk";
import {
  FaroTraceExporter,
  FaroSessionSpanProcessor,
} from "@grafana/faro-web-tracing";
// ...
// initialize Faro Web SDK
const faro = initializeFaro({
  /* ... */
});
// setup OpenTelemetry provider
const provider = new WebTracerProvider({
  /* ... */
});
// ...
// set up span processors and Faro trace exporer
provider.addSpanProcessor(
  new FaroSessionSpanProcessor(
    new BatchSpanProcessor(new FaroTraceExporter({ faro }))
  )
);
// ...
// register OpenTelemetry API with Faro Web SDK instance
faro.api.initOTEL(trace, context);

You can find a complete example here.

Example of starting a trace

The following example shows you how to start a trace.

const { trace, context } = faro.api.getOTEL();

const tracer = trace.getTracer("default");
const span = tracer.startSpan("click");

context.with(trace.setSpan(context.active(), span), () => {
  doSomething();
  span.end();
});