Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions packages/node/src/integrations/tracing/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ export const instrumentGraphql = generateInstrumentOnce<GraphqlOptions>(

if (options.useOperationNameForRootSpan && operationType) {
const rootSpan = getRootSpan(span);

// We guard to only do this on http.server spans

const rootSpanAttributes = spanToJSON(rootSpan).data;

const existingOperations = rootSpanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION] || [];
Expand Down
40 changes: 0 additions & 40 deletions packages/opentelemetry/test/helpers/createSpan.ts

This file was deleted.

28 changes: 21 additions & 7 deletions packages/opentelemetry/test/utils/getRequestSpanData.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
/* eslint-disable deprecation/deprecation */
import { trace } from '@opentelemetry/api';
import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
import { SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_URL } from '@opentelemetry/semantic-conventions';
import { describe, expect, it } from 'vitest';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { getRequestSpanData } from '../../src/utils/getRequestSpanData';
import { createSpan } from '../helpers/createSpan';
import { TestClient, getDefaultTestClientOptions } from '../helpers/TestClient';
import { setupOtel } from '../helpers/initOtel';
import { cleanupOtel } from '../helpers/mockSdkInit';

describe('getRequestSpanData', () => {
let provider: BasicTracerProvider | undefined;

beforeEach(() => {
const client = new TestClient(getDefaultTestClientOptions({ tracesSampleRate: 1 }));
provider = setupOtel(client);
});

afterEach(() => {
cleanupOtel(provider);
});

it('works with basic span', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
const data = getRequestSpanData(span);

expect(data).toEqual({});
});

it('works with http span', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setAttributes({
[SEMATTRS_HTTP_URL]: 'http://example.com?foo=bar#baz',
[SEMATTRS_HTTP_METHOD]: 'GET',
Expand All @@ -31,7 +45,7 @@ describe('getRequestSpanData', () => {
});

it('works without method', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setAttributes({
[SEMATTRS_HTTP_URL]: 'http://example.com',
});
Expand All @@ -45,7 +59,7 @@ describe('getRequestSpanData', () => {
});

it('works with incorrect URL', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setAttributes({
[SEMATTRS_HTTP_URL]: 'malformed-url-here',
[SEMATTRS_HTTP_METHOD]: 'GET',
Expand Down
79 changes: 63 additions & 16 deletions packages/opentelemetry/test/utils/groupSpansWithParents.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
import { describe, expect, it } from 'vitest';

import { trace } from '@opentelemetry/api';
import type { BasicTracerProvider, ReadableSpan } from '@opentelemetry/sdk-trace-base';
import type { Span } from '@sentry/core';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { withActiveSpan } from '../../src/trace';
import { groupSpansWithParents } from '../../src/utils/groupSpansWithParents';
import { createSpan } from '../helpers/createSpan';
import { TestClient, getDefaultTestClientOptions } from '../helpers/TestClient';
import { setupOtel } from '../helpers/initOtel';
import { cleanupOtel } from '../helpers/mockSdkInit';

describe('groupSpansWithParents', () => {
let provider: BasicTracerProvider | undefined;

beforeEach(() => {
const client = new TestClient(getDefaultTestClientOptions({ tracesSampleRate: 1 }));
provider = setupOtel(client);
});

afterEach(() => {
cleanupOtel(provider);
});

it('works with no spans', () => {
const actual = groupSpansWithParents([]);
expect(actual).toEqual([]);
});

it('works with a single root span & in-order spans', () => {
const rootSpan = createSpan('root', { spanId: 'rootId' });
const parentSpan1 = createSpan('parent1', { spanId: 'parent1Id', parentSpanId: 'rootId' });
const parentSpan2 = createSpan('parent2', { spanId: 'parent2Id', parentSpanId: 'rootId' });
const child1 = createSpan('child1', { spanId: 'child1', parentSpanId: 'parent1Id' });
const tracer = trace.getTracer('test');
const rootSpan = tracer.startSpan('root') as unknown as ReadableSpan;
const parentSpan1 = withActiveSpan(
rootSpan as unknown as Span,
() => tracer.startSpan('parent1') as unknown as ReadableSpan,
);
const parentSpan2 = withActiveSpan(
rootSpan as unknown as Span,
() => tracer.startSpan('parent2') as unknown as ReadableSpan,
);
const child1 = withActiveSpan(
parentSpan1 as unknown as Span,
() => tracer.startSpan('child1') as unknown as ReadableSpan,
);

const actual = groupSpansWithParents([rootSpan, parentSpan1, parentSpan2, child1]);
expect(actual).toHaveLength(4);
Expand Down Expand Up @@ -46,15 +72,26 @@ describe('groupSpansWithParents', () => {
});

it('works with a spans with missing root span', () => {
const parentSpan1 = createSpan('parent1', { spanId: 'parent1Id', parentSpanId: 'rootId' });
const parentSpan2 = createSpan('parent2', { spanId: 'parent2Id', parentSpanId: 'rootId' });
const child1 = createSpan('child1', { spanId: 'child1', parentSpanId: 'parent1Id' });
const tracer = trace.getTracer('test');
const rootSpan = tracer.startSpan('root') as unknown as ReadableSpan;
const parentSpan1 = withActiveSpan(
rootSpan as unknown as Span,
() => tracer.startSpan('parent1') as unknown as ReadableSpan,
);
const parentSpan2 = withActiveSpan(
rootSpan as unknown as Span,
() => tracer.startSpan('parent2') as unknown as ReadableSpan,
);
const child1 = withActiveSpan(
parentSpan1 as unknown as Span,
() => tracer.startSpan('child1') as unknown as ReadableSpan,
);

const actual = groupSpansWithParents([parentSpan1, parentSpan2, child1]);
expect(actual).toHaveLength(4);

// Ensure parent & span is correctly set
const rootRef = actual.find(ref => ref.id === 'rootId');
const rootRef = actual.find(ref => ref.id === rootSpan.spanContext().spanId);
const parent1Ref = actual.find(ref => ref.span === parentSpan1);
const parent2Ref = actual.find(ref => ref.span === parentSpan2);
const child1Ref = actual.find(ref => ref.span === child1);
Expand Down Expand Up @@ -82,11 +119,21 @@ describe('groupSpansWithParents', () => {
});

it('works with multiple root spans & out-of-order spans', () => {
const rootSpan1 = createSpan('root1', { spanId: 'root1Id' });
const rootSpan2 = createSpan('root2', { spanId: 'root2Id' });
const parentSpan1 = createSpan('parent1', { spanId: 'parent1Id', parentSpanId: 'root1Id' });
const parentSpan2 = createSpan('parent2', { spanId: 'parent2Id', parentSpanId: 'root2Id' });
const childSpan1 = createSpan('child1', { spanId: 'child1Id', parentSpanId: 'parent1Id' });
const tracer = trace.getTracer('test');
const rootSpan1 = tracer.startSpan('root1') as unknown as ReadableSpan;
const rootSpan2 = tracer.startSpan('root2') as unknown as ReadableSpan;
const parentSpan1 = withActiveSpan(
rootSpan1 as unknown as Span,
() => tracer.startSpan('parent1') as unknown as ReadableSpan,
);
const parentSpan2 = withActiveSpan(
rootSpan2 as unknown as Span,
() => tracer.startSpan('parent2') as unknown as ReadableSpan,
);
const childSpan1 = withActiveSpan(
parentSpan1 as unknown as Span,
() => tracer.startSpan('child1') as unknown as ReadableSpan,
);

const actual = groupSpansWithParents([childSpan1, parentSpan1, parentSpan2, rootSpan2, rootSpan1]);
expect(actual).toHaveLength(5);
Expand Down
61 changes: 36 additions & 25 deletions packages/opentelemetry/test/utils/mapStatus.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
/* eslint-disable deprecation/deprecation */
import { trace } from '@opentelemetry/api';
import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
import { SEMATTRS_HTTP_STATUS_CODE, SEMATTRS_RPC_GRPC_STATUS_CODE } from '@opentelemetry/semantic-conventions';
import { SPAN_STATUS_ERROR, SPAN_STATUS_OK } from '@sentry/core';
import type { SpanStatus } from '@sentry/core';
import { describe, expect, it } from 'vitest';

import { SPAN_STATUS_ERROR, SPAN_STATUS_OK } from '@sentry/core';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { mapStatus } from '../../src/utils/mapStatus';
import { createSpan } from '../helpers/createSpan';
import { TestClient, getDefaultTestClientOptions } from '../helpers/TestClient';
import { setupOtel } from '../helpers/initOtel';
import { cleanupOtel } from '../helpers/mockSdkInit';

describe('mapStatus', () => {
let provider: BasicTracerProvider | undefined;

beforeEach(() => {
const client = new TestClient(getDefaultTestClientOptions({ tracesSampleRate: 1 }));
provider = setupOtel(client);
});

afterEach(() => {
cleanupOtel(provider);
});

const statusTestTable: [undefined | number | string, undefined | string, SpanStatus][] = [
// http codes
[400, undefined, { code: SPAN_STATUS_ERROR, message: 'invalid_argument' }],
Expand All @@ -23,19 +37,6 @@ describe('mapStatus', () => {
[504, undefined, { code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' }],
[999, undefined, { code: SPAN_STATUS_ERROR, message: 'unknown_error' }],

['400', undefined, { code: SPAN_STATUS_ERROR, message: 'invalid_argument' }],
['401', undefined, { code: SPAN_STATUS_ERROR, message: 'unauthenticated' }],
['403', undefined, { code: SPAN_STATUS_ERROR, message: 'permission_denied' }],
['404', undefined, { code: SPAN_STATUS_ERROR, message: 'not_found' }],
['409', undefined, { code: SPAN_STATUS_ERROR, message: 'already_exists' }],
['429', undefined, { code: SPAN_STATUS_ERROR, message: 'resource_exhausted' }],
['499', undefined, { code: SPAN_STATUS_ERROR, message: 'cancelled' }],
['500', undefined, { code: SPAN_STATUS_ERROR, message: 'internal_error' }],
['501', undefined, { code: SPAN_STATUS_ERROR, message: 'unimplemented' }],
['503', undefined, { code: SPAN_STATUS_ERROR, message: 'unavailable' }],
['504', undefined, { code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' }],
['999', undefined, { code: SPAN_STATUS_ERROR, message: 'unknown_error' }],

// grpc codes
[undefined, '1', { code: SPAN_STATUS_ERROR, message: 'cancelled' }],
[undefined, '2', { code: SPAN_STATUS_ERROR, message: 'unknown_error' }],
Expand All @@ -56,11 +57,11 @@ describe('mapStatus', () => {
[undefined, '999', { code: SPAN_STATUS_ERROR, message: 'unknown_error' }],

// http takes precedence over grpc
['400', '2', { code: SPAN_STATUS_ERROR, message: 'invalid_argument' }],
[400, '2', { code: SPAN_STATUS_ERROR, message: 'invalid_argument' }],
];

it.each(statusTestTable)('works with httpCode=%s, grpcCode=%s', (httpCode, grpcCode, expected) => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setStatus({ code: 0 }); // UNSET

if (httpCode) {
Expand All @@ -75,39 +76,49 @@ describe('mapStatus', () => {
expect(actual).toEqual(expected);
});

it('works with string SEMATTRS_HTTP_STATUS_CODE xxx', () => {
const span = trace.getTracer('test').startSpan('test-span');

span.setStatus({ code: 0 }); // UNSET
span.setAttribute(SEMATTRS_HTTP_STATUS_CODE, '400');

const actual = mapStatus(span);
expect(actual).toEqual({ code: SPAN_STATUS_ERROR, message: 'invalid_argument' });
});

it('returns ok span status when is UNSET present on span', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setStatus({ code: 0 }); // UNSET
expect(mapStatus(span)).toEqual({ code: SPAN_STATUS_OK });
});

it('returns ok span status when already present on span', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setStatus({ code: 1 }); // OK
expect(mapStatus(span)).toEqual({ code: SPAN_STATUS_OK });
});

it('returns error status when span already has error status', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setStatus({ code: 2, message: 'invalid_argument' }); // ERROR
expect(mapStatus(span)).toEqual({ code: SPAN_STATUS_ERROR, message: 'invalid_argument' });
});

it('returns error status when span already has error status without message', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setStatus({ code: 2 }); // ERROR
expect(mapStatus(span)).toEqual({ code: SPAN_STATUS_ERROR, message: 'unknown_error' });
});

it('infers error status form attributes when span already has error status without message', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setAttribute(SEMATTRS_HTTP_STATUS_CODE, 500);
span.setStatus({ code: 2 }); // ERROR
expect(mapStatus(span)).toEqual({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
});

it('returns unknown error status when code is unknown', () => {
const span = createSpan();
const span = trace.getTracer('test').startSpan('test-span');
span.setStatus({ code: -1 as 0 });
expect(mapStatus(span)).toEqual({ code: SPAN_STATUS_ERROR, message: 'unknown_error' });
});
Expand Down
Loading
Loading