Replies: 11 comments 35 replies
-
Reading through the source code, it looks like I do not need to call And it looks like I need to make sure I setup OpenTelemetry first because init() calls |
Beta Was this translation helpful? Give feedback.
-
I definitely have to use |
Beta Was this translation helpful? Give feedback.
-
to setup my tracerProvider with the SentrySampler I need the Sentry client before instantiating my TracerProvider. I don't get warnings with it setup this way because DEBUG_BUILD isn't set. |
Beta Was this translation helpful? Give feedback.
-
Here's the setup I landed on. If you see anything weird or wrong here would love to know. import { MetricExporter } from "@google-cloud/opentelemetry-cloud-monitoring-exporter";
import { TraceExporter } from "@google-cloud/opentelemetry-cloud-trace-exporter";
import opentelemetry, * as api from "@opentelemetry/api";
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { IORedisInstrumentation } from "@opentelemetry/instrumentation-ioredis";
import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
import { WinstonInstrumentation } from "@opentelemetry/instrumentation-winston";
import { Resource } from "@opentelemetry/resources";
import { MeterProvider, PeriodicExportingMetricReader, ConsoleMetricExporter } from "@opentelemetry/sdk-metrics";
import { BatchSpanProcessor, SimpleSpanProcessor, ConsoleSpanExporter } from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_NAMESPACE } from "@opentelemetry/semantic-conventions";
import type { NodeClient } from "@sentry/node";
import {
SentrySpanProcessor,
SentryPropagator,
wrapContextManagerClass,
setupEventContextTrace,
SentrySampler,
} from "@sentry/opentelemetry";
import { TypeormInstrumentation } from "opentelemetry-instrumentation-typeorm";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import * as Sentry from "@sentry/node";
import { nodeProfilingIntegration } from "@sentry/profiling-node";
import { environment, release, SentryDSN } from "@smartrr/shared/services/Sentry/constants";
import { IS_DEPLOYED, PRODUCTION, RUNTIME_ENV_NAME } from "./utils/constants";
Sentry.init({
dsn: SentryDSN.backend,
environment,
release,
integrations: [nodeProfilingIntegration()],
skipOpenTelemetrySetup: true,
});
const sentryClient = Sentry.getClient<NodeClient>();
const resource = new Resource({
[SEMRESATTRS_SERVICE_NAME]: "smartrr",
[SEMRESATTRS_SERVICE_NAMESPACE]: RUNTIME_ENV_NAME,
});
const metricReaders = [];
if (IS_DEPLOYED) {
metricReaders.push(
new PeriodicExportingMetricReader({
// Export metrics every 10 seconds.
// 5 seconds is the smallest sample period allowed by Cloud Monitoring.
exportIntervalMillis: 10_000,
exporter: new MetricExporter(),
})
);
}
if (process.env.OTEL_DEBUG || process.env.OTEL_DEBUG_JAEGER) {
metricReaders.push(
new PeriodicExportingMetricReader({
exporter: new ConsoleMetricExporter(),
})
);
}
const meterProvider = new MeterProvider({ resource, readers: metricReaders });
const tracerProvider = new NodeTracerProvider({
resource,
spanLimits: { eventCountLimit: 512 },
sampler: sentryClient && new SentrySampler(sentryClient),
});
const SentryContextManager = wrapContextManagerClass(AsyncLocalStorageContextManager);
tracerProvider.register({
propagator: new SentryPropagator(),
contextManager: new SentryContextManager(),
});
opentelemetry.metrics.setGlobalMeterProvider(meterProvider);
if (sentryClient) {
setupEventContextTrace(sentryClient);
sentryClient.traceProvider = tracerProvider;
}
registerInstrumentations({
tracerProvider,
meterProvider,
instrumentations: [
new HttpInstrumentation(),
new UndiciInstrumentation(),
new ExpressInstrumentation(),
new IORedisInstrumentation(),
new TypeormInstrumentation(),
new WinstonInstrumentation({
logHook(_, record) {
record["resource.service.name"] = tracerProvider.resource.attributes[SEMRESATTRS_SERVICE_NAME];
},
}),
],
});
tracerProvider.addSpanProcessor(new SentrySpanProcessor());
if (IS_DEPLOYED) {
tracerProvider.addSpanProcessor(
new BatchSpanProcessor(new TraceExporter(), {
scheduledDelayMillis: 1000,
maxExportBatchSize: 512,
maxQueueSize: 512 * 6,
})
);
}
if (process.env.OTEL_DEBUG) {
tracerProvider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
}
if (process.env.OTEL_DEBUG_JAEGER) {
tracerProvider.addSpanProcessor(new BatchSpanProcessor(new OTLPTraceExporter()));
}
if (RUNTIME_ENV_NAME !== PRODUCTION) {
opentelemetry.diag.setLogger(new api.DiagConsoleLogger(), api.DiagLogLevel.ERROR);
}
export const OtelTracer = tracerProvider.getTracer("basic");
export const OtelMeter = meterProvider.getMeter(RUNTIME_ENV_NAME); |
Beta Was this translation helpful? Give feedback.
-
Hey, sorry about the confusion there - you are right that there are some incorrect/missing things in the docs there! I will make sure to update them and ensure everything is actually exported etc. correctly! |
Beta Was this translation helpful? Give feedback.
-
I opened a PR with some small fixes based on your feedback: #12214
Thank you so much, we greatly appreciate the feedback and time to go through this! Hopefully with the changes in the PR this will become more straightforward 🙏 |
Beta Was this translation helpful? Give feedback.
-
Hey, we have released 8.5.0 with some updates where stuff should properly work now! |
Beta Was this translation helpful? Give feedback.
-
Hello. We discovered today that with the above configuration, none of our tracing is making it to our Google Cloud Tracing. I also found that it's not making it to my local Jaeger instance when I have OTEL_DEBUG_JAEGER=1 set. While debugging I found that if I remove the SentrySampler my traces make it to my non-sentry tracing destinations, but of course then the sentry stuff stops working. I ended up just removing Sentry from our backend entirely. Do you have any suggestions on how we can support non-sentry trace destinations while still having Sentry work properly? |
Beta Was this translation helpful? Give feedback.
-
My takeaways from this experience:
We have Sentry installed for error tracking. I don't want it to even be involved with our tracing setup at all. I feel I have been sucked into trying to get the two to play nice together and failed. Ultimately I had to remove Sentry from my backend to get our tracing recovered to its previous state, but this is not what I want - I want to keep using Sentry for backend error tracking. Disappointed. |
Beta Was this translation helpful? Give feedback.
-
FYI, we have shipped improved docs on how to use Sentry with a custom OTEL setup: https://docs.sentry.io/platforms/javascript/guides/node/opentelemetry/custom-setup/ Hopefully, these docs clarify some of the challenges that folks had so far. |
Beta Was this translation helpful? Give feedback.
-
In my opinion i do not agree that this is the appropriate but discussion, but this was the direction given to me. The problem: For example:
Reproduction
-- EDIT-- I apologize for the edit, but i forgot to mention some important context about how we use Sentry:
|
Beta Was this translation helpful? Give feedback.
-
I just upgraded my node SDK from v7 to v8. I already have an existing Otel setup and I'm working to get the SDK to play nice with it.
I have found a few miscellaneous pieces of documentation that I'm trying to piece together into a fully working configuration, but I just wanted to drop a note and highlight that it's challenging. The documentation at https://docs.sentry.io/platforms/javascript/guides/node/performance/instrumentation/opentelemetry/#using-a-custom-opentelemetry-setup refers to
SentryContextManager
that is not exported, so I found https://github.com/getsentry/sentry-javascript/blob/develop/packages/opentelemetry/README.md that points outwrapContextManagerClass
should be used instead. However there's some additional steps in that doc that are not in the docs site, such assetupEventContextTrace
that I don't know if I should use.Is there a canonical document or example I should follow?
Beta Was this translation helpful? Give feedback.
All reactions