Reputation: 9
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