Skip to content

Commit 60b6132

Browse files
committed
Merge branch 'develop' into feat/knexIntegration-node
2 parents de2277a + 8c2aa1b commit 60b6132

File tree

22 files changed

+636
-168
lines changed

22 files changed

+636
-168
lines changed

dev-packages/e2e-tests/test-applications/react-router-6/tests/sse.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,12 @@ test('Waits for sse streaming when sse has been explicitly aborted', async ({ pa
6666
expect(resolveBodyDuration).toBe(0);
6767

6868
// validate abort error was thrown by inspecting console
69-
const consoleBreadcrumb = rootSpan.breadcrumbs?.find(breadcrumb => breadcrumb.category === 'console');
70-
expect(consoleBreadcrumb?.message).toBe('Could not fetch sse AbortError: BodyStreamBuffer was aborted');
69+
expect(rootSpan.breadcrumbs).toContainEqual(
70+
expect.objectContaining({
71+
category: 'console',
72+
message: 'Could not fetch sse AbortError: BodyStreamBuffer was aborted',
73+
}),
74+
);
7175
});
7276

7377
test('Aborts when stream takes longer than 5s, by not updating the span duration', async ({ page }) => {

dev-packages/node-integration-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"redis-4": "npm:redis@^4.6.14",
6767
"reflect-metadata": "0.2.1",
6868
"rxjs": "^7.8.1",
69+
"tedious": "^18.6.1",
6970
"yargs": "^16.2.0"
7071
},
7172
"devDependencies": {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version: '3.9'
2+
3+
services:
4+
db:
5+
image: mcr.microsoft.com/mssql/server:2022-latest
6+
restart: always
7+
container_name: integration-tests-tedious
8+
ports:
9+
- '1433:1433'
10+
environment:
11+
ACCEPT_EULA: 'Y'
12+
MSSQL_SA_PASSWORD: 'TESTing123'
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
2+
const Sentry = require('@sentry/node');
3+
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
transport: loggingTransport,
9+
});
10+
11+
const { Connection, Request } = require('tedious');
12+
13+
const config = {
14+
server: '127.0.0.1',
15+
authentication: {
16+
type: 'default',
17+
options: {
18+
userName: 'sa',
19+
password: 'TESTing123',
20+
},
21+
},
22+
options: {
23+
port: 1433,
24+
encrypt: false,
25+
},
26+
};
27+
28+
const connection = new Connection(config);
29+
30+
function executeAllStatements(span) {
31+
executeStatement('SELECT 1 + 1 AS solution', () => {
32+
executeStatement('SELECT GETDATE()', () => {
33+
span.end();
34+
connection.close();
35+
});
36+
});
37+
}
38+
39+
function executeStatement(query, callback) {
40+
const request = new Request(query, err => {
41+
if (err) {
42+
throw err;
43+
}
44+
callback();
45+
});
46+
47+
connection.execSql(request);
48+
}
49+
50+
connection.connect(err => {
51+
if (err) {
52+
throw err;
53+
}
54+
55+
Sentry.startSpanManual(
56+
{
57+
op: 'transaction',
58+
name: 'Test Transaction',
59+
},
60+
span => {
61+
// span must be ended manually after all queries
62+
executeAllStatements(span);
63+
},
64+
);
65+
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { conditionalTest } from '../../../utils';
2+
import { cleanupChildProcesses, createRunner } from '../../../utils/runner';
3+
4+
jest.setTimeout(75000);
5+
6+
// Tedious version we are testing against only supports Node 18+
7+
// https://github.com/tediousjs/tedious/blob/8310c455a2cc1cba83c1ca3c16677da4f83e12a9/package.json#L38
8+
conditionalTest({ min: 18 })('tedious auto instrumentation', () => {
9+
afterAll(() => {
10+
cleanupChildProcesses();
11+
});
12+
13+
test('should auto-instrument `tedious` package', done => {
14+
const EXPECTED_TRANSACTION = {
15+
transaction: 'Test Transaction',
16+
spans: expect.arrayContaining([
17+
expect.objectContaining({
18+
description: 'SELECT GETDATE()',
19+
data: expect.objectContaining({
20+
'sentry.origin': 'auto.db.otel.tedious',
21+
'sentry.op': 'db',
22+
'db.name': 'master',
23+
'db.statement': 'SELECT GETDATE()',
24+
'db.system': 'mssql',
25+
'db.user': 'sa',
26+
'net.peer.name': '127.0.0.1',
27+
'net.peer.port': 1433,
28+
}),
29+
status: 'ok',
30+
}),
31+
expect.objectContaining({
32+
description: 'SELECT 1 + 1 AS solution',
33+
data: expect.objectContaining({
34+
'sentry.origin': 'auto.db.otel.tedious',
35+
'sentry.op': 'db',
36+
'db.name': 'master',
37+
'db.statement': 'SELECT 1 + 1 AS solution',
38+
'db.system': 'mssql',
39+
'db.user': 'sa',
40+
'net.peer.name': '127.0.0.1',
41+
'net.peer.port': 1433,
42+
}),
43+
status: 'ok',
44+
}),
45+
]),
46+
};
47+
48+
createRunner(__dirname, 'scenario.js')
49+
.withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['1433'] })
50+
.expect({ transaction: EXPECTED_TRANSACTION })
51+
.start(done);
52+
});
53+
});

packages/astro/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export {
126126
startSession,
127127
startSpan,
128128
startSpanManual,
129+
tediousIntegration,
129130
trpcMiddleware,
130131
withActiveSpan,
131132
withIsolationScope,

packages/aws-serverless/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export {
100100
mysqlIntegration,
101101
mysql2Integration,
102102
redisIntegration,
103+
tediousIntegration,
103104
nestIntegration,
104105
setupNestErrorHandler,
105106
postgresIntegration,

packages/browser/src/profiling/utils.ts

Lines changed: 3 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
/* eslint-disable max-lines */
22

33
import { DEFAULT_ENVIRONMENT, getClient, spanToJSON } from '@sentry/core';
4-
import type {
5-
DebugImage,
6-
Envelope,
7-
Event,
8-
EventEnvelope,
9-
Profile,
10-
Span,
11-
StackFrame,
12-
StackParser,
13-
ThreadCpuProfile,
14-
} from '@sentry/types';
4+
import type { DebugImage, Envelope, Event, EventEnvelope, Profile, Span, ThreadCpuProfile } from '@sentry/types';
155
import {
16-
GLOBAL_OBJ,
176
browserPerformanceTimeOrigin,
187
forEachEnvelopeItem,
8+
getDebugImagesForResources,
199
logger,
2010
timestampInSeconds,
2111
uuid4,
@@ -352,17 +342,10 @@ export function findProfiledTransactionsFromEnvelope(envelope: Envelope): Event[
352342
return events;
353343
}
354344

355-
const debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();
356345
/**
357346
* Applies debug meta data to an event from a list of paths to resources (sourcemaps)
358347
*/
359348
export function applyDebugMetadata(resource_paths: ReadonlyArray<string>): DebugImage[] {
360-
const debugIdMap = GLOBAL_OBJ._sentryDebugIds;
361-
362-
if (!debugIdMap) {
363-
return [];
364-
}
365-
366349
const client = getClient();
367350
const options = client && client.getOptions();
368351
const stackParser = options && options.stackParser;
@@ -371,51 +354,7 @@ export function applyDebugMetadata(resource_paths: ReadonlyArray<string>): Debug
371354
return [];
372355
}
373356

374-
let debugIdStackFramesCache: Map<string, StackFrame[]>;
375-
const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
376-
if (cachedDebugIdStackFrameCache) {
377-
debugIdStackFramesCache = cachedDebugIdStackFrameCache;
378-
} else {
379-
debugIdStackFramesCache = new Map<string, StackFrame[]>();
380-
debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
381-
}
382-
383-
// Build a map of filename -> debug_id
384-
const filenameDebugIdMap = Object.keys(debugIdMap).reduce<Record<string, string>>((acc, debugIdStackTrace) => {
385-
let parsedStack: StackFrame[];
386-
387-
const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);
388-
if (cachedParsedStack) {
389-
parsedStack = cachedParsedStack;
390-
} else {
391-
parsedStack = stackParser(debugIdStackTrace);
392-
debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
393-
}
394-
395-
for (let i = parsedStack.length - 1; i >= 0; i--) {
396-
const stackFrame = parsedStack[i];
397-
const file = stackFrame && stackFrame.filename;
398-
399-
if (stackFrame && file) {
400-
acc[file] = debugIdMap[debugIdStackTrace] as string;
401-
break;
402-
}
403-
}
404-
return acc;
405-
}, {});
406-
407-
const images: DebugImage[] = [];
408-
for (const path of resource_paths) {
409-
if (path && filenameDebugIdMap[path]) {
410-
images.push({
411-
type: 'sourcemap',
412-
code_file: path,
413-
debug_id: filenameDebugIdMap[path] as string,
414-
});
415-
}
416-
}
417-
418-
return images;
357+
return getDebugImagesForResources(stackParser, resource_paths);
419358
}
420359

421360
/**

packages/bun/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export {
121121
mysqlIntegration,
122122
mysql2Integration,
123123
redisIntegration,
124+
tediousIntegration,
124125
nestIntegration,
125126
setupNestErrorHandler,
126127
postgresIntegration,

packages/core/src/utils/prepareEvent.ts

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@ import type {
66
EventHint,
77
Scope as ScopeInterface,
88
ScopeContext,
9-
StackFrame,
109
StackParser,
1110
} from '@sentry/types';
12-
import { GLOBAL_OBJ, addExceptionMechanism, dateTimestampInSeconds, normalize, truncate, uuid4 } from '@sentry/utils';
11+
import {
12+
addExceptionMechanism,
13+
dateTimestampInSeconds,
14+
getFilenameToDebugIdMap,
15+
normalize,
16+
truncate,
17+
uuid4,
18+
} from '@sentry/utils';
1319

1420
import { DEFAULT_ENVIRONMENT } from '../constants';
1521
import { getGlobalScope } from '../currentScopes';
@@ -161,51 +167,12 @@ function applyClientOptions(event: Event, options: ClientOptions): void {
161167
}
162168
}
163169

164-
const debugIdStackParserCache = new WeakMap<StackParser, Map<string, StackFrame[]>>();
165-
166170
/**
167171
* Puts debug IDs into the stack frames of an error event.
168172
*/
169173
export function applyDebugIds(event: Event, stackParser: StackParser): void {
170-
const debugIdMap = GLOBAL_OBJ._sentryDebugIds;
171-
172-
if (!debugIdMap) {
173-
return;
174-
}
175-
176-
let debugIdStackFramesCache: Map<string, StackFrame[]>;
177-
const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
178-
if (cachedDebugIdStackFrameCache) {
179-
debugIdStackFramesCache = cachedDebugIdStackFrameCache;
180-
} else {
181-
debugIdStackFramesCache = new Map<string, StackFrame[]>();
182-
debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
183-
}
184-
185174
// Build a map of filename -> debug_id
186-
const filenameDebugIdMap = Object.entries(debugIdMap).reduce<Record<string, string>>(
187-
(acc, [debugIdStackTrace, debugIdValue]) => {
188-
let parsedStack: StackFrame[];
189-
const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);
190-
if (cachedParsedStack) {
191-
parsedStack = cachedParsedStack;
192-
} else {
193-
parsedStack = stackParser(debugIdStackTrace);
194-
debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
195-
}
196-
197-
for (let i = parsedStack.length - 1; i >= 0; i--) {
198-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
199-
const stackFrame = parsedStack[i]!;
200-
if (stackFrame.filename) {
201-
acc[stackFrame.filename] = debugIdValue;
202-
break;
203-
}
204-
}
205-
return acc;
206-
},
207-
{},
208-
);
175+
const filenameDebugIdMap = getFilenameToDebugIdMap(stackParser);
209176

210177
try {
211178
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

0 commit comments

Comments
 (0)