Skip to content

Commit 438e8be

Browse files
authored
feat(core): Add consoleLoggingIntegration for logs (#15955)
Adds `consoleLoggingIntegration` integration that takes calls to `console.X` and flushes them as logs. For now this is an opt-in integration. We can evaluate it's default status at a later point. ```js import * as Sentry from '@sentry/browser'; // or any other supported sdk Sentry.init({ // send console.log, console.error, and console.warn calls as logs to Sentry integrations: [Sentry.consoleLoggingIntegration({ levels: ['log', 'error', 'warn'] })], }); ``` ## Notes In general we have inconsistencies with console instrumentation across our different SDKs. - In browser we have console instrumentation as part of the `Breadcrumbs` integration. - In node we have console instrumentation that generates breadcrumbs in the `Console` integration - In core we have console instrumentation, which generates errors and messages via the `CaptureConsole` integration For now because logs are experimental, making it a standalone integration feels fine to me. As we get closer to GA status for logs (and there is a distinct path for breadcrumbs) we should evaluate how all of our console integrations are structured.
1 parent 6501d52 commit 438e8be

File tree

17 files changed

+233
-3
lines changed

17 files changed

+233
-3
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
window.Sentry = Sentry;
4+
5+
Sentry.init({
6+
dsn: 'https://[email protected]/1337',
7+
_experiments: {
8+
enableLogs: true,
9+
},
10+
integrations: [Sentry.consoleLoggingIntegration()],
11+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
console.trace('console.trace', 123, false);
2+
console.debug('console.debug', 123, false);
3+
console.log('console.log', 123, false);
4+
console.info('console.info', 123, false);
5+
console.warn('console.warn', 123, false);
6+
console.error('console.error', 123, false);
7+
console.assert(false, 'console.assert', 123, false);
8+
9+
console.log('');
10+
11+
Sentry.flush();
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { expect } from '@playwright/test';
2+
import type { OtelLogEnvelope } from '@sentry/core';
3+
4+
import { sentryTest } from '../../../../utils/fixtures';
5+
import { getFirstSentryEnvelopeRequest, properFullEnvelopeRequestParser } from '../../../../utils/helpers';
6+
7+
sentryTest('should capture console object calls', async ({ getLocalTestUrl, page }) => {
8+
const bundle = process.env.PW_BUNDLE || '';
9+
// Only run this for npm package exports
10+
if (bundle.startsWith('bundle') || bundle.startsWith('loader')) {
11+
sentryTest.skip();
12+
}
13+
14+
const url = await getLocalTestUrl({ testDir: __dirname });
15+
16+
const event = await getFirstSentryEnvelopeRequest<OtelLogEnvelope>(page, url, properFullEnvelopeRequestParser);
17+
const envelopeItems = event[1];
18+
19+
expect(envelopeItems[0]).toEqual([
20+
{
21+
type: 'otel_log',
22+
},
23+
{
24+
severityText: 'trace',
25+
body: { stringValue: 'console.trace 123 false' },
26+
attributes: [],
27+
timeUnixNano: expect.any(String),
28+
traceId: expect.any(String),
29+
severityNumber: 1,
30+
},
31+
]);
32+
33+
expect(envelopeItems[1]).toEqual([
34+
{
35+
type: 'otel_log',
36+
},
37+
{
38+
severityText: 'debug',
39+
body: { stringValue: 'console.debug 123 false' },
40+
attributes: [],
41+
timeUnixNano: expect.any(String),
42+
traceId: expect.any(String),
43+
severityNumber: 5,
44+
},
45+
]);
46+
47+
expect(envelopeItems[2]).toEqual([
48+
{
49+
type: 'otel_log',
50+
},
51+
{
52+
severityText: 'info',
53+
body: { stringValue: 'console.log 123 false' },
54+
attributes: [],
55+
timeUnixNano: expect.any(String),
56+
traceId: expect.any(String),
57+
severityNumber: 10,
58+
},
59+
]);
60+
61+
expect(envelopeItems[3]).toEqual([
62+
{
63+
type: 'otel_log',
64+
},
65+
{
66+
severityText: 'info',
67+
body: { stringValue: 'console.info 123 false' },
68+
attributes: [],
69+
timeUnixNano: expect.any(String),
70+
traceId: expect.any(String),
71+
severityNumber: 9,
72+
},
73+
]);
74+
75+
expect(envelopeItems[4]).toEqual([
76+
{
77+
type: 'otel_log',
78+
},
79+
{
80+
severityText: 'warn',
81+
body: { stringValue: 'console.warn 123 false' },
82+
attributes: [],
83+
timeUnixNano: expect.any(String),
84+
traceId: expect.any(String),
85+
severityNumber: 13,
86+
},
87+
]);
88+
89+
expect(envelopeItems[5]).toEqual([
90+
{
91+
type: 'otel_log',
92+
},
93+
{
94+
severityText: 'error',
95+
body: { stringValue: 'console.error 123 false' },
96+
attributes: [],
97+
timeUnixNano: expect.any(String),
98+
traceId: expect.any(String),
99+
severityNumber: 17,
100+
},
101+
]);
102+
103+
expect(envelopeItems[6]).toEqual([
104+
{
105+
type: 'otel_log',
106+
},
107+
{
108+
severityText: 'error',
109+
body: { stringValue: 'Assertion failed: console.assert 123 false' },
110+
attributes: [],
111+
timeUnixNano: expect.any(String),
112+
traceId: expect.any(String),
113+
severityNumber: 17,
114+
},
115+
]);
116+
});

dev-packages/browser-integration-tests/suites/public-api/logger/test.ts renamed to dev-packages/browser-integration-tests/suites/public-api/logger/simple/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { expect } from '@playwright/test';
22
import type { OtelLogEnvelope } from '@sentry/core';
33

4-
import { sentryTest } from '../../../utils/fixtures';
5-
import { getFirstSentryEnvelopeRequest, properFullEnvelopeRequestParser } from '../../../utils/helpers';
4+
import { sentryTest } from '../../../../utils/fixtures';
5+
import { getFirstSentryEnvelopeRequest, properFullEnvelopeRequestParser } from '../../../../utils/helpers';
66

77
sentryTest('should capture all logging methods', async ({ getLocalTestUrl, page }) => {
88
const bundle = process.env.PW_BUNDLE || '';

packages/astro/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export {
128128
zodErrorsIntegration,
129129
profiler,
130130
logger,
131+
consoleLoggingIntegration,
131132
} from '@sentry/node';
132133

133134
export { init } from './server/sdk';

packages/aws-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export {
114114
amqplibIntegration,
115115
vercelAIIntegration,
116116
logger,
117+
consoleLoggingIntegration,
117118
} from '@sentry/node';
118119

119120
export {

packages/browser/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export {
1414
extraErrorDataIntegration,
1515
rewriteFramesIntegration,
1616
captureFeedback,
17+
consoleLoggingIntegration,
1718
} from '@sentry/core';
1819

1920
export { replayIntegration, getReplay } from '@sentry-internal/replay';

packages/bun/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export {
133133
amqplibIntegration,
134134
vercelAIIntegration,
135135
logger,
136+
consoleLoggingIntegration,
136137
} from '@sentry/node';
137138

138139
export {

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export { trpcMiddleware } from './trpc';
114114
export { captureFeedback } from './feedback';
115115
export type { ReportDialogOptions } from './report-dialog';
116116
export { _INTERNAL_captureLog, _INTERNAL_flushLogsBuffer } from './logs/exports';
117+
export { consoleLoggingIntegration } from './logs/console-integration';
117118

118119
// TODO: Make this structure pretty again and don't do "export *"
119120
export * from './utils-hoist/index';

0 commit comments

Comments
 (0)