Skip to content

Commit 77501a1

Browse files
jbertranStephen Belanger
authored andcommitted
add peer service remapping capability (#3320)
Supplying a `DD_TRACE_PEER_SERVICE_MAPPING` allows users to modify the `peer.service` tag in the same manner that `DD_SERVICE_MAPPING` does for service name. If the `peer.service` value was matched by the mapping, the original value of the tag before remapping is reported in `_dd.peer.service.remapped_from`.
1 parent 287e7d8 commit 77501a1

File tree

6 files changed

+144
-13
lines changed

6 files changed

+144
-13
lines changed

packages/dd-trace/src/config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,12 @@ class Config {
320320
const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
321321
process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
322322
)
323+
const DD_TRACE_PEER_SERVICE_MAPPING = coalesce(
324+
options.peerServiceMapping,
325+
process.env.DD_TRACE_PEER_SERVICE_MAPPING ? fromEntries(
326+
process.env.DD_TRACE_PEER_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
327+
) : {}
328+
)
323329
const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
324330

325331
const DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED = coalesce(
@@ -561,6 +567,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
561567
: true
562568
)
563569
this.traceRemoveIntegrationServiceNamesEnabled = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
570+
this.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
564571
this.lookup = options.lookup
565572
this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
566573
// Disabled for CI Visibility's agentless

packages/dd-trace/src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ module.exports = {
2828
CLIENT_PORT_KEY: 'network.destination.port',
2929
PEER_SERVICE_KEY: 'peer.service',
3030
PEER_SERVICE_SOURCE_KEY: '_dd.peer.service.source',
31+
PEER_SERVICE_REMAP_KEY: '_dd.peer.service.remapped_from',
3132
SCI_REPOSITORY_URL: '_dd.git.repository_url',
3233
SCI_COMMIT_SHA: '_dd.git.commit.sha'
3334
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class DatadogTracer {
2727
this._env = config.env
2828
this._tags = config.tags
2929
this._computePeerService = config.spanComputePeerService
30+
this._peerServiceMapping = config.peerServiceMapping
3031
this._logInjection = config.logInjection
3132
this._debug = config.debug
3233
this._prioritySampler = new PrioritySampler(config.env, config.sampler)

packages/dd-trace/src/plugins/outbound.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
const {
44
CLIENT_PORT_KEY,
55
PEER_SERVICE_KEY,
6-
PEER_SERVICE_SOURCE_KEY
6+
PEER_SERVICE_SOURCE_KEY,
7+
PEER_SERVICE_REMAP_KEY
78
} = require('../constants')
89
const TracingPlugin = require('./tracing')
910

@@ -34,9 +35,11 @@ class OutboundPlugin extends TracingPlugin {
3435
* - If `peer.service` was defined _before_ we compute it (for example in custom instrumentation),
3536
* `_dd.peer.service.source`'s value is `peer.service`
3637
*/
37-
38-
if (tags['peer.service'] !== undefined) {
39-
return { [PEER_SERVICE_SOURCE_KEY]: 'peer.service' }
38+
if (tags[PEER_SERVICE_KEY] !== undefined) {
39+
return {
40+
[PEER_SERVICE_KEY]: tags[PEER_SERVICE_KEY],
41+
[PEER_SERVICE_SOURCE_KEY]: PEER_SERVICE_KEY
42+
}
4043
}
4144

4245
const sourceTags = [
@@ -52,25 +55,35 @@ class OutboundPlugin extends TracingPlugin {
5255
}
5356
}
5457
}
55-
return {}
58+
return undefined
5659
}
5760

58-
startSpan (name, options) {
59-
const span = super.startSpan(name, options)
60-
return span
61+
getPeerServiceRemap (peerData) {
62+
/**
63+
* If DD_TRACE_PEER_SERVICE_MAPPING is matched, we need to override the existing
64+
* peer service and add the value we overrode.
65+
*/
66+
const peerService = peerData[PEER_SERVICE_KEY]
67+
if (peerService && this.tracer._peerServiceMapping[peerService]) {
68+
return {
69+
...peerData,
70+
[PEER_SERVICE_KEY]: this.tracer._peerServiceMapping[peerService],
71+
[PEER_SERVICE_REMAP_KEY]: peerService
72+
}
73+
}
74+
return peerData
6175
}
6276

6377
finish () {
64-
const span = this.activeSpan
65-
this.tagPeerService(span)
78+
this.tagPeerService(this.activeSpan)
6679
super.finish(...arguments)
6780
}
6881

6982
tagPeerService (span) {
7083
if (this.tracer._computePeerService) {
7184
const peerData = this.getPeerService(span.context()._tags)
72-
if (peerData) {
73-
span.addTags(peerData)
85+
if (peerData !== undefined) {
86+
span.addTags(this.getPeerServiceRemap(peerData))
7487
}
7588
}
7689
}

packages/dd-trace/test/config.spec.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ describe('Config', () => {
165165
process.env.DD_TRACE_AGENT_PROTOCOL_VERSION = '0.5'
166166
process.env.DD_SERVICE = 'service'
167167
process.env.DD_SERVICE_MAPPING = 'a:aa, b:bb'
168+
process.env.DD_TRACE_PEER_SERVICE_MAPPING = 'c:cc, d:dd'
168169
process.env.DD_VERSION = '1.0.0'
169170
process.env.DD_TRACE_CLIENT_IP_ENABLED = 'true'
170171
process.env.DD_TRACE_CLIENT_IP_HEADER = 'x-true-client-ip'
@@ -258,6 +259,10 @@ describe('Config', () => {
258259
a: 'aa',
259260
b: 'bb'
260261
})
262+
expect(config).to.have.deep.property('peerServiceMapping', {
263+
c: 'cc',
264+
d: 'dd'
265+
})
261266
expect(config).to.have.nested.deep.property('tracePropagationStyle.inject', ['b3', 'tracecontext'])
262267
expect(config).to.have.nested.deep.property('tracePropagationStyle.extract', ['b3', 'tracecontext'])
263268
expect(config).to.have.nested.property('experimental.runtimeId', true)
@@ -560,6 +565,7 @@ describe('Config', () => {
560565
process.env.DD_TRACE_PARTIAL_FLUSH_MIN_SPANS = 2000
561566
process.env.DD_SERVICE = 'service'
562567
process.env.DD_SERVICE_MAPPING = 'a:aa'
568+
process.env.DD_TRACE_PEER_SERVICE_MAPPING = 'c:cc'
563569
process.env.DD_VERSION = '0.0.0'
564570
process.env.DD_RUNTIME_METRICS_ENABLED = 'true'
565571
process.env.DD_TRACE_REPORT_HOSTNAME = 'true'
@@ -614,6 +620,9 @@ describe('Config', () => {
614620
serviceMapping: {
615621
b: 'bb'
616622
},
623+
peerServiceMapping: {
624+
d: 'dd'
625+
},
617626
tracePropagationStyle: {
618627
inject: [],
619628
extract: []
@@ -668,6 +677,7 @@ describe('Config', () => {
668677
expect(config.tags).to.include({ foo: 'foo', baz: 'qux' })
669678
expect(config.tags).to.include({ service: 'test', version: '1.0.0', env: 'development' })
670679
expect(config).to.have.deep.property('serviceMapping', { b: 'bb' })
680+
expect(config).to.have.deep.property('peerServiceMapping', { d: 'dd' })
671681
expect(config).to.have.nested.deep.property('tracePropagationStyle.inject', [])
672682
expect(config).to.have.nested.deep.property('tracePropagationStyle.extract', [])
673683
expect(config).to.have.nested.property('experimental.runtimeId', false)

packages/dd-trace/test/plugins/outbound.spec.js

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,54 @@
22

33
require('../setup/tap')
44

5+
const { expect } = require('chai')
56
const OutboundPlugin = require('../../src/plugins/outbound')
67

78
describe('OuboundPlugin', () => {
9+
describe('peer service decision', () => {
10+
let instance = null
11+
let computePeerServiceStub = null
12+
let getPeerServiceStub = null
13+
let getRemapStub = null
14+
15+
beforeEach(() => {
16+
instance = new OutboundPlugin()
17+
computePeerServiceStub = sinon.stub(instance, 'tracer')
18+
getPeerServiceStub = sinon.stub(instance, 'getPeerService')
19+
getRemapStub = sinon.stub(instance, 'getPeerServiceRemap')
20+
})
21+
22+
afterEach(() => {
23+
computePeerServiceStub.restore()
24+
getPeerServiceStub.restore()
25+
getRemapStub.restore()
26+
})
27+
28+
it('should attempt to remap when we found peer service', () => {
29+
computePeerServiceStub.value({ _computePeerService: true })
30+
getPeerServiceStub.returns({ foo: 'bar' })
31+
instance.tagPeerService({ context: () => { return { _tags: {} } }, addTags: () => {} })
32+
33+
expect(getPeerServiceStub).to.be.called
34+
expect(getRemapStub).to.be.called
35+
})
36+
37+
it('should not attempt to remap if we found no peer service', () => {
38+
computePeerServiceStub.value({ _computePeerService: true })
39+
getPeerServiceStub.returns(undefined)
40+
instance.tagPeerService({ context: () => { return { _tags: {} } }, addTags: () => {} })
41+
42+
expect(getPeerServiceStub).to.be.called
43+
expect(getRemapStub).to.not.be.called
44+
})
45+
46+
it('should do nothing when disabled', () => {
47+
computePeerServiceStub.value({ _computePeerService: false })
48+
instance.tagPeerService({ context: () => { return { _tags: {} } }, addTags: () => {} })
49+
expect(getPeerServiceStub).to.not.be.called
50+
expect(getRemapStub).to.not.be.called
51+
})
52+
})
853
describe('peer.service computation', () => {
954
let instance = null
1055

@@ -16,7 +61,7 @@ describe('OuboundPlugin', () => {
1661
const res = instance.getPeerService({
1762
fooIsNotAPrecursor: 'bar'
1863
})
19-
expect(res).to.deep.equal({})
64+
expect(res).to.equal(undefined)
2065
})
2166

2267
it('should grab from remote host in datadog format', () => {
@@ -56,4 +101,58 @@ describe('OuboundPlugin', () => {
56101
})
57102
})
58103
})
104+
describe('remapping computation', () => {
105+
let instance = null
106+
let mappingStub = null
107+
const peerData = {
108+
'peer.service': 'foosvc',
109+
'_dd.peer.service.source': 'out.host'
110+
}
111+
112+
beforeEach(() => {
113+
instance = new OutboundPlugin()
114+
})
115+
116+
afterEach(() => {
117+
mappingStub.restore()
118+
})
119+
120+
it('should return peer data unchanged if there is no peer service', () => {
121+
const mappingData = instance.getPeerServiceRemap({ 'foo': 'bar' })
122+
mappingStub = sinon.stub(instance, 'tracer')
123+
expect(mappingData).to.deep.equal({ 'foo': 'bar' })
124+
})
125+
126+
it('should return peer data unchanged if no mapping is available', () => {
127+
mappingStub = sinon.stub(instance, 'tracer').value({ _peerServiceMapping: {} })
128+
const mappingData = instance.getPeerServiceRemap(peerData)
129+
expect(mappingData).to.deep.equal(peerData)
130+
})
131+
132+
it('should return peer data unchanged if no mapping item matches', () => {
133+
mappingStub = sinon.stub(instance, 'tracer').value({
134+
_peerServiceMapping: {
135+
barsvc: 'bar',
136+
bazsvc: 'baz'
137+
}
138+
})
139+
const mappingData = instance.getPeerServiceRemap(peerData)
140+
expect(mappingData).to.deep.equal(peerData)
141+
})
142+
143+
it('should remap if a mapping item matches', () => {
144+
mappingStub = sinon.stub(instance, 'tracer').value({
145+
_peerServiceMapping: {
146+
foosvc: 'foo',
147+
bazsvc: 'baz'
148+
}
149+
})
150+
const mappingData = instance.getPeerServiceRemap(peerData)
151+
expect(mappingData).to.deep.equal({
152+
'peer.service': 'foo',
153+
'_dd.peer.service.source': 'out.host',
154+
'_dd.peer.service.remapped_from': 'foosvc'
155+
})
156+
})
157+
})
59158
})

0 commit comments

Comments
 (0)