Faran
Faran

Reputation: 9

Can't get active span in Express instrumentation

I am trying to instrument OTel in JavaScript. I am getting this error: TypeError: Cannot read properties of undefined (reading 'spanContext')

otel.js:

const { PrometheusExporter } = require("@opentelemetry/exporter-prometheus");
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http");
const { registerInstrumentations } = require("@opentelemetry/instrumentation");
const { ExpressInstrumentation } = require("@opentelemetry/instrumentation-express");
const { HttpInstrumentation } = require("@opentelemetry/instrumentation-http");
const { Resource } = require("@opentelemetry/resources");
const { MeterProvider } = require("@opentelemetry/sdk-metrics");
const {
  NodeTracerProvider,
  SimpleSpanProcessor,
  ConsoleSpanExporter,
} = require("@opentelemetry/sdk-trace-node");
const { ATTR_SERVICE_NAME } = require("@opentelemetry/semantic-conventions");

const init = function (serviceName, metricPort) {
  // Define metrics
  const metricExporter = new PrometheusExporter({ port: metricPort }, () => {
    console.log(
      `scrape: http://localhost:${metricPort}${PrometheusExporter.DEFAULT_OPTIONS.endpoint}`
    );
  });

  // Create meter provider
  const meterProvider = new MeterProvider({
    readers: [metricExporter],
  });

  // Get meter
  const meter = meterProvider.getMeter(serviceName);

  // Define traces
  // const traceExporter = new ConsoleSpanExporter();
  const traceExporter = new OTLPTraceExporter();

  const processor = new SimpleSpanProcessor(traceExporter);

  // Create trace provider
  const provider = new NodeTracerProvider({
    resource: new Resource({
      [ATTR_SERVICE_NAME]: serviceName,
    }),
    spanProcessors: [processor],
  });

  provider.register();

  // Register instrumentations
  registerInstrumentations({
    instrumentations: [new ExpressInstrumentation(), new HttpInstrumentation()],
  });

  // Get tracer
  const tracer = provider.getTracer(serviceName);

  // Return meter & tracer
  return { meter, tracer };
};

module.exports = init;

items-service.js:

const axios = require("axios");
const express = require("express");
const bodyParser = require("body-parser");
const init = require("./otel.js");
const api = require("@opentelemetry/api");

init("items-service", 8081);
const app = express();

// Define prometheus counter
const httpCounter = meter.createCounter("http_calls");
app.use((req, res, next) => {
  httpCounter.add(1);
  next();
});

app.get("/data", async (req, res) => {
  try {
    if (req.query["fail"]) {
      throw new Error("A really bad error :/");
    }
    const apiResponse = await axios.get("http://localhost:8090/user");
    res.json(apiResponse.data);
  } catch (error) {
    // Get active span
    const activeSpan = api.trace.getSpan(api.context.active());

    if (activeSpan) {
      const traceId = activeSpan.spanContext().traceId;
      // Combine log  with trace
      console.error(`Critical Error, traceId: ${traceId}`);
      activeSpan.recordException(error);
    } else {
      console.warn("No active span found");
    }

    res.sendStatus(500);
  }
});

const server = app.listen(8080, () => {
  console.log("Items service is listening at port 8080");
});

I tried creating a separate span inside the request:

const { tracer } = init("items-service", 8081);
...

// Create a span
    const span = tracer.startSpan("items-service");
    span.addEvent("An error has occurred");
    span.end();
    console.error(`Critical Error, traceId: ${span.spanContext().traceId}`);

However, the express instrumentation should automatically do this. Is the initialization correct in the items-service.js? Also, I am exporting the data to Jaeger using OLTP. I have to create a span in order to see the traces on Jaeger but nothing shows up when I initialize using init("items-service", 8081);

docker-compose.yml:

services:
  jaeger:
    image: jaegertracing/all-in-one
    ports:
      - 16686:16686
      - 4317:4317
      - 4318:4318
  prometheus:
    image: prom/prometheus
    volumes:
      - ./config/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - 9090:9090

Upvotes: 0

Views: 35

Answers (0)

Related Questions