dd-trace 2.22.0 → 2.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +32 -32
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/connect.js +15 -15
- package/packages/datadog-instrumentations/src/http/server.js +11 -12
- package/packages/datadog-instrumentations/src/koa.js +32 -32
- package/packages/datadog-instrumentations/src/restify.js +5 -2
- package/packages/datadog-instrumentations/src/router.js +22 -22
- package/packages/datadog-plugin-http/src/server.js +8 -0
- package/packages/datadog-plugin-router/src/index.js +7 -1
- package/packages/dd-trace/src/plugins/util/web.js +5 -1
- package/packages/dd-trace/src/profiling/config.js +3 -1
- package/packages/dd-trace/src/profiling/index.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +35 -6
package/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
15
15
|
* @param {SpanOptions} [options] Options for the newly created span.
|
|
16
16
|
* @returns {Span} A new Span object.
|
|
17
17
|
*/
|
|
18
|
-
startSpan(name: string, options?: SpanOptions): Span;
|
|
18
|
+
startSpan (name: string, options?: SpanOptions): Span;
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Injects the given SpanContext instance for cross-process propagation
|
|
@@ -27,7 +27,7 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
27
27
|
* @param {string} format The format of the carrier.
|
|
28
28
|
* @param {any} carrier The carrier object.
|
|
29
29
|
*/
|
|
30
|
-
inject(spanContext: SpanContext | Span, format: string, carrier: any): void;
|
|
30
|
+
inject (spanContext: SpanContext | Span, format: string, carrier: any): void;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Returns a SpanContext instance extracted from `carrier` in the given
|
|
@@ -38,31 +38,31 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
38
38
|
* The extracted SpanContext, or null if no such SpanContext could
|
|
39
39
|
* be found in `carrier`
|
|
40
40
|
*/
|
|
41
|
-
extract(format: string, carrier: any): SpanContext | null;
|
|
41
|
+
extract (format: string, carrier: any): SpanContext | null;
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Initializes the tracer. This should be called before importing other libraries.
|
|
45
45
|
*/
|
|
46
|
-
init(options?: TracerOptions): this;
|
|
46
|
+
init (options?: TracerOptions): this;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Sets the URL for the trace agent. This should only be called _after_
|
|
50
50
|
* init() is called, only in cases where the URL needs to be set after
|
|
51
51
|
* initialization.
|
|
52
52
|
*/
|
|
53
|
-
setUrl(url: string): this;
|
|
53
|
+
setUrl (url: string): this;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Enable and optionally configure a plugin.
|
|
57
57
|
* @param plugin The name of a built-in plugin.
|
|
58
58
|
* @param config Configuration options. Can also be `false` to disable the plugin.
|
|
59
59
|
*/
|
|
60
|
-
use<P extends keyof Plugins>(plugin: P, config?: Plugins[P] | boolean): this;
|
|
60
|
+
use<P extends keyof Plugins> (plugin: P, config?: Plugins[P] | boolean): this;
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Returns a reference to the current scope.
|
|
64
64
|
*/
|
|
65
|
-
scope(): Scope;
|
|
65
|
+
scope (): Scope;
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Instruments a function by automatically creating a span activated on its
|
|
@@ -81,8 +81,8 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
81
81
|
* If the `orphanable` option is set to false, the function will not be traced
|
|
82
82
|
* unless there is already an active span or `childOf` option.
|
|
83
83
|
*/
|
|
84
|
-
trace<T>(name: string, fn: (span?: Span, fn?: (error?: Error) => any) => T): T;
|
|
85
|
-
trace<T>(name: string, options: TraceOptions & SpanOptions, fn: (span?: Span, done?: (error?: Error) => string) => T): T;
|
|
84
|
+
trace<T> (name: string, fn: (span?: Span, fn?: (error?: Error) => any) => T): T;
|
|
85
|
+
trace<T> (name: string, options: TraceOptions & SpanOptions, fn: (span?: Span, done?: (error?: Error) => string) => T): T;
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
88
|
* Wrap a function to automatically create a span activated on its
|
|
@@ -98,23 +98,23 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
98
98
|
* * The function doesn't accept a callback and doesn't return a promise, in
|
|
99
99
|
* which case the span will finish at the end of the function execution.
|
|
100
100
|
*/
|
|
101
|
-
wrap<T = (...args: any[]) => any>(name: string, fn: T, requiresParent?: boolean): T;
|
|
102
|
-
wrap<T = (...args: any[]) => any>(name: string, options: TraceOptions & SpanOptions, fn: T): T;
|
|
103
|
-
wrap<T = (...args: any[]) => any>(name: string, options: (...args: any[]) => TraceOptions & SpanOptions, fn: T): T;
|
|
101
|
+
wrap<T = (...args: any[]) => any> (name: string, fn: T, requiresParent?: boolean): T;
|
|
102
|
+
wrap<T = (...args: any[]) => any> (name: string, options: TraceOptions & SpanOptions, fn: T): T;
|
|
103
|
+
wrap<T = (...args: any[]) => any> (name: string, options: (...args: any[]) => TraceOptions & SpanOptions, fn: T): T;
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Create and return a string that can be included in the <head> of a
|
|
107
107
|
* document to enable RUM tracing to include it. The resulting string
|
|
108
108
|
* should not be cached.
|
|
109
109
|
*/
|
|
110
|
-
getRumData(): string;
|
|
110
|
+
getRumData (): string;
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
113
|
* Links an authenticated user to the current trace.
|
|
114
114
|
* @param {User} user Properties of the authenticated user. Accepts custom fields.
|
|
115
115
|
* @returns {Tracer} The Tracer instance for chaining.
|
|
116
116
|
*/
|
|
117
|
-
setUser(user: User): Tracer;
|
|
117
|
+
setUser (user: User): Tracer;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
export declare interface TraceOptions extends Analyzable {
|
|
@@ -144,7 +144,7 @@ export declare interface TraceOptions extends Analyzable {
|
|
|
144
144
|
* have children.
|
|
145
145
|
*/
|
|
146
146
|
export declare interface Span extends opentracing.Span {
|
|
147
|
-
context(): SpanContext;
|
|
147
|
+
context (): SpanContext;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
/**
|
|
@@ -161,17 +161,17 @@ export declare interface SpanContext extends opentracing.SpanContext {
|
|
|
161
161
|
/**
|
|
162
162
|
* Returns the string representation of the internal trace ID.
|
|
163
163
|
*/
|
|
164
|
-
toTraceId(): string;
|
|
164
|
+
toTraceId (): string;
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
167
|
* Returns the string representation of the internal span ID.
|
|
168
168
|
*/
|
|
169
|
-
toSpanId(): string;
|
|
169
|
+
toSpanId (): string;
|
|
170
170
|
|
|
171
171
|
/**
|
|
172
172
|
* Returns the string representation used for DBM integration.
|
|
173
173
|
*/
|
|
174
|
-
toTraceparent(): string;
|
|
174
|
+
toTraceparent (): string;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
/**
|
|
@@ -329,7 +329,7 @@ export declare interface TracerOptions {
|
|
|
329
329
|
* Number of spans before partially exporting a trace. This prevents keeping all the spans in memory for very large traces.
|
|
330
330
|
* @default 1000
|
|
331
331
|
*/
|
|
332
|
-
|
|
332
|
+
flushMinSpans?: number;
|
|
333
333
|
|
|
334
334
|
/**
|
|
335
335
|
* Whether to enable runtime metrics.
|
|
@@ -382,10 +382,10 @@ export declare interface TracerOptions {
|
|
|
382
382
|
runtimeId?: boolean
|
|
383
383
|
|
|
384
384
|
/**
|
|
385
|
-
* Whether to write traces to log output, rather than send to an agent
|
|
385
|
+
* Whether to write traces to log output or agentless, rather than send to an agent
|
|
386
386
|
* @default false
|
|
387
387
|
*/
|
|
388
|
-
exporter?: 'log' | 'agent'
|
|
388
|
+
exporter?: 'log' | 'agent' | 'datadog'
|
|
389
389
|
|
|
390
390
|
/**
|
|
391
391
|
* Whether to enable the experimental `getRumData` method.
|
|
@@ -396,7 +396,7 @@ export declare interface TracerOptions {
|
|
|
396
396
|
/**
|
|
397
397
|
* Configuration of the IAST. Can be a boolean as an alias to `iast.enabled`.
|
|
398
398
|
*/
|
|
399
|
-
iast?: boolean
|
|
399
|
+
iast?: boolean | {
|
|
400
400
|
/**
|
|
401
401
|
* Whether to enable IAST.
|
|
402
402
|
* @default false
|
|
@@ -516,7 +516,7 @@ export declare interface TracerOptions {
|
|
|
516
516
|
/**
|
|
517
517
|
* User object that can be passed to `tracer.setUser()`.
|
|
518
518
|
*/
|
|
519
|
-
|
|
519
|
+
export declare interface User {
|
|
520
520
|
/**
|
|
521
521
|
* Unique identifier of the user.
|
|
522
522
|
* Mandatory.
|
|
@@ -588,7 +588,7 @@ export declare interface Scope {
|
|
|
588
588
|
*
|
|
589
589
|
* @returns {Span} The active span.
|
|
590
590
|
*/
|
|
591
|
-
active(): Span | null;
|
|
591
|
+
active (): Span | null;
|
|
592
592
|
|
|
593
593
|
/**
|
|
594
594
|
* Activate a span in the scope of a function.
|
|
@@ -597,7 +597,7 @@ export declare interface Scope {
|
|
|
597
597
|
* @param {Function} fn Function that will have the span activated on its scope.
|
|
598
598
|
* @returns The return value of the provided function.
|
|
599
599
|
*/
|
|
600
|
-
activate<T>(span: Span, fn: ((...args: any[]) => T)): T;
|
|
600
|
+
activate<T> (span: Span, fn: ((...args: any[]) => T)): T;
|
|
601
601
|
|
|
602
602
|
/**
|
|
603
603
|
* Binds a target to the provided span, or the active span if omitted.
|
|
@@ -606,9 +606,9 @@ export declare interface Scope {
|
|
|
606
606
|
* @param {Span} [span=scope.active()] The span to activate.
|
|
607
607
|
* @returns The bound target.
|
|
608
608
|
*/
|
|
609
|
-
bind<T extends (...args: any[]) => void>(fn: T, span?: Span | null): T;
|
|
610
|
-
bind<V, T extends (...args: any[]) => V>(fn: T, span?: Span | null): T;
|
|
611
|
-
bind<T>(fn: Promise<T>, span?: Span | null): Promise<T>;
|
|
609
|
+
bind<T extends (...args: any[]) => void> (fn: T, span?: Span | null): T;
|
|
610
|
+
bind<V, T extends (...args: any[]) => V> (fn: T, span?: Span | null): T;
|
|
611
|
+
bind<T> (fn: Promise<T>, span?: Span | null): Promise<T>;
|
|
612
612
|
bind(emitter: EventEmitter, span?: Span | null): EventEmitter;
|
|
613
613
|
}
|
|
614
614
|
|
|
@@ -1229,7 +1229,7 @@ declare namespace plugins {
|
|
|
1229
1229
|
* This plugin automatically instruments the
|
|
1230
1230
|
* [mariadb](https://github.com/mariadb-corporation/mariadb-connector-nodejs) module.
|
|
1231
1231
|
*/
|
|
1232
|
-
|
|
1232
|
+
interface mariadb extends mysql {}
|
|
1233
1233
|
|
|
1234
1234
|
/**
|
|
1235
1235
|
* This plugin automatically instruments the
|
|
@@ -1253,7 +1253,7 @@ declare namespace plugins {
|
|
|
1253
1253
|
* This plugin automatically instruments the
|
|
1254
1254
|
* [moleculer](https://moleculer.services/) module.
|
|
1255
1255
|
*/
|
|
1256
|
-
|
|
1256
|
+
interface moleculer extends Moleculer {
|
|
1257
1257
|
/**
|
|
1258
1258
|
* Configuration for Moleculer clients. Set to false to disable client
|
|
1259
1259
|
* instrumentation.
|
|
@@ -1307,7 +1307,7 @@ declare namespace plugins {
|
|
|
1307
1307
|
/**
|
|
1308
1308
|
* Hooks to run before spans are finished.
|
|
1309
1309
|
*/
|
|
1310
|
-
|
|
1310
|
+
hooks?: {
|
|
1311
1311
|
/**
|
|
1312
1312
|
* Hook to execute just before the request span finishes.
|
|
1313
1313
|
*/
|
|
@@ -1336,7 +1336,7 @@ declare namespace plugins {
|
|
|
1336
1336
|
* This plugin automatically instruments the
|
|
1337
1337
|
* [paperplane](https://github.com/articulate/paperplane) module.
|
|
1338
1338
|
*/
|
|
1339
|
-
|
|
1339
|
+
interface paperplane extends HttpServer {}
|
|
1340
1340
|
|
|
1341
1341
|
/**
|
|
1342
1342
|
* This plugin automatically instruments the
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel
|
|
4
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const enterChannel = channel('apm:connect:middleware:enter')
|
|
7
7
|
const exitChannel = channel('apm:connect:middleware:exit')
|
|
8
8
|
const errorChannel = channel('apm:connect:middleware:error')
|
|
9
9
|
const nextChannel = channel('apm:connect:middleware:next')
|
|
10
|
+
const finishChannel = channel('apm:connect:middleware:finish')
|
|
10
11
|
const handleChannel = channel('apm:connect:request:handle')
|
|
11
12
|
|
|
12
13
|
function wrapConnect (connect) {
|
|
@@ -61,7 +62,6 @@ function wrapLayerHandle (layer) {
|
|
|
61
62
|
return shimmer.wrap(original, function () {
|
|
62
63
|
if (!enterChannel.hasSubscribers) return original.apply(this, arguments)
|
|
63
64
|
|
|
64
|
-
const middlewareResource = new AsyncResource('bound-anonymous-fn')
|
|
65
65
|
const lastIndex = arguments.length - 1
|
|
66
66
|
const name = original._name || original.name
|
|
67
67
|
const req = arguments[arguments.length > 3 ? 1 : 0]
|
|
@@ -71,21 +71,21 @@ function wrapLayerHandle (layer) {
|
|
|
71
71
|
arguments[lastIndex] = wrapNext(req, next)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
const route = layer.route
|
|
74
|
+
const route = layer.route
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
enterChannel.publish({ name, req, route })
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
try {
|
|
79
|
+
return original.apply(this, arguments)
|
|
80
|
+
} catch (error) {
|
|
81
|
+
errorChannel.publish({ req, error })
|
|
82
|
+
nextChannel.publish({ req })
|
|
83
|
+
finishChannel.publish({ req })
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
throw error
|
|
86
|
+
} finally {
|
|
87
|
+
exitChannel.publish({ req })
|
|
88
|
+
}
|
|
89
89
|
})
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -96,7 +96,7 @@ function wrapNext (req, next) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
nextChannel.publish({ req })
|
|
99
|
-
|
|
99
|
+
finishChannel.publish({ req })
|
|
100
100
|
|
|
101
101
|
next.apply(this, arguments)
|
|
102
102
|
}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
channel,
|
|
5
|
-
addHook
|
|
6
|
-
AsyncResource
|
|
5
|
+
addHook
|
|
7
6
|
} = require('../helpers/instrument')
|
|
8
7
|
const shimmer = require('../../../datadog-shimmer')
|
|
9
8
|
|
|
10
9
|
const startServerCh = channel('apm:http:server:request:start')
|
|
10
|
+
const exitServerCh = channel('apm:http:server:request:exit')
|
|
11
11
|
const errorServerCh = channel('apm:http:server:request:error')
|
|
12
12
|
const finishServerCh = channel('apm:http:server:request:finish')
|
|
13
13
|
|
|
@@ -45,18 +45,17 @@ function wrapEmit (emit) {
|
|
|
45
45
|
if (eventName === 'request') {
|
|
46
46
|
res.req = req
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
return asyncResource.runInAsyncScope(() => {
|
|
50
|
-
startServerCh.publish({ req, res })
|
|
48
|
+
startServerCh.publish({ req, res })
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
try {
|
|
51
|
+
return emit.apply(this, arguments)
|
|
52
|
+
} catch (err) {
|
|
53
|
+
errorServerCh.publish(err)
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
throw err
|
|
56
|
+
} finally {
|
|
57
|
+
exitServerCh.publish({ req })
|
|
58
|
+
}
|
|
60
59
|
}
|
|
61
60
|
return emit.apply(this, arguments)
|
|
62
61
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel
|
|
4
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const enterChannel = channel('apm:koa:middleware:enter')
|
|
7
7
|
const exitChannel = channel('apm:koa:middleware:exit')
|
|
8
8
|
const errorChannel = channel('apm:koa:middleware:error')
|
|
9
9
|
const nextChannel = channel('apm:koa:middleware:next')
|
|
10
|
+
const finishChannel = channel('apm:koa:middleware:finish')
|
|
10
11
|
const handleChannel = channel('apm:koa:request:handle')
|
|
11
12
|
const routeChannel = channel('apm:koa:request:route')
|
|
12
13
|
|
|
@@ -86,42 +87,41 @@ function wrapMiddleware (fn, layer) {
|
|
|
86
87
|
return function (ctx, next) {
|
|
87
88
|
if (!ctx || !enterChannel.hasSubscribers) return fn.apply(this, arguments)
|
|
88
89
|
|
|
89
|
-
const middlewareResource = new AsyncResource('bound-anonymous-fn')
|
|
90
90
|
const req = ctx.req
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const route = typeof path === 'string' && !path.endsWith('(.*)') && !path.endsWith('([^/]*)') && path
|
|
92
|
+
const path = layer && layer.path
|
|
93
|
+
const route = typeof path === 'string' && !path.endsWith('(.*)') && !path.endsWith('([^/]*)') && path
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
enterChannel.publish({ req, name, route })
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
if (typeof next === 'function') {
|
|
98
|
+
arguments[1] = wrapNext(req, next)
|
|
99
|
+
}
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
} catch (e) {
|
|
121
|
-
fulfill(ctx, e)
|
|
122
|
-
throw e
|
|
101
|
+
try {
|
|
102
|
+
const result = fn.apply(this, arguments)
|
|
103
|
+
|
|
104
|
+
if (result && typeof result.then === 'function') {
|
|
105
|
+
return result.then(
|
|
106
|
+
result => {
|
|
107
|
+
fulfill(ctx)
|
|
108
|
+
return result
|
|
109
|
+
},
|
|
110
|
+
err => {
|
|
111
|
+
fulfill(ctx, err)
|
|
112
|
+
throw err
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
} else {
|
|
116
|
+
fulfill(ctx)
|
|
117
|
+
return result
|
|
123
118
|
}
|
|
124
|
-
})
|
|
119
|
+
} catch (e) {
|
|
120
|
+
fulfill(ctx, e)
|
|
121
|
+
throw e
|
|
122
|
+
} finally {
|
|
123
|
+
exitChannel.publish({ req })
|
|
124
|
+
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -138,7 +138,7 @@ function fulfill (ctx, error) {
|
|
|
138
138
|
routeChannel.publish({ req, route })
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
finishChannel.publish({ req })
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
function wrapNext (req, next) {
|
|
@@ -9,6 +9,7 @@ const handleChannel = channel('apm:restify:request:handle')
|
|
|
9
9
|
const errorChannel = channel('apm:restify:middleware:error')
|
|
10
10
|
const enterChannel = channel('apm:restify:middleware:enter')
|
|
11
11
|
const exitChannel = channel('apm:restify:middleware:exit')
|
|
12
|
+
const finishChannel = channel('apm:restify:middleware:finish')
|
|
12
13
|
const nextChannel = channel('apm:restify:middleware:next')
|
|
13
14
|
|
|
14
15
|
function wrapSetupRequest (setupRequest) {
|
|
@@ -53,8 +54,10 @@ function wrapFn (fn) {
|
|
|
53
54
|
} catch (error) {
|
|
54
55
|
errorChannel.publish({ req, error })
|
|
55
56
|
nextChannel.publish({ req })
|
|
56
|
-
|
|
57
|
+
finishChannel.publish({ req })
|
|
57
58
|
throw error
|
|
59
|
+
} finally {
|
|
60
|
+
exitChannel.publish({ req })
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
}
|
|
@@ -62,7 +65,7 @@ function wrapFn (fn) {
|
|
|
62
65
|
function wrapNext (req, next) {
|
|
63
66
|
return function () {
|
|
64
67
|
nextChannel.publish({ req })
|
|
65
|
-
|
|
68
|
+
finishChannel.publish({ req })
|
|
66
69
|
|
|
67
70
|
next.apply(this, arguments)
|
|
68
71
|
}
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
const METHODS = require('methods').concat('all')
|
|
4
4
|
const pathToRegExp = require('path-to-regexp')
|
|
5
5
|
const shimmer = require('../../datadog-shimmer')
|
|
6
|
-
const { addHook, channel
|
|
6
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
7
7
|
|
|
8
8
|
function createWrapRouterMethod (name) {
|
|
9
9
|
const enterChannel = channel(`apm:${name}:middleware:enter`)
|
|
10
10
|
const exitChannel = channel(`apm:${name}:middleware:exit`)
|
|
11
|
+
const finishChannel = channel(`apm:${name}:middleware:finish`)
|
|
11
12
|
const errorChannel = channel(`apm:${name}:middleware:error`)
|
|
12
13
|
const nextChannel = channel(`apm:${name}:middleware:next`)
|
|
13
14
|
|
|
@@ -21,7 +22,6 @@ function createWrapRouterMethod (name) {
|
|
|
21
22
|
if (!enterChannel.hasSubscribers) return original.apply(this, arguments)
|
|
22
23
|
|
|
23
24
|
const matchers = layerMatchers.get(layer)
|
|
24
|
-
const middlewareResource = new AsyncResource('bound-anonymous-fn')
|
|
25
25
|
const lastIndex = arguments.length - 1
|
|
26
26
|
const name = original._name || original.name
|
|
27
27
|
const req = arguments[arguments.length > 3 ? 1 : 0]
|
|
@@ -31,32 +31,32 @@ function createWrapRouterMethod (name) {
|
|
|
31
31
|
arguments[lastIndex] = wrapNext(req, next)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
let route
|
|
34
|
+
let route
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
if (matchers) {
|
|
37
|
+
// Try to guess which path actually matched
|
|
38
|
+
for (let i = 0; i < matchers.length; i++) {
|
|
39
|
+
if (matchers[i].test(layer)) {
|
|
40
|
+
route = matchers[i].path
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
}
|
|
42
|
+
break
|
|
45
43
|
}
|
|
46
44
|
}
|
|
45
|
+
}
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
enterChannel.publish({ name, req, route })
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
try {
|
|
50
|
+
return original.apply(this, arguments)
|
|
51
|
+
} catch (error) {
|
|
52
|
+
errorChannel.publish({ req, error })
|
|
53
|
+
nextChannel.publish({ req })
|
|
54
|
+
finishChannel.publish({ req })
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
throw error
|
|
57
|
+
} finally {
|
|
58
|
+
exitChannel.publish({ req })
|
|
59
|
+
}
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
// This is a workaround for the `loopback` library so that it can find the correct express layer
|
|
@@ -95,7 +95,7 @@ function createWrapRouterMethod (name) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
nextChannel.publish({ req })
|
|
98
|
-
|
|
98
|
+
finishChannel.publish({ req })
|
|
99
99
|
|
|
100
100
|
next.apply(this, arguments)
|
|
101
101
|
}
|
|
@@ -14,12 +14,15 @@ class HttpServerPlugin extends Plugin {
|
|
|
14
14
|
constructor (...args) {
|
|
15
15
|
super(...args)
|
|
16
16
|
|
|
17
|
+
this._parentStore = undefined
|
|
18
|
+
|
|
17
19
|
this.addSub('apm:http:server:request:start', ({ req, res }) => {
|
|
18
20
|
const store = storage.getStore()
|
|
19
21
|
const span = web.startSpan(this.tracer, this.config, req, res, 'http.request')
|
|
20
22
|
|
|
21
23
|
span.setTag(COMPONENT, this.constructor.name)
|
|
22
24
|
|
|
25
|
+
this._parentStore = store
|
|
23
26
|
this.enter(span, { ...store, req })
|
|
24
27
|
|
|
25
28
|
const context = web.getContext(req)
|
|
@@ -38,6 +41,11 @@ class HttpServerPlugin extends Plugin {
|
|
|
38
41
|
web.addError(error)
|
|
39
42
|
})
|
|
40
43
|
|
|
44
|
+
this.addSub('apm:http:server:request:exit', ({ req }) => {
|
|
45
|
+
this.enter(this._parentStore)
|
|
46
|
+
this._parentStore = undefined
|
|
47
|
+
})
|
|
48
|
+
|
|
41
49
|
this.addSub('apm:http:server:request:finish', ({ req }) => {
|
|
42
50
|
const context = web.getContext(req)
|
|
43
51
|
|
|
@@ -14,6 +14,7 @@ class RouterPlugin extends WebPlugin {
|
|
|
14
14
|
constructor (...args) {
|
|
15
15
|
super(...args)
|
|
16
16
|
|
|
17
|
+
this._storeStack = []
|
|
17
18
|
this._contexts = new WeakMap()
|
|
18
19
|
|
|
19
20
|
this.addSub(`apm:${this.constructor.name}:middleware:enter`, ({ req, name, route }) => {
|
|
@@ -28,6 +29,7 @@ class RouterPlugin extends WebPlugin {
|
|
|
28
29
|
context.middleware.push(span)
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
this._storeStack.push(storage.getStore())
|
|
31
33
|
this.enter(span)
|
|
32
34
|
|
|
33
35
|
web.patch(req)
|
|
@@ -42,7 +44,7 @@ class RouterPlugin extends WebPlugin {
|
|
|
42
44
|
context.stack.pop()
|
|
43
45
|
})
|
|
44
46
|
|
|
45
|
-
this.addSub(`apm:${this.constructor.name}:middleware:
|
|
47
|
+
this.addSub(`apm:${this.constructor.name}:middleware:finish`, ({ req }) => {
|
|
46
48
|
const context = this._contexts.get(req)
|
|
47
49
|
|
|
48
50
|
if (!context || context.middleware.length === 0) return
|
|
@@ -50,6 +52,10 @@ class RouterPlugin extends WebPlugin {
|
|
|
50
52
|
context.middleware.pop().finish()
|
|
51
53
|
})
|
|
52
54
|
|
|
55
|
+
this.addSub(`apm:${this.constructor.name}:middleware:exit`, ({ req }) => {
|
|
56
|
+
this.enter(this._storeStack.pop())
|
|
57
|
+
})
|
|
58
|
+
|
|
53
59
|
this.addSub(`apm:${this.constructor.name}:middleware:error`, ({ req, error }) => {
|
|
54
60
|
web.addError(req, error)
|
|
55
61
|
|
|
@@ -265,7 +265,11 @@ const web = {
|
|
|
265
265
|
|
|
266
266
|
// Extract the parent span from the headers and start a new span as its child
|
|
267
267
|
startChildSpan (tracer, name, headers) {
|
|
268
|
-
const
|
|
268
|
+
const activeSpan = tracer.scope().active()
|
|
269
|
+
const spanContext = activeSpan && activeSpan.context()
|
|
270
|
+
const isLambda = spanContext && spanContext._name === 'aws.lambda'
|
|
271
|
+
|
|
272
|
+
const childOf = (isLambda && activeSpan) || tracer.extract(FORMAT_HTTP_HEADERS, headers)
|
|
269
273
|
|
|
270
274
|
const span = tracer.startSpan(name, { childOf })
|
|
271
275
|
|
|
@@ -33,6 +33,7 @@ class Config {
|
|
|
33
33
|
const service = options.service || DD_SERVICE || 'node'
|
|
34
34
|
const host = os.hostname()
|
|
35
35
|
const version = coalesce(options.version, DD_VERSION)
|
|
36
|
+
const functionname = process.env.AWS_LAMBDA_FUNCTION_NAME
|
|
36
37
|
// Must be longer than one minute so pad with five seconds
|
|
37
38
|
const flushInterval = coalesce(options.interval, 65 * 1000)
|
|
38
39
|
const uploadTimeout = coalesce(options.uploadTimeout,
|
|
@@ -46,12 +47,13 @@ class Config {
|
|
|
46
47
|
this.service = service
|
|
47
48
|
this.env = env
|
|
48
49
|
this.host = host
|
|
50
|
+
this.functionname = functionname
|
|
49
51
|
|
|
50
52
|
this.version = version
|
|
51
53
|
this.tags = Object.assign(
|
|
52
54
|
tagger.parse(DD_TAGS),
|
|
53
55
|
tagger.parse(options.tags),
|
|
54
|
-
tagger.parse({ env, host, service, version })
|
|
56
|
+
tagger.parse({ env, host, service, version, functionname })
|
|
55
57
|
)
|
|
56
58
|
this.logger = ensureLogger(options.logger)
|
|
57
59
|
this.flushInterval = flushInterval
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { Profiler } = require('./profiler')
|
|
3
|
+
const { Profiler, ServerlessProfiler } = require('./profiler')
|
|
4
4
|
const CpuProfiler = require('./profilers/cpu')
|
|
5
5
|
const WallProfiler = require('./profilers/wall')
|
|
6
6
|
const SpaceProfiler = require('./profilers/space')
|
|
@@ -8,7 +8,7 @@ const { AgentExporter } = require('./exporters/agent')
|
|
|
8
8
|
const { FileExporter } = require('./exporters/file')
|
|
9
9
|
const { ConsoleLogger } = require('./loggers/console')
|
|
10
10
|
|
|
11
|
-
const profiler = new Profiler()
|
|
11
|
+
const profiler = process.env.AWS_LAMBDA_FUNCTION_NAME ? new ServerlessProfiler() : new Profiler()
|
|
12
12
|
|
|
13
13
|
module.exports = {
|
|
14
14
|
profiler,
|
|
@@ -5,7 +5,6 @@ const { Config } = require('./config')
|
|
|
5
5
|
|
|
6
6
|
function maybeSourceMap (sourceMap) {
|
|
7
7
|
if (!sourceMap) return
|
|
8
|
-
|
|
9
8
|
const { SourceMapper } = require('@datadog/pprof')
|
|
10
9
|
return SourceMapper.create([
|
|
11
10
|
process.cwd()
|
|
@@ -20,6 +19,7 @@ class Profiler extends EventEmitter {
|
|
|
20
19
|
this._config = undefined
|
|
21
20
|
this._timer = undefined
|
|
22
21
|
this._lastStart = undefined
|
|
22
|
+
this._timeoutInterval = undefined
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
start (options) {
|
|
@@ -35,6 +35,7 @@ class Profiler extends EventEmitter {
|
|
|
35
35
|
|
|
36
36
|
this._logger = config.logger
|
|
37
37
|
this._enabled = true
|
|
38
|
+
this._setInterval()
|
|
38
39
|
|
|
39
40
|
// Log errors if the source map finder fails, but don't prevent the rest
|
|
40
41
|
// of the profiler from running without source maps.
|
|
@@ -52,13 +53,17 @@ class Profiler extends EventEmitter {
|
|
|
52
53
|
this._logger.debug(`Started ${profiler.type} profiler`)
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
this._capture(
|
|
56
|
+
this._capture(this._timeoutInterval)
|
|
56
57
|
} catch (e) {
|
|
57
58
|
this._logger.error(e)
|
|
58
59
|
this.stop()
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
_setInterval () {
|
|
64
|
+
this._timeoutInterval = this._config.flushInterval
|
|
65
|
+
}
|
|
66
|
+
|
|
62
67
|
stop () {
|
|
63
68
|
if (!this._enabled) return
|
|
64
69
|
|
|
@@ -78,8 +83,7 @@ class Profiler extends EventEmitter {
|
|
|
78
83
|
_capture (timeout) {
|
|
79
84
|
if (!this._enabled) return
|
|
80
85
|
this._lastStart = new Date()
|
|
81
|
-
|
|
82
|
-
if (!this._timer || timeout !== this._config.flushInterval) {
|
|
86
|
+
if (!this._timer || timeout !== this._timeoutInterval) {
|
|
83
87
|
this._timer = setTimeout(() => this._collect(), timeout)
|
|
84
88
|
this._timer.unref()
|
|
85
89
|
} else {
|
|
@@ -106,7 +110,7 @@ class Profiler extends EventEmitter {
|
|
|
106
110
|
})
|
|
107
111
|
}
|
|
108
112
|
|
|
109
|
-
this._capture(this.
|
|
113
|
+
this._capture(this._timeoutInterval)
|
|
110
114
|
await this._submit(profiles, start, end)
|
|
111
115
|
this._logger.debug('Submitted profiles')
|
|
112
116
|
} catch (err) {
|
|
@@ -133,4 +137,29 @@ class Profiler extends EventEmitter {
|
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
|
|
136
|
-
|
|
140
|
+
class ServerlessProfiler extends Profiler {
|
|
141
|
+
constructor () {
|
|
142
|
+
super()
|
|
143
|
+
this._profiledIntervals = 0
|
|
144
|
+
this._interval = 1
|
|
145
|
+
this._flushAfterIntervals = undefined
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_setInterval () {
|
|
149
|
+
this._timeoutInterval = this._interval * 1000
|
|
150
|
+
this._flushAfterIntervals = this._config.flushInterval / 1000
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async _collect () {
|
|
154
|
+
if (this._profiledIntervals >= this._flushAfterIntervals) {
|
|
155
|
+
this._profiledIntervals = 0
|
|
156
|
+
await super._collect()
|
|
157
|
+
} else {
|
|
158
|
+
this._profiledIntervals += 1
|
|
159
|
+
this._capture(this._timeoutInterval)
|
|
160
|
+
// Don't submit profile until 65 (flushAfterIntervals) intervals have elapsed
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { Profiler, ServerlessProfiler }
|