Skip to content

Commit 80571e0

Browse files
authored
fix(ts): added filter into ts definition file (#7368)
* added filter into ts definition file * moved queryStringObfuscation and resourceRenamingEnabled * Added e2e tests for filter config in http http2 and redis * added tests for resourceRenamingEnabled in http * added tests for queryStringObfuscation * added test to verify multiple filters don't conflict
1 parent 93f7c4b commit 80571e0

File tree

6 files changed

+424
-24
lines changed

6 files changed

+424
-24
lines changed

index.d.ts

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,16 @@ declare namespace tracer {
15741574
*/
15751575
blacklist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
15761576

1577+
/**
1578+
* Custom filter function used to decide whether a URL/path is allowed.
1579+
* When provided, this takes precedence over allowlist/blocklist configuration.
1580+
* If not provided, allowlist/blocklist logic will be used instead.
1581+
*
1582+
* @param urlOrPath - The URL or path to filter
1583+
* @returns true to instrument the request, false to skip it
1584+
*/
1585+
filter?: (urlOrPath: string) => boolean;
1586+
15771587
/**
15781588
* An array of headers to include in the span metadata.
15791589
*
@@ -1626,6 +1636,21 @@ declare namespace tracer {
16261636
* @default true
16271637
*/
16281638
middleware?: boolean;
1639+
1640+
/**
1641+
* Whether (or how) to obfuscate querystring values in `http.url`.
1642+
*
1643+
* - `true`: obfuscate all values
1644+
* - `false`: disable obfuscation
1645+
* - `string`: regex string used to obfuscate matching values (empty string disables)
1646+
* - `RegExp`: regex used to obfuscate matching values
1647+
*/
1648+
queryStringObfuscation?: boolean | string | RegExp;
1649+
1650+
/**
1651+
* Whether to enable resource renaming when the framework route is unavailable.
1652+
*/
1653+
resourceRenamingEnabled?: boolean;
16291654
}
16301655

16311656
/** @hidden */
@@ -1691,6 +1716,20 @@ declare namespace tracer {
16911716
* @default code => code < 500
16921717
*/
16931718
validateStatus?: (code: number) => boolean;
1719+
/**
1720+
* Whether (or how) to obfuscate querystring values in `http.url`.
1721+
*
1722+
* - `true`: obfuscate all values
1723+
* - `false`: disable obfuscation
1724+
* - `string`: regex string used to obfuscate matching values (empty string disables)
1725+
* - `RegExp`: regex used to obfuscate matching values
1726+
*/
1727+
queryStringObfuscation?: boolean | string | RegExp;
1728+
1729+
/**
1730+
* Whether to enable resource renaming when the framework route is unavailable.
1731+
*/
1732+
resourceRenamingEnabled?: boolean;
16941733
}
16951734

16961735
/** @hidden */
@@ -1827,7 +1866,12 @@ declare namespace tracer {
18271866
* This plugin automatically instruments the
18281867
* @azure/functions module.
18291868
*/
1830-
interface azure_functions extends Instrumentation {}
1869+
interface azure_functions extends Instrumentation {
1870+
/**
1871+
* Whether to enable resource renaming when the framework route is unavailable.
1872+
*/
1873+
resourceRenamingEnabled?: boolean;
1874+
}
18311875

18321876
/**
18331877
* This plugin automatically instruments the
@@ -2178,6 +2222,16 @@ declare namespace tracer {
21782222
*/
21792223
blacklist?: string | RegExp | ((command: string) => boolean) | (string | RegExp | ((command: string) => boolean))[];
21802224

2225+
/**
2226+
* Custom filter function used to decide whether a Redis command should be instrumented.
2227+
* When provided, this takes precedence over allowlist/blocklist configuration.
2228+
* If not provided, allowlist/blocklist logic will be used instead.
2229+
*
2230+
* @param command - The Redis command name to filter
2231+
* @returns true to instrument the command, false to skip it
2232+
*/
2233+
filter?: (command: string) => boolean;
2234+
21812235
/**
21822236
* Whether to use a different service name for each Redis instance based
21832237
* on the configured connection name of the client.
@@ -2225,6 +2279,16 @@ declare namespace tracer {
22252279
*/
22262280
blacklist?: string | RegExp | ((command: string) => boolean) | (string | RegExp | ((command: string) => boolean))[];
22272281

2282+
/**
2283+
* Custom filter function used to decide whether a Valkey command should be instrumented.
2284+
* When provided, this takes precedence over allowlist/blocklist configuration.
2285+
* If not provided, allowlist/blocklist logic will be used instead.
2286+
*
2287+
* @param command - The Valkey command name to filter
2288+
* @returns true to instrument the command, false to skip it
2289+
*/
2290+
filter?: (command: string) => boolean;
2291+
22282292
/**
22292293
* Whether to use a different service name for each Redis instance based
22302294
* on the configured connection name of the client.
@@ -2498,6 +2562,16 @@ declare namespace tracer {
24982562
* @hidden
24992563
*/
25002564
blacklist?: string | RegExp | ((command: string) => boolean) | (string | RegExp | ((command: string) => boolean))[];
2565+
2566+
/**
2567+
* Custom filter function used to decide whether a Redis command should be instrumented.
2568+
* When provided, this takes precedence over allowlist/blocklist configuration.
2569+
* If not provided, allowlist/blocklist logic will be used instead.
2570+
*
2571+
* @param command - The Redis command name to filter
2572+
* @returns true to instrument the command, false to skip it
2573+
*/
2574+
filter?: (command: string) => boolean;
25012575
}
25022576

25032577
/**
@@ -2566,28 +2640,7 @@ declare namespace tracer {
25662640
/**
25672641
* This plugin implements shared web request instrumentation helpers.
25682642
*/
2569-
interface web extends HttpServer {
2570-
/**
2571-
* Custom filter function used to decide whether a URL/path should be instrumented.
2572-
* Takes precedence over allowlist/blocklist.
2573-
*/
2574-
filter?: (urlOrPath: string) => boolean;
2575-
2576-
/**
2577-
* Whether (or how) to obfuscate querystring values in `http.url`.
2578-
*
2579-
* - `true`: obfuscate all values
2580-
* - `false`: disable obfuscation
2581-
* - `string`: regex string used to obfuscate matching values (empty string disables)
2582-
* - `RegExp`: regex used to obfuscate matching values
2583-
*/
2584-
queryStringObfuscation?: boolean | string | RegExp;
2585-
2586-
/**
2587-
* Whether to enable resource renaming when the framework route is unavailable.
2588-
*/
2589-
resourceRenamingEnabled?: boolean;
2590-
}
2643+
interface web extends HttpServer {}
25912644

25922645
/**
25932646
* This plugin patches the [winston](https://github.com/winstonjs/winston)

packages/datadog-plugin-http/test/client.spec.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,95 @@ describe('Plugin', () => {
14171417
})
14181418
})
14191419
})
1420+
1421+
describe('with filter configuration', () => {
1422+
describe('when filter is only applied to client', () => {
1423+
beforeEach(() => {
1424+
const config = {
1425+
server: false,
1426+
client: {
1427+
filter: (url) => !url.includes('/health'),
1428+
},
1429+
}
1430+
1431+
return agent.load('http', config)
1432+
.then(() => {
1433+
http = require(pluginToBeLoaded)
1434+
express = require('express')
1435+
})
1436+
})
1437+
1438+
it('should skip recording if the filter function returns false', done => {
1439+
const app = express()
1440+
1441+
app.get('/health', (req, res) => {
1442+
res.status(200).send()
1443+
})
1444+
1445+
const timer = setTimeout(done, 100)
1446+
1447+
agent.assertSomeTraces(() => {
1448+
clearTimeout(timer)
1449+
done(new Error('Filtered requests should not be recorded.'))
1450+
})
1451+
1452+
appListener = server(app, port => {
1453+
const req = http.request(`${protocol}://localhost:${port}/health`, res => {
1454+
res.on('data', () => {})
1455+
})
1456+
req.end()
1457+
})
1458+
})
1459+
})
1460+
1461+
// This tests that multiple filters do not conflict
1462+
describe('when both server and client apply a filter', () => {
1463+
beforeEach(() => {
1464+
const config = {
1465+
server: {
1466+
filter: (url) => !url.includes('/health'),
1467+
},
1468+
client: {
1469+
filter: () => true,
1470+
},
1471+
}
1472+
1473+
return agent.load('http', config)
1474+
.then(() => {
1475+
http = require(pluginToBeLoaded)
1476+
express = require('express')
1477+
})
1478+
})
1479+
1480+
it('should record only the client span', done => {
1481+
const allSpans = []
1482+
const app = express()
1483+
1484+
app.get('/health', (req, res) => {
1485+
res.status(200).send()
1486+
})
1487+
1488+
agent
1489+
.assertSomeTraces(traces => {
1490+
allSpans.push(...traces.flat())
1491+
const clientSpans = allSpans.filter(span => span.meta['span.kind'] === 'client')
1492+
const serverSpans = allSpans.filter(span => span.meta['span.kind'] === 'server')
1493+
1494+
assert.strictEqual(clientSpans.length, 1)
1495+
assert.strictEqual(serverSpans.length, 0)
1496+
})
1497+
.then(done)
1498+
.catch(done)
1499+
1500+
appListener = server(app, port => {
1501+
const req = http.request(`${protocol}://localhost:${port}/health`, res => {
1502+
res.on('data', () => {})
1503+
})
1504+
req.end()
1505+
})
1506+
})
1507+
})
1508+
})
14201509
})
14211510
})
14221511
})

packages/datadog-plugin-http/test/server.spec.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,68 @@ describe('Plugin', () => {
265265
axios.get(`http://localhost:${port}/health`).catch(done)
266266
})
267267
})
268+
269+
describe('with resourceRenamingEnabled configuration', () => {
270+
beforeEach(() => {
271+
return agent.load('http', { client: false, resourceRenamingEnabled: true })
272+
.then(() => {
273+
http = require(pluginToBeLoaded)
274+
})
275+
})
276+
277+
beforeEach(done => {
278+
const server = new http.Server(listener)
279+
appListener = server
280+
.listen(0, 'localhost', () => {
281+
port = appListener.address().port
282+
done()
283+
})
284+
})
285+
286+
it('should normalize hex segments in the path', done => {
287+
agent
288+
.assertSomeTraces(traces => {
289+
assert.strictEqual(traces[0][0].meta['http.endpoint'], '/users/{param:hex}/profile')
290+
})
291+
.then(done)
292+
.catch(done)
293+
294+
axios.get(`http://localhost:${port}/users/a1f3e2d1c0/profile`).catch(done)
295+
})
296+
297+
it('should normalize int segments in the path', done => {
298+
agent
299+
.assertSomeTraces(traces => {
300+
assert.strictEqual(traces[0][0].meta['http.endpoint'], '/users/{param:int}/profile')
301+
})
302+
.then(done)
303+
.catch(done)
304+
305+
axios.get(`http://localhost:${port}/users/1234/profile`).catch(done)
306+
})
307+
308+
it('should normalize int id segments in the path', done => {
309+
agent
310+
.assertSomeTraces(traces => {
311+
assert.strictEqual(traces[0][0].meta['http.endpoint'], '/users/{param:int_id}/profile')
312+
})
313+
.then(done)
314+
.catch(done)
315+
316+
axios.get(`http://localhost:${port}/users/1234-1234/profile`).catch(done)
317+
})
318+
319+
it('should keep short path segments unchanged', done => {
320+
agent
321+
.assertSomeTraces(traces => {
322+
assert.strictEqual(traces[0][0].meta['http.endpoint'], '/api/v1/users')
323+
})
324+
.then(done)
325+
.catch(done)
326+
327+
axios.get(`http://localhost:${port}/api/v1/users`).catch(done)
328+
})
329+
})
268330
})
269331
})
270332
})

packages/datadog-plugin-http2/test/client.spec.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,51 @@ describe('Plugin', () => {
947947
})
948948
})
949949
})
950+
951+
describe('with filter configuration', () => {
952+
let config
953+
954+
beforeEach(() => {
955+
config = {
956+
server: false,
957+
client: {
958+
filter: (url) => !url.includes('/health'),
959+
},
960+
}
961+
962+
return agent.load('http2', config)
963+
.then(() => {
964+
http2 = require(loadPlugin)
965+
})
966+
})
967+
968+
it('should skip recording if the url is filtered out', done => {
969+
const app = (stream, headers) => {
970+
stream.respond({
971+
':status': 200,
972+
})
973+
stream.end()
974+
}
975+
976+
appListener = server(app, port => {
977+
const timer = setTimeout(done, 100)
978+
979+
agent
980+
.assertSomeTraces(() => {
981+
clearTimeout(timer)
982+
done(new Error('filtered requests should not be recorded.'))
983+
})
984+
.catch(done)
985+
986+
const client = http2.connect(`${protocol}://localhost:${port}`)
987+
.on('error', done)
988+
989+
client.request({ ':path': '/health' })
990+
.on('error', done)
991+
.end()
992+
})
993+
})
994+
})
950995
})
951996
})
952997
})

0 commit comments

Comments
 (0)