Skip to content

Commit 2c5e17c

Browse files
authored
dbm: tedious (sql server) service mode (#5375)
1 parent c5e5f8c commit 2c5e17c

File tree

4 files changed

+96
-31
lines changed

4 files changed

+96
-31
lines changed

packages/datadog-instrumentations/src/tedious.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ addHook({ name: 'tedious', versions: ['>=1.0.0'] }, tedious => {
1616
return makeRequest.apply(this, arguments)
1717
}
1818

19-
const queryOrProcedure = getQueryOrProcedure(request)
19+
const [queryOrProcedure, queryParent, queryField] = getQueryOrProcedure(request)
2020

2121
if (!queryOrProcedure) {
2222
return makeRequest.apply(this, arguments)
@@ -28,7 +28,9 @@ addHook({ name: 'tedious', versions: ['>=1.0.0'] }, tedious => {
2828
const connectionConfig = this.config
2929

3030
return asyncResource.runInAsyncScope(() => {
31-
startCh.publish({ queryOrProcedure, connectionConfig })
31+
const payload = { queryOrProcedure, connectionConfig }
32+
startCh.publish(payload)
33+
queryParent[queryField] = payload.sql
3234

3335
const cb = callbackResource.bind(request.callback, request)
3436
request.callback = asyncResource.bind(function (error) {
@@ -53,14 +55,15 @@ addHook({ name: 'tedious', versions: ['>=1.0.0'] }, tedious => {
5355
return tedious
5456
})
5557

58+
// returns [queryOrProcedure, parentObjectToSet, propertyNameToSet]
5659
function getQueryOrProcedure (request) {
57-
if (!request.parameters) return
58-
59-
const statement = request.parametersByName.statement || request.parametersByName.stmt
60-
61-
if (!statement) {
62-
return request.sqlTextOrProcedure
60+
if (!request.parameters) return [null]
61+
62+
if (request.parametersByName.statement) {
63+
return [request.parametersByName.statement.value, request.parametersByName.statement, 'value']
64+
} else if (request.parametersByName.stmt) {
65+
return [request.parametersByName.stmt.value, request.parametersByName.stmt, 'value']
66+
} else {
67+
return [request.sqlTextOrProcedure, request, 'sqlTextOrProcedure']
6368
}
64-
65-
return statement.value
6669
}

packages/datadog-plugin-tedious/src/index.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ class TediousPlugin extends DatabasePlugin {
88
static get operation () { return 'request' } // TODO: change to match other database plugins
99
static get system () { return 'mssql' }
1010

11-
start ({ queryOrProcedure, connectionConfig }) {
12-
this.startSpan(this.operationName(), {
13-
service: this.serviceName({ pluginConfig: this.config, system: this.system }),
14-
resource: queryOrProcedure,
11+
start (payload) {
12+
const service = this.serviceName({ pluginConfig: this.config, system: this.system })
13+
const span = this.startSpan(this.operationName(), {
14+
service,
15+
resource: payload.queryOrProcedure,
1516
type: 'sql',
1617
kind: 'client',
1718
meta: {
1819
'db.type': 'mssql',
1920
component: 'tedious',
20-
'out.host': connectionConfig.server,
21-
[CLIENT_PORT_KEY]: connectionConfig.options.port,
22-
'db.user': connectionConfig.userName || connectionConfig.authentication.options.userName,
23-
'db.name': connectionConfig.options.database,
24-
'db.instance': connectionConfig.options.instanceName
21+
'out.host': payload.connectionConfig.server,
22+
[CLIENT_PORT_KEY]: payload.connectionConfig.options.port,
23+
'db.user': payload.connectionConfig.userName || payload.connectionConfig.authentication.options.userName,
24+
'db.name': payload.connectionConfig.options.database,
25+
'db.instance': payload.connectionConfig.options.instanceName
2526
}
2627
})
28+
29+
// SQL Server includes comments when caching queries
30+
// For that reason we allow service mode but not full mode
31+
payload.sql = this.injectDbmQuery(span, payload.queryOrProcedure, service, true)
2732
}
2833
}
2934

packages/datadog-plugin-tedious/test/index.spec.js

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ describe('Plugin', () => {
1212
let tds
1313
let tracer
1414
let connection
15-
let connectionIsClosed
1615

1716
withVersions('tedious', 'tedious', version => {
1817
beforeEach(() => {
@@ -53,7 +52,6 @@ describe('Plugin', () => {
5352
config.password = MSSQL_PASSWORD
5453
}
5554

56-
connectionIsClosed = false
5755
connection = new tds.Connection(config)
5856
.on('connect', done)
5957

@@ -64,12 +62,8 @@ describe('Plugin', () => {
6462
})
6563

6664
afterEach(function (done) {
67-
if (connectionIsClosed) {
68-
done()
69-
} else {
70-
connection.on('end', () => done())
71-
connection.close()
72-
}
65+
connection.on('end', () => done())
66+
connection.close()
7367
})
7468

7569
withNamingSchema(
@@ -405,5 +399,68 @@ describe('Plugin', () => {
405399
})
406400
}
407401
})
402+
403+
// it's a pretty old version with a different enough API that I don't think it's worth supporting
404+
const testDbm = semver.intersects(version, '<10') ? describe.skip : describe
405+
testDbm('with configuration and DBM enabled', () => {
406+
let config
407+
let tds
408+
let connection
409+
410+
beforeEach(() => {
411+
return agent.load('tedious', { dbmPropagationMode: 'service', service: 'custom' }).then(() => {
412+
tds = require(`../../../versions/tedious@${version}`).get()
413+
})
414+
})
415+
416+
afterEach(() => {
417+
return agent.close({ ritmReset: false })
418+
})
419+
420+
beforeEach((done) => {
421+
config = {
422+
server: 'localhost',
423+
options: {
424+
database: 'master',
425+
trustServerCertificate: true
426+
},
427+
authentication: {
428+
options: {
429+
userName: MSSQL_USERNAME,
430+
password: MSSQL_PASSWORD
431+
},
432+
type: 'default'
433+
}
434+
}
435+
436+
connection = new tds.Connection(config)
437+
.on('connect', done)
438+
439+
connection.connect()
440+
})
441+
442+
afterEach(function (done) {
443+
connection.on('end', () => done())
444+
connection.close()
445+
})
446+
447+
it('should inject the correct DBM comment into query but not into trace', done => {
448+
const query = 'SELECT 1 + 1 AS solution'
449+
450+
const request = new tds.Request(query, (err) => {
451+
if (err) return done(err)
452+
promise.then(done, done)
453+
})
454+
455+
const promise = agent
456+
.use(traces => {
457+
expect(traces[0][0]).to.have.property('resource', 'SELECT 1 + 1 AS solution')
458+
expect(request.sqlTextOrProcedure).to.equal("/*dddb='master',dddbs='custom',dde='tester'," +
459+
"ddh='localhost',ddps='test',ddpv='10.8.2'*/ SELECT 1 + 1 AS solution")
460+
})
461+
462+
connection.execSql(request)
463+
})
464+
})
408465
})
409466
})

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class DatabasePlugin extends StoragePlugin {
6363
return tracerService
6464
}
6565

66-
createDbmComment (span, serviceName, isPreparedStatement = false) {
66+
createDbmComment (span, serviceName, disableFullMode = false) {
6767
const mode = this.config.dbmPropagationMode
6868
const dbmService = this.getDbmServiceName(span, serviceName)
6969

@@ -73,7 +73,7 @@ class DatabasePlugin extends StoragePlugin {
7373

7474
const servicePropagation = this.createDBMPropagationCommentService(dbmService, span)
7575

76-
if (isPreparedStatement || mode === 'service') {
76+
if (disableFullMode || mode === 'service') {
7777
return servicePropagation
7878
} else if (mode === 'full') {
7979
span.setTag('_dd.dbm_trace_injected', 'true')
@@ -82,8 +82,8 @@ class DatabasePlugin extends StoragePlugin {
8282
}
8383
}
8484

85-
injectDbmQuery (span, query, serviceName, isPreparedStatement = false) {
86-
const dbmTraceComment = this.createDbmComment(span, serviceName, isPreparedStatement)
85+
injectDbmQuery (span, query, serviceName, disableFullMode = false) {
86+
const dbmTraceComment = this.createDbmComment(span, serviceName, disableFullMode)
8787

8888
if (!dbmTraceComment) {
8989
return query

0 commit comments

Comments
 (0)