diff --git a/src/main/integrations/net-breadcrumbs.ts b/src/main/integrations/net-breadcrumbs.ts index 08ba85bc..898ea44f 100644 --- a/src/main/integrations/net-breadcrumbs.ts +++ b/src/main/integrations/net-breadcrumbs.ts @@ -1,7 +1,14 @@ /* eslint-disable deprecation/deprecation */ +import { getDynamicSamplingContextFromClient } from '@sentry/core'; import { getCurrentHub } from '@sentry/node'; -import { EventProcessor, Hub, Integration, Span, TracePropagationTargets } from '@sentry/types'; -import { fill, stringMatchesSomePattern } from '@sentry/utils'; +import { DynamicSamplingContext, EventProcessor, Hub, Integration, Span, TracePropagationTargets } from '@sentry/types'; +import { + dynamicSamplingContextToSentryBaggageHeader, + fill, + generateSentryTraceHeader, + logger, + stringMatchesSomePattern, +} from '@sentry/utils'; import { ClientRequest, ClientRequestConstructorOptions, IncomingMessage, net } from 'electron'; import { LRUMap } from 'lru_map'; import * as urlModule from 'url'; @@ -102,6 +109,21 @@ function parseOptions(optionsIn: ClientRequestConstructorOptions | string): { me }; } +function addHeadersToRequest( + request: Electron.ClientRequest, + url: string, + sentryTraceHeader: string, + dynamicSamplingContext?: Partial, +): void { + logger.log(`[Tracing] Adding sentry-trace header ${sentryTraceHeader} to outgoing request to "${url}": `); + request.setHeader('sentry-trace', sentryTraceHeader); + + const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext); + if (sentryBaggageHeader) { + request.setHeader('baggage', sentryBaggageHeader); + } +} + type RequestOptions = string | ClientRequestConstructorOptions; type RequestMethod = (opt: RequestOptions) => ClientRequest; type WrappedRequestMethodFactory = (original: RequestMethod) => RequestMethod; @@ -200,7 +222,21 @@ function createWrappedRequestFactory( }); if (shouldAttachTraceData(method, url)) { - request.setHeader('sentry-trace', span.toTraceparent()); + const sentryTraceHeader = span.toTraceparent(); + const dynamicSamplingContext = span?.transaction?.getDynamicSamplingContext(); + + addHeadersToRequest(request, url, sentryTraceHeader, dynamicSamplingContext); + } + } else { + if (shouldAttachTraceData(method, url)) { + const { traceId, sampled, dsc } = scope.getPropagationContext(); + const sentryTraceHeader = generateSentryTraceHeader(traceId, undefined, sampled); + + const client = hub.getClient(); + const dynamicSamplingContext = + dsc || (client ? getDynamicSamplingContextFromClient(traceId, client, scope) : undefined); + + addHeadersToRequest(request, url, sentryTraceHeader, dynamicSamplingContext); } } } diff --git a/test/unit/net.test.ts b/test/unit/net.test.ts index d921cb8f..d4d98544 100644 --- a/test/unit/net.test.ts +++ b/test/unit/net.test.ts @@ -1,7 +1,7 @@ import { expect, should, use } from 'chai'; import * as http from 'http'; import chaiAsPromised = require('chai-as-promised'); -import { setAsyncContextStrategy, Span } from '@sentry/core'; +import { getActiveTransaction, setAsyncContextStrategy, Span } from '@sentry/core'; import { createTransport, Hub, NodeClient } from '@sentry/node'; import { ClientOptions, Transaction, TransactionContext } from '@sentry/types'; import { resolvedSyncPromise } from '@sentry/utils'; @@ -53,10 +53,7 @@ function mockAsyncContextStrategy(getHub: () => Hub): void { setAsyncContextStrategy({ getCurrentHub, runWithAsyncContext }); } -function createTransactionOnScope( - customOptions: Partial = {}, - customContext?: Partial, -): [Transaction, Hub] { +function createHubOnScope(customOptions: Partial = {}): Hub { const hub = new Hub(); mockAsyncContextStrategy(() => hub); @@ -78,6 +75,15 @@ function createTransactionOnScope( }), ); + return hub; +} + +function createTransactionOnScope( + customOptions: Partial = {}, + customContext?: Partial, +): [Transaction, Hub] { + const hub = createHubOnScope(customOptions); + const transaction = hub.startTransaction({ name: 'dogpark', traceId: '12312012123120121231201212312012', @@ -217,4 +223,19 @@ describe.skip('net integration', () => { expect(headers['sentry-trace']).to.be.undefined; }); }); + + describe('tracing without performance', () => { + it('adds headers without transaction', async () => { + createHubOnScope({ + tracePropagationTargets: ['localhost'], + integrations: [new Net()], + }); + const headers = await makeRequest(); + const transaction = getActiveTransaction(); + + expect(transaction).to.be.undefined; + expect(headers['sentry-trace']).not.to.be.empty; + expect(headers['baggage']).not.to.be.empty; + }); + }); });