Skip to content

Commit f22756b

Browse files
khanayan123tlhunter
authored andcommitted
Fix log injection and applied sampling rule bug (#6299)
* fix log injection and sampling rule bug * instead of deferring sampling decision seperate log injection from sampling * revert * address feedback
1 parent 2b8601e commit f22756b

File tree

4 files changed

+131
-1
lines changed

4 files changed

+131
-1
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict'
2+
3+
const { FakeAgent, createSandbox, spawnProc, curlAndAssertMessage, assertObjectContains } = require('./helpers')
4+
const path = require('path')
5+
const { USER_KEEP } = require('../ext/priority')
6+
7+
describe('Log Injection', () => {
8+
let agent
9+
let proc
10+
let sandbox
11+
let cwd
12+
let app
13+
let env
14+
15+
before(async () => {
16+
sandbox = await createSandbox(['express', 'winston'])
17+
cwd = sandbox.folder
18+
app = path.join(cwd, 'log_injection/index.js')
19+
})
20+
21+
after(async () => {
22+
await sandbox.remove()
23+
})
24+
25+
beforeEach(async () => {
26+
agent = await new FakeAgent().start()
27+
})
28+
29+
describe('log injection with rule based sampling', () => {
30+
beforeEach(async () => {
31+
agent = await new FakeAgent().start()
32+
})
33+
34+
afterEach(async () => {
35+
proc.kill()
36+
await agent.stop()
37+
})
38+
39+
it('should correctly apply rule based sampling when log injection is enabled', async () => {
40+
env = {
41+
AGENT_PORT: agent.port,
42+
lOG_INJECTION: 'true'
43+
}
44+
proc = await spawnProc(app, { cwd, env, execArgv: [] })
45+
const url = proc.url + '/sampled'
46+
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
47+
// Bug: previously got USER_REJECT instead of USER_KEEP when log injection is enabled,
48+
// meaning resource rules are not applied & instead global sampling is applied
49+
// Now gets USER_KEEP because resource rules are applied
50+
assertObjectContains(payload, [[{ metrics: { _sampling_priority_v1: USER_KEEP } }]])
51+
}, 20000, 1)
52+
})
53+
54+
it('should correctly apply rule based sampling when log injection is disabled', async () => {
55+
env = {
56+
AGENT_PORT: agent.port,
57+
lOG_INJECTION: 'false'
58+
}
59+
proc = await spawnProc(app, { cwd, env, execArgv: [] })
60+
const url = proc.url + '/sampled'
61+
return curlAndAssertMessage(agent, url, ({ headers, payload }) => {
62+
assertObjectContains(payload, [[{ metrics: { _sampling_priority_v1: USER_KEEP } }]])
63+
}, 20000, 1)
64+
})
65+
})
66+
})
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict'
2+
3+
const options = {
4+
service: 'test-service',
5+
sampleRate: 0.0,
6+
samplingRules: [
7+
{
8+
resource: 'GET /sampled',
9+
sampleRate: 1.0
10+
}
11+
]
12+
}
13+
14+
if (process.env.AGENT_PORT) {
15+
options.port = process.env.AGENT_PORT
16+
}
17+
18+
if (process.env.lOG_INJECTION) {
19+
options.logInjection = process.env.lOG_INJECTION
20+
}
21+
22+
const tracer = require('dd-trace')
23+
tracer.init(options)
24+
25+
const express = require('express')
26+
const winston = require('winston')
27+
28+
const app = express()
29+
30+
// Create winston logger
31+
const logger = winston.createLogger({
32+
level: 'info',
33+
format: winston.format.json(),
34+
transports: [
35+
new winston.transports.Console({ silent: true })
36+
]
37+
})
38+
39+
// Route WITH logging (demonstrates the bug)
40+
app.get('/sampled', (req, res) => {
41+
// BUG: This winston.info() triggers log injection BEFORE resource.name is set
42+
// which causes sampling decision to happen too early, bypassing the resource rule
43+
logger.info('Processing GET /sampled request')
44+
res.json({ message: 'logged request' })
45+
})
46+
47+
const server = app.listen(0, () => {
48+
const port = server.address().port
49+
process.send({ port })
50+
})

packages/dd-trace/src/opentracing/tracer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class DatadogTracer {
8686
}
8787

8888
try {
89-
if (format !== 'text_map_dsm') {
89+
if (format !== 'text_map_dsm' && format !== formats.LOG) {
9090
this._prioritySampler.sample(context)
9191
}
9292
this._propagators[format].inject(context, carrier)

packages/dd-trace/test/opentracing/tracer.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ require('../setup/tap')
55
const opentracing = require('opentracing')
66
const os = require('os')
77
const SpanContext = require('../../src/opentracing/span_context')
8+
const formats = require('../../../../ext/formats')
89
const Reference = opentracing.Reference
910

1011
describe('Tracer', () => {
@@ -25,6 +26,7 @@ describe('Tracer', () => {
2526
let TextMapPropagator
2627
let HttpPropagator
2728
let BinaryPropagator
29+
let LogPropagator
2830
let propagator
2931
let config
3032
let log
@@ -58,6 +60,7 @@ describe('Tracer', () => {
5860
TextMapPropagator = sinon.stub()
5961
HttpPropagator = sinon.stub()
6062
BinaryPropagator = sinon.stub()
63+
LogPropagator = sinon.stub()
6164
propagator = {
6265
inject: sinon.stub(),
6366
extract: sinon.stub()
@@ -90,6 +93,7 @@ describe('Tracer', () => {
9093
'./propagation/text_map': TextMapPropagator,
9194
'./propagation/http': HttpPropagator,
9295
'./propagation/binary': BinaryPropagator,
96+
'./propagation/log': LogPropagator,
9397
'../log': log,
9498
'../exporter': exporter
9599
})
@@ -368,6 +372,16 @@ describe('Tracer', () => {
368372

369373
expect(prioritySampler.sample).to.have.been.calledWith(spanContext)
370374
})
375+
376+
it('should not generate sampling priority for log injection', () => {
377+
LogPropagator.returns(propagator)
378+
379+
tracer = new Tracer(config)
380+
tracer.inject(spanContext, formats.LOG, carrier)
381+
382+
expect(prioritySampler.sample).to.not.have.been.called
383+
expect(propagator.inject).to.have.been.calledWith(spanContext, carrier)
384+
})
371385
})
372386

373387
describe('extract', () => {

0 commit comments

Comments
 (0)