Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
60ecb6e
feat(node): Allow selective tracking of `pino` loggers
timfish Oct 14, 2025
abdce67
fix(node): `pino` child loggers
timfish Oct 14, 2025
ad39cb4
Fix logic
timfish Oct 15, 2025
f23891a
Merge branch 'develop' into timfish/fix/pino-child-loggers
timfish Oct 15, 2025
e00cf68
Merge branch 'develop' into timfish/fix/pino-child-loggers
timfish Oct 15, 2025
536df18
Merge remote-tracking branch 'upstream/master' into timfish/fix/pino-…
timfish Oct 15, 2025
32cab77
Merge branch 'timfish/fix/pino-child-loggers' of github.com:getsentry…
timfish Oct 15, 2025
4308b37
docs: Update supported Angular version in README
guillaume-moreau Oct 14, 2025
908e4ec
fix(browser): Ignore React 19.2+ component render measure entries (#1…
Lms24 Oct 15, 2025
318ce67
feat(solid): Add support for TanStack Router Solid (#17735)
thedanchez Oct 15, 2025
715f12f
chore(ci): Update Next.js canary testing (#17939)
chargome Oct 15, 2025
1c4c62b
chore: Bump size limit (#17941)
chargome Oct 15, 2025
eb5a5a8
chore: Add external contributor to CHANGELOG.md (#17940)
HazAT Oct 15, 2025
e53277e
fix(react): Add `POP` guard for long-running `pageload` spans (#17867)
onurtemizkan Oct 15, 2025
d03fc61
fix(tracemetrics): Send boolean for internal replay attribute (#17908)
chargome Oct 15, 2025
6abafe3
meta(changelog): Update changelog for 10.20.0
chargome Oct 15, 2025
1b8de2e
Merge branch 'timfish/fix/pino-child-loggers' of github.com:getsentry…
timfish Oct 15, 2025
8eb3787
Child tests
timfish Oct 15, 2025
fe0a46e
Merge branch 'develop' into timfish/fix/pino-child-loggers
timfish Oct 16, 2025
1bc5b4f
No breaking changes!
timfish Oct 16, 2025
b25e47d
remove duplicate test
timfish Oct 16, 2025
fd0242a
Merge branch 'develop' into timfish/fix/pino-child-loggers
timfish Oct 22, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,18 @@ Sentry.withIsolationScope(() => {
setTimeout(() => {
Sentry.withIsolationScope(() => {
Sentry.startSpan({ name: 'later' }, () => {
logger.error(new Error('oh no'));
// This child should be captured as we marked the parent logger to be tracked
const child = logger.child({ module: 'authentication' });
child.error(new Error('oh no'));

// This child should be ignored
const child2 = logger.child({ module: 'authentication.v2' });
Sentry.pinoIntegration.untrackLogger(child2);
child2.error(new Error('oh no v2'));

// This should also be ignored as the parent is ignored
const child3 = child2.child({ module: 'authentication.v3' });
child3.error(new Error('oh no v3'));
});
});
}, 1000);
3 changes: 2 additions & 1 deletion dev-packages/node-integration-tests/suites/pino/scenario.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Sentry.withIsolationScope(() => {
setTimeout(() => {
Sentry.withIsolationScope(() => {
Sentry.startSpan({ name: 'later' }, () => {
logger.error(new Error('oh no'));
const child = logger.child({ module: 'authentication' });
child.error(new Error('oh no'));
});
});
}, 1000);
44 changes: 22 additions & 22 deletions dev-packages/node-integration-tests/suites/pino/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ conditionalTest({ min: 20 })('Pino integration', () => {
function: '?',
in_app: true,
module: 'scenario',
context_line: " logger.error(new Error('oh no'));",
}),
]),
},
Expand All @@ -63,8 +62,8 @@ conditionalTest({ min: 20 })('Pino integration', () => {
body: 'hello world',
trace_id: expect.any(String),
severity_number: 9,
attributes: expect.objectContaining({
'pino.logger.name': { value: 'myapp', type: 'string' },
attributes: {
name: { value: 'myapp', type: 'string' },
'pino.logger.level': { value: 30, type: 'integer' },
user: { value: 'user-id', type: 'string' },
something: {
Expand All @@ -74,22 +73,22 @@ conditionalTest({ min: 20 })('Pino integration', () => {
'sentry.origin': { value: 'auto.logging.pino', type: 'string' },
'sentry.release': { value: '1.0', type: 'string' },
'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' },
}),
},
},
{
timestamp: expect.any(Number),
level: 'error',
body: 'oh no',
trace_id: expect.any(String),
severity_number: 17,
attributes: expect.objectContaining({
'pino.logger.name': { value: 'myapp', type: 'string' },
attributes: {
name: { value: 'myapp', type: 'string' },
module: { value: 'authentication', type: 'string' },
'pino.logger.level': { value: 50, type: 'integer' },
err: { value: '{}', type: 'string' },
'sentry.origin': { value: 'auto.logging.pino', type: 'string' },
'sentry.release': { value: '1.0', type: 'string' },
'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' },
}),
},
},
],
},
Expand Down Expand Up @@ -139,8 +138,8 @@ conditionalTest({ min: 20 })('Pino integration', () => {
body: 'hello world',
trace_id: expect.any(String),
severity_number: 9,
attributes: expect.objectContaining({
'pino.logger.name': { value: 'myapp', type: 'string' },
attributes: {
name: { value: 'myapp', type: 'string' },
'pino.logger.level': { value: 30, type: 'integer' },
user: { value: 'user-id', type: 'string' },
something: {
Expand All @@ -150,22 +149,21 @@ conditionalTest({ min: 20 })('Pino integration', () => {
'sentry.origin': { value: 'auto.logging.pino', type: 'string' },
'sentry.release': { value: '1.0', type: 'string' },
'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' },
}),
},
},
{
timestamp: expect.any(Number),
level: 'error',
body: 'oh no',
trace_id: expect.any(String),
severity_number: 17,
attributes: expect.objectContaining({
'pino.logger.name': { value: 'myapp', type: 'string' },
attributes: {
name: { value: 'myapp', type: 'string' },
'pino.logger.level': { value: 50, type: 'integer' },
err: { value: '{}', type: 'string' },
'sentry.origin': { value: 'auto.logging.pino', type: 'string' },
'sentry.release': { value: '1.0', type: 'string' },
'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' },
}),
},
},
],
},
Expand All @@ -189,33 +187,35 @@ conditionalTest({ min: 20 })('Pino integration', () => {
body: 'hello world',
trace_id: expect.any(String),
severity_number: 9,
attributes: expect.objectContaining({
'pino.logger.name': { value: 'myapp', type: 'string' },
attributes: {
name: { value: 'myapp', type: 'string' },
'pino.logger.level': { value: 30, type: 'integer' },
user: { value: 'user-id', type: 'string' },
something: {
type: 'string',
value: '{"more":3,"complex":"nope"}',
},
msg: { value: 'hello world', type: 'string' },
'sentry.origin': { value: 'auto.logging.pino', type: 'string' },
'sentry.release': { value: '1.0', type: 'string' },
'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' },
}),
},
},
{
timestamp: expect.any(Number),
level: 'error',
body: 'oh no',
trace_id: expect.any(String),
severity_number: 17,
attributes: expect.objectContaining({
'pino.logger.name': { value: 'myapp', type: 'string' },
attributes: {
name: { value: 'myapp', type: 'string' },
module: { value: 'authentication', type: 'string' },
msg: { value: 'oh no', type: 'string' },
'pino.logger.level': { value: 50, type: 'integer' },
err: { value: '{}', type: 'string' },
'sentry.origin': { value: 'auto.logging.pino', type: 'string' },
'sentry.release': { value: '1.0', type: 'string' },
'sentry.sdk.name': { value: 'sentry.javascript.node', type: 'string' },
}),
},
},
],
},
Expand Down
38 changes: 24 additions & 14 deletions packages/node-core/src/integrations/pino.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,23 @@ type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? Partial<T[P]> : T[P];
};

type PinoResult = {
level?: string;
time?: string;
pid?: number;
hostname?: string;
err?: Error;
} & Record<string, unknown>;

function stripIgnoredFields(result: PinoResult): PinoResult {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { level, time, pid, hostname, err, ...rest } = result;
return rest;
}

const _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions> = {}) => {
const options: PinoOptions = {
autoInstrument: userOptions.autoInstrument === false ? userOptions.autoInstrument : DEFAULT_OPTIONS.autoInstrument,
autoInstrument: userOptions.autoInstrument !== false,
error: { ...DEFAULT_OPTIONS.error, ...userOptions.error },
log: { ...DEFAULT_OPTIONS.log, ...userOptions.log },
};
Expand Down Expand Up @@ -112,27 +126,23 @@ const _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions
const injectedChannel = tracingChannel('orchestrion:pino:pino-log');
const integratedChannel = tracingChannel('pino_asJson');

function onPinoStart(self: Pino, args: PinoHookArgs, result: string): void {
function onPinoStart(self: Pino, args: PinoHookArgs, result: PinoResult): void {
if (!shouldTrackLogger(self)) {
return;
}

const [obj, message, levelNumber] = args;
const resultObj = stripIgnoredFields(result);

const [captureObj, message, levelNumber] = args;
const level = self?.levels?.labels?.[levelNumber] || 'info';

if (enableLogs && options.log.levels.includes(level)) {
const attributes: Record<string, unknown> = {
...obj,
...resultObj,
'sentry.origin': 'auto.logging.pino',
'pino.logger.level': levelNumber,
};

const parsedResult = JSON.parse(result) as { name?: string };

if (parsedResult.name) {
attributes['pino.logger.name'] = parsedResult.name;
}

_INTERNAL_captureLog({ level, message, attributes });
}

Expand All @@ -153,8 +163,8 @@ const _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions
return event;
});

if (obj.err) {
captureException(obj.err, captureContext);
if (captureObj.err) {
captureException(captureObj.err, captureContext);
return;
}

Expand All @@ -165,7 +175,7 @@ const _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions

injectedChannel.end.subscribe(data => {
const { self, arguments: args, result } = data as { self: Pino; arguments: PinoHookArgs; result: string };
onPinoStart(self, args, result);
onPinoStart(self, args, JSON.parse(result));
});

integratedChannel.end.subscribe(data => {
Expand All @@ -174,7 +184,7 @@ const _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions
arguments: args,
result,
} = data as { instance: Pino; arguments: PinoHookArgs; result: string };
onPinoStart(instance, args, result);
onPinoStart(instance, args, JSON.parse(result));
});
},
};
Expand Down
Loading