Skip to content

Commit c273f1d

Browse files
jbertranuurien
authored andcommitted
Make HTTP clients fit in the plugin hierarchy (#3178)
* move http client to clientPlugin * move http2 client to clientPlugin
1 parent 73e6979 commit c273f1d

File tree

2 files changed

+120
-115
lines changed

2 files changed

+120
-115
lines changed

packages/datadog-plugin-http/src/client.js

Lines changed: 70 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const Plugin = require('../../dd-trace/src/plugins/plugin')
3+
const ClientPlugin = require('../../dd-trace/src/plugins/client')
44
const { storage } = require('../../datadog-core')
55
const tags = require('../../../ext/tags')
66
const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
@@ -9,97 +9,99 @@ const HTTP_HEADERS = formats.HTTP_HEADERS
99
const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
1010
const log = require('../../dd-trace/src/log')
1111
const url = require('url')
12-
const { COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
12+
const { CLIENT_PORT_KEY, COMPONENT, ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
1313

1414
const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE
1515
const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
1616
const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS
1717

18-
class HttpClientPlugin extends Plugin {
18+
class HttpClientPlugin extends ClientPlugin {
1919
static get id () {
2020
return 'http'
2121
}
2222

23-
constructor (...args) {
24-
super(...args)
25-
26-
this.addSub('apm:http:client:request:start', ({ args, http }) => {
27-
const store = storage.getStore()
28-
const options = args.options
29-
const agent = options.agent || options._defaultAgent || http.globalAgent
30-
const protocol = options.protocol || agent.protocol || 'http:'
31-
const hostname = options.hostname || options.host || 'localhost'
32-
const host = options.port ? `${hostname}:${options.port}` : hostname
33-
const path = options.path ? options.path.split(/[?#]/)[0] : '/'
34-
const uri = `${protocol}//${host}${path}`
35-
const allowed = this.config.filter(uri)
36-
37-
const method = (options.method || 'GET').toUpperCase()
38-
const childOf = store && allowed ? store.span : null
39-
const span = this.tracer.startSpan('http.request', {
40-
childOf,
41-
tags: {
42-
[COMPONENT]: this.constructor.id,
43-
'span.kind': 'client',
44-
'service.name': getServiceName(this.tracer, this.config, options),
45-
'resource.name': method,
46-
'span.type': 'http',
47-
'http.method': method,
48-
'http.url': uri,
49-
'out.host': hostname
50-
}
51-
})
23+
addTraceSub (eventName, handler) {
24+
this.addSub(`apm:${this.constructor.id}:client:${this.operation}:${eventName}`, handler)
25+
}
5226

53-
// TODO: Figure out a better way to do this for any span.
54-
if (!allowed) {
55-
span._spanContext._trace.record = false
27+
start ({ args, http }) {
28+
const store = storage.getStore()
29+
const options = args.options
30+
const agent = options.agent || options._defaultAgent || http.globalAgent
31+
const protocol = options.protocol || agent.protocol || 'http:'
32+
const hostname = options.hostname || options.host || 'localhost'
33+
const host = options.port ? `${hostname}:${options.port}` : hostname
34+
const path = options.path ? options.path.split(/[?#]/)[0] : '/'
35+
const uri = `${protocol}//${host}${path}`
36+
const allowed = this.config.filter(uri)
37+
38+
const method = (options.method || 'GET').toUpperCase()
39+
const childOf = store && allowed ? store.span : null
40+
// TODO delegate to super.startspan
41+
const span = this.startSpan('http.request', {
42+
childOf,
43+
meta: {
44+
[COMPONENT]: this.constructor.id,
45+
'span.kind': 'client',
46+
'service.name': getServiceName(this.tracer, this.config, options),
47+
'resource.name': method,
48+
'span.type': 'http',
49+
'http.method': method,
50+
'http.url': uri,
51+
'out.host': hostname
52+
},
53+
metrics: {
54+
[CLIENT_PORT_KEY]: parseInt(options.port)
5655
}
56+
})
5757

58-
if (!(hasAmazonSignature(options) || !this.config.propagationFilter(uri))) {
59-
this.tracer.inject(span, HTTP_HEADERS, options.headers)
60-
}
58+
// TODO: Figure out a better way to do this for any span.
59+
if (!allowed) {
60+
span._spanContext._trace.record = false
61+
}
6162

62-
analyticsSampler.sample(span, this.config.measured)
63-
this.enter(span, store)
64-
})
63+
if (!(hasAmazonSignature(options) || !this.config.propagationFilter(uri))) {
64+
this.tracer.inject(span, HTTP_HEADERS, options.headers)
65+
}
6566

66-
this.addSub('apm:http:client:request:finish', ({ req, res }) => {
67-
const span = storage.getStore().span
68-
if (res) {
69-
span.setTag(HTTP_STATUS_CODE, res.statusCode)
67+
analyticsSampler.sample(span, this.config.measured)
68+
this.enter(span, store)
69+
}
7070

71-
if (!this.config.validateStatus(res.statusCode)) {
72-
span.setTag('error', 1)
73-
}
71+
finish ({ req, res }) {
72+
const span = storage.getStore().span
73+
if (res) {
74+
span.setTag(HTTP_STATUS_CODE, res.statusCode)
7475

75-
addResponseHeaders(res, span, this.config)
76+
if (!this.config.validateStatus(res.statusCode)) {
77+
span.setTag('error', 1)
7678
}
7779

78-
addRequestHeaders(req, span, this.config)
80+
addResponseHeaders(res, span, this.config)
81+
}
7982

80-
this.config.hooks.request(span, req, res)
81-
span.finish()
82-
})
83+
addRequestHeaders(req, span, this.config)
8384

84-
this.addSub('apm:http:client:request:error', errorHandler)
85+
this.config.hooks.request(span, req, res)
86+
span.finish()
8587
}
8688

87-
configure (config) {
88-
return super.configure(normalizeClientConfig(config))
89-
}
90-
}
89+
error (err) {
90+
const span = storage.getStore().span
9191

92-
function errorHandler (err) {
93-
const span = storage.getStore().span
92+
if (err) {
93+
span.addTags({
94+
[ERROR_TYPE]: err.name,
95+
[ERROR_MESSAGE]: err.message || err.code,
96+
[ERROR_STACK]: err.stack
97+
})
98+
} else {
99+
span.setTag('error', 1)
100+
}
101+
}
94102

95-
if (err) {
96-
span.addTags({
97-
[ERROR_TYPE]: err.name,
98-
[ERROR_MESSAGE]: err.message || err.code,
99-
[ERROR_STACK]: err.stack
100-
})
101-
} else {
102-
span.setTag('error', 1)
103+
configure (config) {
104+
return super.configure(normalizeClientConfig(config))
103105
}
104106
}
105107

packages/datadog-plugin-http2/src/client.js

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
const { storage } = require('../../datadog-core')
4-
const Plugin = require('../../dd-trace/src/plugins/plugin')
4+
const ClientPlugin = require('../../dd-trace/src/plugins/client')
55

66
const URL = require('url').URL
77
const log = require('../../dd-trace/src/log')
@@ -24,55 +24,14 @@ const HTTP2_HEADER_PATH = ':path'
2424
const HTTP2_HEADER_STATUS = ':status'
2525
const HTTP2_METHOD_GET = 'GET'
2626

27-
class Http2ClientPlugin extends Plugin {
27+
class Http2ClientPlugin extends ClientPlugin {
2828
static get id () {
2929
return 'http2'
3030
}
3131

3232
constructor (...args) {
3333
super(...args)
3434

35-
this.addSub('apm:http2:client:request:start', ({ authority, options, headers = {} }) => {
36-
const sessionDetails = extractSessionDetails(authority, options)
37-
const path = headers[HTTP2_HEADER_PATH] || '/'
38-
const pathname = path.split(/[?#]/)[0]
39-
const method = headers[HTTP2_HEADER_METHOD] || HTTP2_METHOD_GET
40-
const uri = `${sessionDetails.protocol}//${sessionDetails.host}:${sessionDetails.port}${pathname}`
41-
const allowed = this.config.filter(uri)
42-
43-
const store = storage.getStore()
44-
const childOf = store && allowed ? store.span : null
45-
const span = this.tracer.startSpan('http.request', {
46-
childOf,
47-
tags: {
48-
[COMPONENT]: this.constructor.id,
49-
[CLIENT_PORT_KEY]: parseInt(sessionDetails.port),
50-
[SPAN_KIND]: CLIENT,
51-
'service.name': getServiceName(this.tracer, this.config, sessionDetails),
52-
'resource.name': method,
53-
'span.type': 'http',
54-
'http.method': method,
55-
'http.url': uri,
56-
'out.host': sessionDetails.host
57-
}
58-
})
59-
60-
// TODO: Figure out a better way to do this for any span.
61-
if (!allowed) {
62-
span._spanContext._trace.record = false
63-
}
64-
65-
addHeaderTags(span, headers, HTTP_REQUEST_HEADERS, this.config)
66-
67-
if (!hasAmazonSignature(headers, path)) {
68-
this.tracer.inject(span, HTTP_HEADERS, headers)
69-
}
70-
71-
analyticsSampler.sample(span, this.config.measured)
72-
73-
this.enter(span, store)
74-
})
75-
7635
this.addSub('apm:http2:client:response', (headers) => {
7736
const span = storage.getStore().span
7837
const status = headers && headers[HTTP2_HEADER_STATUS]
@@ -85,14 +44,58 @@ class Http2ClientPlugin extends Plugin {
8544

8645
addHeaderTags(span, headers, HTTP_RESPONSE_HEADERS, this.config)
8746
})
47+
}
8848

89-
this.addSub('apm:http2:client:request:finish', () => {
90-
const span = storage.getStore().span
49+
addTraceSub (eventName, handler) {
50+
this.addSub(`apm:${this.constructor.id}:client:${this.operation}:${eventName}`, handler)
51+
}
9152

92-
span.finish()
53+
start ({ authority, options, headers = {} }) {
54+
const sessionDetails = extractSessionDetails(authority, options)
55+
const path = headers[HTTP2_HEADER_PATH] || '/'
56+
const pathname = path.split(/[?#]/)[0]
57+
const method = headers[HTTP2_HEADER_METHOD] || HTTP2_METHOD_GET
58+
const uri = `${sessionDetails.protocol}//${sessionDetails.host}:${sessionDetails.port}${pathname}`
59+
const allowed = this.config.filter(uri)
60+
61+
const store = storage.getStore()
62+
const childOf = store && allowed ? store.span : null
63+
const span = this.startSpan('http.request', {
64+
childOf,
65+
meta: {
66+
[COMPONENT]: this.constructor.id,
67+
[SPAN_KIND]: CLIENT,
68+
'service.name': getServiceName(this.tracer, this.config, sessionDetails),
69+
'resource.name': method,
70+
'span.type': 'http',
71+
'http.method': method,
72+
'http.url': uri,
73+
'out.host': sessionDetails.host
74+
},
75+
metrics: {
76+
[CLIENT_PORT_KEY]: parseInt(sessionDetails.port)
77+
}
9378
})
9479

95-
this.addSub('apm:http2:client:request:error', this.addError)
80+
// TODO: Figure out a better way to do this for any span.
81+
if (!allowed) {
82+
span._spanContext._trace.record = false
83+
}
84+
85+
addHeaderTags(span, headers, HTTP_REQUEST_HEADERS, this.config)
86+
87+
if (!hasAmazonSignature(headers, path)) {
88+
this.tracer.inject(span, HTTP_HEADERS, headers)
89+
}
90+
91+
analyticsSampler.sample(span, this.config.measured)
92+
93+
this.enter(span, store)
94+
}
95+
96+
finish () {
97+
const span = storage.getStore().span
98+
span.finish()
9699
}
97100

98101
configure (config) {

0 commit comments

Comments
 (0)