Skip to content

Commit 1ae023d

Browse files
authored
[DI] Use column number from source maps (#5279)
1 parent 366368a commit 1ae023d

File tree

15 files changed

+86
-34
lines changed

15 files changed

+86
-34
lines changed

eslint.config.mjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ export default [
4141
'**/versions', // This is effectively a node_modules tree.
4242
'**/acmeair-nodejs', // We don't own this.
4343
'**/vendor', // Generally, we didn't author this code.
44-
'integration-tests/debugger/target-app/source-map-support/index.js', // Generated
44+
'integration-tests/debugger/target-app/source-map-support/minify.min.js', // Generated
45+
'integration-tests/debugger/target-app/source-map-support/typescript.js', // Generated
4546
'integration-tests/esbuild/out.js', // Generated
4647
'integration-tests/esbuild/aws-sdk-out.js', // Generated
4748
'packages/dd-trace/src/appsec/blocked_templates.js', // TODO Why is this ignored?

integration-tests/debugger/source-map-support.spec.js

+35-12
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,46 @@ const { setup } = require('./utils')
55

66
describe('Dynamic Instrumentation', function () {
77
describe('source map support', function () {
8-
const t = setup({
9-
testApp: 'target-app/source-map-support/index.js',
10-
testAppSource: 'target-app/source-map-support/index.ts'
11-
})
8+
describe('Different file extention (TypeScript)', function () {
9+
const t = setup({
10+
testApp: 'target-app/source-map-support/typescript.js',
11+
testAppSource: 'target-app/source-map-support/typescript.ts'
12+
})
1213

13-
beforeEach(t.triggerBreakpoint)
14+
beforeEach(t.triggerBreakpoint)
1415

15-
it('should support source maps', function (done) {
16-
t.agent.on('debugger-input', ({ payload: [{ 'debugger.snapshot': { probe: { location } } }] }) => {
17-
assert.deepEqual(location, {
18-
file: 'target-app/source-map-support/index.ts',
19-
lines: ['9']
16+
it('should support source maps', function (done) {
17+
t.agent.on('debugger-input', ({ payload: [{ 'debugger.snapshot': { probe: { location } } }] }) => {
18+
assert.deepEqual(location, {
19+
file: 'target-app/source-map-support/typescript.ts',
20+
lines: ['9']
21+
})
22+
done()
2023
})
21-
done()
24+
25+
t.agent.addRemoteConfig(t.rcConfig)
26+
})
27+
})
28+
29+
describe('Column information required (Minified)', function () {
30+
const t = setup({
31+
testApp: 'target-app/source-map-support/minify.min.js',
32+
testAppSource: 'target-app/source-map-support/minify.js'
2233
})
2334

24-
t.agent.addRemoteConfig(t.rcConfig)
35+
beforeEach(t.triggerBreakpoint)
36+
37+
it('should support source maps', function (done) {
38+
t.agent.on('debugger-input', ({ payload: [{ 'debugger.snapshot': { probe: { location } } }] }) => {
39+
assert.deepEqual(location, {
40+
file: 'target-app/source-map-support/minify.js',
41+
lines: ['6']
42+
})
43+
done()
44+
})
45+
46+
t.agent.addRemoteConfig(t.rcConfig)
47+
})
2548
})
2649
})
2750
})

integration-tests/debugger/target-app/source-map-support/index.js.map

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require('dd-trace/init')
2+
3+
const { createServer } = require('node:http')
4+
5+
const server = createServer((req, res) => {
6+
res.end('hello world') // BREAKPOINT: /
7+
})
8+
9+
server.listen(process.env.APP_PORT, () => {
10+
process.send?.({ port: process.env.APP_PORT })
11+
})

integration-tests/debugger/target-app/source-map-support/minify.min.js

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration-tests/debugger/target-app/source-map-support/minify.min.js.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env sh
2+
3+
npx uglify-js integration-tests/debugger/target-app/source-map-support/minify.js \
4+
-o integration-tests/debugger/target-app/source-map-support/minify.min.js \
5+
--v8 \
6+
--source-map url=minify.min.js.map
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env sh
2+
3+
npx --package=typescript -- tsc --sourceMap integration-tests/debugger/target-app/source-map-support/typescript.ts

integration-tests/debugger/target-app/source-map-support/index.js integration-tests/debugger/target-app/source-map-support/typescript.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integration-tests/debugger/target-app/source-map-support/typescript.js.map

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const { randomUUID } = require('crypto')
1212
// TODO: move debugger/devtools_client/session to common place
1313
const session = require('../../../debugger/devtools_client/session')
1414
// TODO: move debugger/devtools_client/source-maps to common place
15-
const { getSourceMappedLine } = require('../../../debugger/devtools_client/source-maps')
15+
const { getGeneratedPosition } = require('../../../debugger/devtools_client/source-maps')
1616
// TODO: move debugger/devtools_client/snapshot to common place
1717
const { getLocalStateForCallFrame } = require('../../../debugger/devtools_client/snapshot')
1818
// TODO: move debugger/devtools_client/state to common place
@@ -104,24 +104,27 @@ async function addBreakpoint (probe) {
104104
log.warn(`Adding breakpoint at ${url}:${line}`)
105105

106106
let lineNumber = line
107+
let columnNumber = 0
107108

108109
if (sourceMapURL) {
109110
try {
110-
lineNumber = await getSourceMappedLine(url, source, line, sourceMapURL)
111+
({ line: lineNumber, column: columnNumber } = await getGeneratedPosition(url, source, line, sourceMapURL))
111112
} catch (err) {
112113
log.error('Error processing script with source map', err)
113114
}
114115
if (lineNumber === null) {
115116
log.error('Could not find generated position for %s:%s', url, line)
116117
lineNumber = line
118+
columnNumber = 0
117119
}
118120
}
119121

120122
try {
121123
const { breakpointId } = await session.post('Debugger.setBreakpoint', {
122124
location: {
123125
scriptId,
124-
lineNumber: lineNumber - 1
126+
lineNumber: lineNumber - 1,
127+
columnNumber
125128
}
126129
})
127130

packages/dd-trace/src/debugger/devtools_client/breakpoints.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const { getSourceMappedLine } = require('./source-maps')
3+
const { getGeneratedPosition } = require('./source-maps')
44
const session = require('./session')
55
const { MAX_SNAPSHOTS_PER_SECOND_PER_PROBE, MAX_NON_SNAPSHOTS_PER_SECOND_PER_PROBE } = require('./defaults')
66
const { findScriptFromPartialPath, probes, breakpoints } = require('./state')
@@ -17,10 +17,11 @@ async function addBreakpoint (probe) {
1717
if (!sessionStarted) await start()
1818

1919
const file = probe.where.sourceFile
20-
let line = Number(probe.where.lines[0]) // Tracer doesn't support multiple-line breakpoints
20+
let lineNumber = Number(probe.where.lines[0]) // Tracer doesn't support multiple-line breakpoints
21+
let columnNumber = 0 // Probes do not contain/support column information
2122

2223
// Optimize for sending data to /debugger/v1/input endpoint
23-
probe.location = { file, lines: [String(line)] }
24+
probe.location = { file, lines: [String(lineNumber)] }
2425
delete probe.where
2526

2627
// Optimize for fast calculations when probe is hit
@@ -38,18 +39,19 @@ async function addBreakpoint (probe) {
3839
const { url, scriptId, sourceMapURL, source } = script
3940

4041
if (sourceMapURL) {
41-
line = await getSourceMappedLine(url, source, line, sourceMapURL)
42+
({ line: lineNumber, column: columnNumber } = await getGeneratedPosition(url, source, lineNumber, sourceMapURL))
4243
}
4344

4445
log.debug(
45-
'[debugger:devtools_client] Adding breakpoint at %s:%d (probe: %s, version: %d)',
46-
url, line, probe.id, probe.version
46+
'[debugger:devtools_client] Adding breakpoint at %s:%d:%d (probe: %s, version: %d)',
47+
url, lineNumber, columnNumber, probe.id, probe.version
4748
)
4849

4950
const { breakpointId } = await session.post('Debugger.setBreakpoint', {
5051
location: {
5152
scriptId,
52-
lineNumber: line - 1 // Beware! lineNumber is zero-indexed
53+
lineNumber: lineNumber - 1, // Beware! lineNumber is zero-indexed
54+
columnNumber
5355
}
5456
})
5557

packages/dd-trace/src/debugger/devtools_client/source-maps.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ const self = module.exports = {
2323
return cacheIt(path, JSON.parse(readFileSync(path, 'utf8')))
2424
},
2525

26-
async getSourceMappedLine (url, source, line, sourceMapURL) {
26+
async getGeneratedPosition (url, source, line, sourceMapURL) {
2727
const dir = dirname(new URL(url).pathname)
2828
return await SourceMapConsumer.with(
2929
await self.loadSourceMap(dir, sourceMapURL),
3030
null,
31-
(consumer) => consumer.generatedPositionFor({ source, line, column: 0 }).line
31+
(consumer) => consumer.generatedPositionFor({ source, line, column: 0 })
3232
)
3333
}
3434
}

packages/dd-trace/test/debugger/devtools_client/source-maps.spec.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const rawSourceMap = JSON.stringify(parsedSourceMap)
1616
const inlineSourceMap = `data:application/json;base64,${Buffer.from(rawSourceMap).toString('base64')}`
1717

1818
describe('source map utils', function () {
19-
let loadSourceMap, loadSourceMapSync, getSourceMappedLine, readFileSync, readFile
19+
let loadSourceMap, loadSourceMapSync, getGeneratedPosition, readFileSync, readFile
2020

2121
describe('basic', function () {
2222
beforeEach(function () {
@@ -30,7 +30,7 @@ describe('source map utils', function () {
3030

3131
loadSourceMap = sourceMaps.loadSourceMap
3232
loadSourceMapSync = sourceMaps.loadSourceMapSync
33-
getSourceMappedLine = sourceMaps.getSourceMappedLine
33+
getGeneratedPosition = sourceMaps.getGeneratedPosition
3434
})
3535

3636
describe('loadSourceMap', function () {
@@ -77,19 +77,19 @@ describe('source map utils', function () {
7777
})
7878
})
7979

80-
describe('getSourceMappedLine', function () {
80+
describe('getGeneratedPosition', function () {
8181
const url = `file://${dir}/${parsedSourceMap.file}`
8282
const source = parsedSourceMap.sources[0]
8383
const line = 1
8484

8585
it('should return expected line for inline source map', async function () {
86-
const result = await getSourceMappedLine(url, source, line, sourceMapURL)
87-
expect(result).to.equal(2)
86+
const pos = await getGeneratedPosition(url, source, line, sourceMapURL)
87+
expect(pos).to.deep.equal({ line: 2, column: 0, lastColumn: 5 })
8888
})
8989

9090
it('should return expected line for non-inline source map', async function () {
91-
const result = await getSourceMappedLine(url, source, line, inlineSourceMap)
92-
expect(result).to.equal(2)
91+
const pos = await getGeneratedPosition(url, source, line, inlineSourceMap)
92+
expect(pos).to.deep.equal({ line: 2, column: 0, lastColumn: 5 })
9393
})
9494
})
9595
})

0 commit comments

Comments
 (0)