I am instrumenting a node.js service in Google Cloud Platform's Cloud Run.
I'm running into a problem where custom spans are not showing up in Trace.
I know that tracing is working because HTTP/TCP spans (which you get for free in GCP) are showing up nested properly--they wouldn't be nested automatically without configuration, which suggests to me the configuration below is working:
tracing.ts
:
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import {
SimpleSpanProcessor,
} from "@opentelemetry/sdk-trace-base";
import { TraceExporter } from "@google-cloud/opentelemetry-cloud-trace-exporter";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import * as opentelemetry from "@opentelemetry/api";
import { AsyncHooksContextManager } from "@opentelemetry/context-async-hooks";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { Resource } from "@opentelemetry/resources"
export const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "my-service-name",
})
});
// this *should* work automatically in GCP??
provider.addSpanProcessor(new SimpleSpanProcessor(new TraceExporter({
resourceFilter: /^service\./
})));
provider.register();
opentelemetry.trace.setGlobalTracerProvider(provider);
const contextManager = new AsyncHooksContextManager();
contextManager.enable();
opentelemetry.context.setGlobalContextManager(contextManager);
export const tracer = opentelemetry.trace.getTracer("basic");
// this works (spans are correctly associated with parents)
registerInstrumentations({
instrumentations: [
getNodeAutoInstrumentations({
"@opentelemetry/instrumentation-http": {},
"@opentelemetry/instrumentation-express": {},
}),
],
});
The spans that are not showing up are those that are emitted in code like the following redacted production code:
import { tracer } from "../tracing";
// ...
export const doWork = async (
req: Request,
res: Response
) => {
// ... but this does *NOT* work: these spans appear nowhere
// start span
const span = tracer.startSpan("doWork");
const ctx = opentelemetry.trace.setSpan(opentelemetry.context.active(), span);
opentelemetry.propagation.extract(ctx, req.headers);
try {
// ... do work here with ctx to emit child spans
res.status(200).send("ok");
} catch (e) {
res.status(500).send("error");
}
span.end();
};
It is unclear to me why these spans are not showing up anywhere.
The service account that deploys the Cloud Run instance has the roles/cloudtrace.agent
role:
- members:
- serviceAccount:<my service account name>@<project id>.iam.gserviceaccount.com
role: roles/cloudtrace.agent
I am unsure if there are additional permissions that need to be added (or what entity they may need to be added to).
So far I have tried
OTLPTraceExporter
to export spans in GCP (still nothing shows up)trace-agent
instead (not compatible with webpack)OTLPTraceExporter
with a Open-Telemetry collector (everything works exactly as expected -- traces all showing up)I'm really at a loss.
As checked in GCP documentation, only Google Compute Engine and GKE are supported by this service.
However, you can refer to Cloud Run Support in Github, if you are running OpenTelemetry on Cloud Run and a Stackoverflow discussion.