Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

Work in this release was contributed by @psh4607, @thijsw, @trinitiwowka, @nehaprasad-dev, @JealousGx, @Jxxunnn, @eddie333016, @davidmurdoch, @yashschandra, @atharv-sys32, @AG0708, @birkskyum, @mkly, @mcbbugu, @suhailopensource, @zkasuran, @mohd-akram, @RealBhupesh, @halillusion, @psang39, and @hafzism. Thank you for your contributions!

- feat(core): Accept a `CollectBehavior` shorthand for `dataCollection.httpHeaders`. Passing `true`, `false`, `{ allow: [...] }` or `{ deny: [...] }` now applies to both request and response headers; `{ request, response }` still controls each direction independently.
- feat(langchain)!: Emit `gen_ai.pipeline.name` instead of `langchain.chain.name` on LangChain chain spans. The attribute is omitted when the chain is unnamed.
- feat(deno)!: Rename several default integrations to match the other SDKs ([#22404](https://github.com/getsentry/sentry-javascript/pull/22404)). The `deno*Integration` exports are kept as deprecated aliases. If you were relying on the names (for example, to disable them), then note that these have changed:
- `DenoAmqplib` => `Amqplib`
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ export type {
CollectBehavior,
DataCollection,
HttpBodyCollectionTarget,
HttpHeadersCollection,
ResolvedDataCollection,
} from './types/datacollection';
export type { ClientOptions, CoreOptions as Options } from './types/options';
Expand Down
19 changes: 13 additions & 6 deletions packages/core/src/types/datacollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ export type CollectBehavior = boolean | { allow: string[] } | { deny: string[] }

export type HttpBodyCollectionTarget = 'incomingRequest' | 'outgoingRequest' | 'incomingResponse' | 'outgoingResponse';

/**
* Controls HTTP header collection per direction.
*/
export interface HttpHeadersCollection {
request?: CollectBehavior;
response?: CollectBehavior;
}

/**
* Controls what data the SDK collects and sends to Sentry.
*
Expand All @@ -30,12 +38,11 @@ export interface DataCollection {

/**
* Controls HTTP header collection for requests and responses.
*
* Accepts a `CollectBehavior` applied to both directions, or `{ request, response }` to control each independently.
* @default { request: true, response: true }
*/
httpHeaders?: {
request?: CollectBehavior;
response?: CollectBehavior;
};
httpHeaders?: CollectBehavior | HttpHeadersCollection;

/**
* Which HTTP body types to collect. An omitted value collects all body types valid for the
Expand Down Expand Up @@ -118,8 +125,8 @@ export interface DataCollection {
/**
* Fully resolved `DataCollection` with all defaults applied.
*/
export type ResolvedDataCollection = Required<DataCollection> & {
httpHeaders: Required<NonNullable<DataCollection['httpHeaders']>>;
export type ResolvedDataCollection = Required<Omit<DataCollection, 'httpHeaders'>> & {
httpHeaders: Required<HttpHeadersCollection>;
graphQL: Required<NonNullable<DataCollection['graphQL']>>;
genAI: Required<NonNullable<DataCollection['genAI']>>;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { DataCollection, ResolvedDataCollection } from '../../types/datacollection';
import type {
CollectBehavior,
DataCollection,
HttpHeadersCollection,
ResolvedDataCollection,
} from '../../types/datacollection';

const DEFAULTS: ResolvedDataCollection = {
userInfo: true,
Expand All @@ -14,6 +19,25 @@ const DEFAULTS: ResolvedDataCollection = {
frameContextLines: 5,
};

function isCollectBehavior(value: CollectBehavior | HttpHeadersCollection): value is CollectBehavior {
return typeof value === 'boolean' || 'allow' in value || 'deny' in value;
}

function resolveHttpHeaders(httpHeaders: DataCollection['httpHeaders']): ResolvedDataCollection['httpHeaders'] {
if (httpHeaders === undefined) {
return { ...DEFAULTS.httpHeaders };
}

if (isCollectBehavior(httpHeaders)) {
return { request: httpHeaders, response: httpHeaders };
}

return {
request: httpHeaders.request ?? DEFAULTS.httpHeaders.request,
response: httpHeaders.response ?? DEFAULTS.httpHeaders.response,
};
}

/**
* Resolves the effective `DataCollection` configuration from client options.
*
Expand All @@ -27,10 +51,7 @@ export function resolveDataCollectionOptions(options: { dataCollection?: DataCol
return {
userInfo: dc.userInfo ?? DEFAULTS.userInfo,
cookies: dc.cookies ?? DEFAULTS.cookies,
httpHeaders: {
request: dc.httpHeaders?.request ?? DEFAULTS.httpHeaders.request,
response: dc.httpHeaders?.response ?? DEFAULTS.httpHeaders.response,
},
httpHeaders: resolveHttpHeaders(dc.httpHeaders),
httpBodies: dc.httpBodies ?? DEFAULTS.httpBodies,
urlQueryParams: dc.urlQueryParams ?? DEFAULTS.urlQueryParams,
graphQL: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,59 @@ describe('resolveDataCollectionOptions', () => {
expect(result.httpHeaders.response).toBe(true);
});

it('merges nested httpHeaders partially for the response direction', () => {
const result = resolveDataCollectionOptions({
dataCollection: {
httpHeaders: { response: { allow: ['content-type'] } },
},
});

expect(result.httpHeaders).toEqual({ request: true, response: { allow: ['content-type'] } });
});

it('resolves independent request and response header settings', () => {
const result = resolveDataCollectionOptions({
dataCollection: {
httpHeaders: { request: { allow: ['x-request-id'] }, response: false },
},
});

expect(result.httpHeaders).toEqual({ request: { allow: ['x-request-id'] }, response: false });
});

it('treats an empty httpHeaders object as directional config with defaults', () => {
expect(resolveDataCollectionOptions({ dataCollection: { httpHeaders: {} } }).httpHeaders).toEqual({
request: true,
response: true,
});
});

it('applies boolean httpHeaders shorthand to both directions', () => {
expect(resolveDataCollectionOptions({ dataCollection: { httpHeaders: false } }).httpHeaders).toEqual({
request: false,
response: false,
});

expect(resolveDataCollectionOptions({ dataCollection: { httpHeaders: true } }).httpHeaders).toEqual({
request: true,
response: true,
});
});

it('applies allow/deny httpHeaders shorthand to both directions', () => {
const deny = { deny: ['forwarded', '-ip'] };
expect(resolveDataCollectionOptions({ dataCollection: { httpHeaders: deny } }).httpHeaders).toEqual({
request: deny,
response: deny,
});

const allow = { allow: ['content-type'] };
expect(resolveDataCollectionOptions({ dataCollection: { httpHeaders: allow } }).httpHeaders).toEqual({
request: allow,
response: allow,
});
});

it('merges nested genAI partially', () => {
const result = resolveDataCollectionOptions({
dataCollection: {
Expand Down
Loading