Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sentry.getCurrentHub().getScope().getTransaction() does not find transaction when using otel #7985

Closed
3 tasks done
md384 opened this issue Apr 27, 2023 · 5 comments
Closed
3 tasks done

Comments

@md384
Copy link
Contributor

md384 commented Apr 27, 2023

Is there an existing issue for this?

How do you use Sentry?

Self-hosted/on-premise

Which SDK are you using?

@sentry/opentelemetry-node

SDK Version

7.49.0

Framework Version

No response

Link to Sentry event

No response

SDK Setup

Sentry.init({
  dsn: SENTRY_DSN,
  integrations: [
    new Sentry.Integrations.Http({ tracing: false }),
    new CaptureConsole({
      levels: ['error', 'critical'],
    }),
  ],
  tracesSampleRate: SENTRY_TRACE_SAMPLING,
  release: GIT_SHA,
  environment: stack,
  instrumenter: 'otel',
})

propagation.setGlobalPropagator(new SentryPropagator())

const tracer = (serviceName: string) => {
  const provider = new NodeTracerProvider({
    resource: new Resource({
      [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
    }),
    sampler: new TraceIdRatioBasedSampler(SENTRY_TRACE_SAMPLING),
  })
  registerInstrumentations({
    tracerProvider: provider,
    instrumentations: getNodeAutoInstrumentations({
      '@opentelemetry/instrumentation-fs': {
        // this instrumentation causes excessive memory usage and we don't really need it
        // https://github.com/open-telemetry/opentelemetry-js-contrib/issues/1344
        enabled: false,
      },
      '@opentelemetry/instrumentation-ioredis': {
        requireParentSpan: true,
      },
      '@opentelemetry/instrumentation-http': {
        applyCustomAttributesOnSpan: (span) => {
          span.setAttribute('z_service_tag', serviceName)
          span.setAttribute('stack_name', STACK_NAME)
        },
      },
    }),
  })

  provider.addSpanProcessor(new SentrySpanProcessor())

  // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings
  provider.register()
}

Steps to Reproduce

import * as SentryCore from '@sentry/core'
import * as Sentry from '@sentry/node'
// @ts-expect-error
import { SENTRY_SPAN_PROCESSOR_MAP } from '@sentry/opentelemetry-node/cjs/spanprocessor'

const fromMapTransaction = Array.from(SENTRY_SPAN_PROCESSOR_MAP.values()).filter(
    (v) => v instanceof SentryCore.Transaction
  )[0]
const fromScopeTransaction = Sentry.getCurrentHub().getScope().getTransaction()

console.log("fromMapTransaction: ", fromMapTransaction)
console.log("fromScopeTransaction: ", fromScopeTransaction)

I am trying to connect server and browser services with https://docs.sentry.io/platforms/javascript/performance/connect-services/#pageload so need to get the current transaction.

Expected Result

// fromMapTransaction:  <ref *1> Transaction
// fromScopeTransaction:  <ref *1> Transaction

Expect the same transaction

Actual Result

// fromMapTransaction:  <ref *1> Transaction
// fromScopeTransaction:  undefined
@AbhiPrasad
Copy link
Member

Hey @md384 this is intentional! When you set instrumenter: 'otel' to be the configuration in your Sentry.init, we expect you to use the otel APIs to create/read span, and not rely on startTransaction or getTransaction.

Instead we recommend you grab the active span off via the otel APIs, and use that to add a sentry-trace header.

const activeSpan = opentelemetry.trace.getActiveSpan();

const { traceId, spanId } = activeSpan.spanContext();

const sentryTrace = `${traceId}-${spanId}-1`;

then when you inject

<html>
  <head>
    <meta name="sentry-trace" content="{{ sentryTrace }}" />
  </head>
</html>

You shouldn't need a baggage header here!

@md384
Copy link
Contributor Author

md384 commented May 1, 2023

@AbhiPrasad can we get a helper function in the @sentry/opentelemetry-node for this? Seems like generating the sentry-trace value is something that should be handled by sentry code (mostly in-case that definition changes).

@gajus
Copy link
Contributor

gajus commented Jan 22, 2024

For what it is worth, our internal helper:

import { context, trace } from '@opentelemetry/api';

export const findSentryTrace = () => {
  const activeContext = context.active();

  const activeSpan = trace.getSpan(activeContext);

  if (!activeSpan) {
    return null;
  }

  const { spanId, traceId } = activeSpan.spanContext();

  const sentryTrace = `${traceId}-${spanId}-1`;

  // Note that we do not need the `baggage` header.
  // @see https://github.com/getsentry/sentry-javascript/issues/7985#issuecomment-1529060940

  return {
    sentryTrace,
  };
};

@gajus
Copy link
Contributor

gajus commented Jan 26, 2024

Hey @md384 this is intentional! When you set instrumenter: 'otel' to be the configuration in your Sentry.init, we expect you to use the otel APIs to create/read span, and not rely on startTransaction or getTransaction.

Instead we recommend you grab the active span off via the otel APIs, and use that to add a sentry-trace header.

const activeSpan = opentelemetry.trace.getActiveSpan();

const { traceId, spanId } = activeSpan.spanContext();

const sentryTrace = `${traceId}-${spanId}-1`;

then when you inject

<html>
  <head>
    <meta name="sentry-trace" content="{{ sentryTrace }}" />
  </head>
</html>

You shouldn't need a baggage header here!

Heads up that the -1 at the end signals that the request should be sampled.

From conversation with Sentry support:

At the end of the header there can be a -0 or a -1 indicating "don't sample" and "sample".

You need to adjust this value accordingly as otherwise every request will get sampled.

@gajus
Copy link
Contributor

gajus commented Jan 31, 2024

Related thread #7538

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants