dd-trace 3.14.1 → 3.16.0
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/LICENSE-3rdparty.csv +2 -2
- package/README.md +9 -5
- package/ci/init.js +9 -1
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +36 -3
- package/package.json +21 -19
- package/packages/datadog-instrumentations/src/cucumber.js +80 -3
- package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +100 -27
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +35 -3
- package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
- package/packages/datadog-instrumentations/src/mariadb.js +130 -11
- package/packages/datadog-instrumentations/src/mocha.js +30 -6
- package/packages/datadog-instrumentations/src/mongodb-core.js +8 -2
- package/packages/datadog-instrumentations/src/mongoose.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +33 -4
- package/packages/datadog-instrumentations/src/playwright.js +42 -13
- package/packages/datadog-plugin-amqp10/src/consumer.js +1 -1
- package/packages/datadog-plugin-amqp10/src/index.js +1 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -2
- package/packages/datadog-plugin-amqplib/src/client.js +3 -2
- package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
- package/packages/datadog-plugin-amqplib/src/index.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +7 -2
- package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -0
- package/packages/datadog-plugin-bunyan/src/index.js +1 -1
- package/packages/datadog-plugin-cassandra-driver/src/index.js +3 -2
- package/packages/datadog-plugin-connect/src/index.js +1 -1
- package/packages/datadog-plugin-couchbase/src/index.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +33 -6
- package/packages/datadog-plugin-cypress/src/index.js +1 -1
- package/packages/datadog-plugin-cypress/src/plugin.js +40 -33
- package/packages/datadog-plugin-dns/src/index.js +1 -1
- package/packages/datadog-plugin-dns/src/lookup.js +1 -1
- package/packages/datadog-plugin-dns/src/lookup_service.js +1 -1
- package/packages/datadog-plugin-dns/src/resolve.js +1 -1
- package/packages/datadog-plugin-dns/src/reverse.js +1 -1
- package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
- package/packages/datadog-plugin-express/src/index.js +1 -1
- package/packages/datadog-plugin-fastify/src/index.js +1 -1
- package/packages/datadog-plugin-find-my-way/src/index.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +5 -5
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +7 -6
- package/packages/datadog-plugin-graphql/src/execute.js +1 -1
- package/packages/datadog-plugin-graphql/src/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/parse.js +1 -1
- package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
- package/packages/datadog-plugin-graphql/src/validate.js +1 -1
- package/packages/datadog-plugin-grpc/src/client.js +1 -1
- package/packages/datadog-plugin-grpc/src/index.js +1 -1
- package/packages/datadog-plugin-grpc/src/server.js +1 -1
- package/packages/datadog-plugin-hapi/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +2 -2
- package/packages/datadog-plugin-http/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +3 -3
- package/packages/datadog-plugin-http2/src/client.js +4 -3
- package/packages/datadog-plugin-http2/src/index.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +3 -3
- package/packages/datadog-plugin-ioredis/src/index.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +53 -19
- package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
- package/packages/datadog-plugin-koa/src/index.js +1 -1
- package/packages/datadog-plugin-mariadb/src/index.js +18 -1
- package/packages/datadog-plugin-memcached/src/index.js +3 -2
- package/packages/datadog-plugin-microgateway-core/src/index.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +13 -9
- package/packages/datadog-plugin-moleculer/src/client.js +1 -1
- package/packages/datadog-plugin-moleculer/src/index.js +1 -1
- package/packages/datadog-plugin-moleculer/src/server.js +1 -1
- package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
- package/packages/datadog-plugin-mysql/src/index.js +3 -2
- package/packages/datadog-plugin-mysql2/src/index.js +1 -1
- package/packages/datadog-plugin-net/src/index.js +9 -75
- package/packages/datadog-plugin-net/src/ipc.js +1 -1
- package/packages/datadog-plugin-net/src/tcp.js +3 -2
- package/packages/datadog-plugin-next/src/index.js +3 -3
- package/packages/datadog-plugin-opensearch/src/index.js +1 -1
- package/packages/datadog-plugin-oracledb/src/index.js +3 -2
- package/packages/datadog-plugin-paperplane/src/index.js +1 -1
- package/packages/datadog-plugin-paperplane/src/logger.js +1 -1
- package/packages/datadog-plugin-paperplane/src/server.js +1 -1
- package/packages/datadog-plugin-pg/src/index.js +3 -2
- package/packages/datadog-plugin-pino/src/index.js +1 -1
- package/packages/datadog-plugin-playwright/src/index.js +5 -4
- package/packages/datadog-plugin-redis/src/index.js +3 -2
- package/packages/datadog-plugin-restify/src/index.js +1 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
- package/packages/datadog-plugin-rhea/src/index.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +3 -2
- package/packages/datadog-plugin-router/src/index.js +8 -8
- package/packages/datadog-plugin-sharedb/src/index.js +1 -1
- package/packages/datadog-plugin-tedious/src/index.js +3 -2
- package/packages/datadog-plugin-web/src/index.js +1 -1
- package/packages/datadog-plugin-winston/src/index.js +1 -1
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +35 -9
- package/packages/dd-trace/src/appsec/gateway/engine/runner.js +2 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
- package/packages/dd-trace/src/appsec/iast/iast-log.js +111 -0
- package/packages/dd-trace/src/appsec/iast/index.js +10 -6
- package/packages/dd-trace/src/appsec/iast/path-line.js +3 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +5 -3
- package/packages/dd-trace/src/appsec/iast/telemetry/log_collector.js +96 -0
- package/packages/dd-trace/src/appsec/iast/telemetry/logs.js +87 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +27 -2
- package/packages/dd-trace/src/appsec/index.js +4 -4
- package/packages/dd-trace/src/appsec/recommended.json +76 -75
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
- package/packages/dd-trace/src/appsec/sdk/index.js +19 -1
- package/packages/dd-trace/src/appsec/sdk/noop.js +6 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
- package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +27 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -9
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +14 -8
- package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/index.js +33 -0
- package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/writer.js +37 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +12 -4
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +12 -4
- package/packages/dd-trace/src/config.js +24 -5
- package/packages/dd-trace/src/constants.js +2 -1
- package/packages/dd-trace/src/datastreams/encoding.js +80 -0
- package/packages/dd-trace/src/exporter.js +7 -9
- package/packages/dd-trace/src/exporters/common/agents.js +42 -0
- package/packages/dd-trace/src/exporters/common/docker.js +4 -1
- package/packages/dd-trace/src/exporters/common/request.js +1 -4
- package/packages/dd-trace/src/lambda/handler.js +19 -12
- package/packages/dd-trace/src/log/writer.js +32 -24
- package/packages/dd-trace/src/metrics.js +18 -0
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/opentracing/span.js +5 -0
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugin_manager.js +7 -7
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -17
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/outgoing.js +2 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +12 -0
- package/packages/dd-trace/src/plugins/util/exec.js +2 -2
- package/packages/dd-trace/src/plugins/util/git.js +16 -1
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +23 -27
- package/packages/dd-trace/src/plugins/util/test.js +26 -7
- package/packages/dd-trace/src/profiler.js +3 -0
- package/packages/dd-trace/src/profiling/config.js +92 -20
- package/packages/dd-trace/src/profiling/constants.js +16 -0
- package/packages/dd-trace/src/profiling/exporter_cli.js +62 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +2 -1
- package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
- package/packages/dd-trace/src/profiling/profiler.js +42 -12
- package/packages/dd-trace/src/profiling/profilers/space.js +21 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/proxy.js +1 -1
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_sampler.js +71 -54
- package/packages/dd-trace/src/startup-log.js +3 -6
- package/packages/dd-trace/src/telemetry/index.js +16 -2
- package/packages/dd-trace/src/tracer.js +0 -16
- package/packages/dd-trace/src/util.js +10 -1
- package/scripts/install_plugin_modules.js +5 -1
- package/scripts/junit_report.js +0 -25
- package/scripts/tdd.js +0 -34
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const log = require('../log')
|
|
3
4
|
const { channel } = require('../../../datadog-instrumentations/src/helpers/instrument')
|
|
4
5
|
const { ERROR_MESSAGE, ERROR_TYPE } = require('../constants')
|
|
5
6
|
const { ImpendingTimeout } = require('./runtime/errors')
|
|
@@ -22,15 +23,14 @@ let __lambdaTimeout
|
|
|
22
23
|
* @param {*} context AWS Lambda context object.
|
|
23
24
|
*/
|
|
24
25
|
function checkTimeout (context) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
26
|
+
const remainingTimeInMillis = context.getRemainingTimeInMillis()
|
|
27
|
+
|
|
28
|
+
let apmFlushDeadline = parseInt(process.env.DD_APM_FLUSH_DEADLINE_MILLISECONDS) || 100
|
|
29
|
+
apmFlushDeadline = apmFlushDeadline < 0 ? 100 : apmFlushDeadline
|
|
30
30
|
|
|
31
31
|
__lambdaTimeout = setTimeout(() => {
|
|
32
32
|
timeoutChannel.publish(undefined)
|
|
33
|
-
}, remainingTimeInMillis -
|
|
33
|
+
}, remainingTimeInMillis - apmFlushDeadline)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -43,13 +43,20 @@ function checkTimeout (context) {
|
|
|
43
43
|
*/
|
|
44
44
|
function crashFlush () {
|
|
45
45
|
const activeSpan = tracer.scope().active()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (activeSpan !== null) {
|
|
47
|
+
const error = new ImpendingTimeout('Datadog detected an impending timeout')
|
|
48
|
+
activeSpan.addTags({
|
|
49
|
+
[ERROR_MESSAGE]: error.message,
|
|
50
|
+
[ERROR_TYPE]: error.name
|
|
51
|
+
})
|
|
52
|
+
} else {
|
|
53
|
+
log.warn('An impending timeout was reached, but no root span was found. No error will be tagged.')
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
tracer._processor.killAll()
|
|
52
|
-
activeSpan
|
|
57
|
+
if (activeSpan !== null) {
|
|
58
|
+
activeSpan.finish()
|
|
59
|
+
}
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
/**
|
|
@@ -78,39 +78,47 @@ function reset () {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function onError (err) {
|
|
81
|
-
if (enabled)
|
|
82
|
-
if (typeof err !== 'object' || !err) {
|
|
83
|
-
err = String(err)
|
|
84
|
-
} else if (!err.stack) {
|
|
85
|
-
err = String(err.message || err)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (typeof err === 'string') {
|
|
89
|
-
err = new Error(err)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
withNoop(() => logger.error(err))
|
|
93
|
-
}
|
|
81
|
+
if (enabled) error(err)
|
|
94
82
|
}
|
|
95
83
|
|
|
96
84
|
function onWarn (message) {
|
|
97
|
-
if (
|
|
98
|
-
if (enabled) {
|
|
99
|
-
withNoop(() => logger.warn(message))
|
|
100
|
-
}
|
|
85
|
+
if (enabled) warn(message)
|
|
101
86
|
}
|
|
102
87
|
|
|
103
88
|
function onInfo (message) {
|
|
104
|
-
if (
|
|
105
|
-
if (enabled) {
|
|
106
|
-
withNoop(() => logger.info(message))
|
|
107
|
-
}
|
|
89
|
+
if (enabled) info(message)
|
|
108
90
|
}
|
|
109
91
|
|
|
110
92
|
function onDebug (message) {
|
|
111
|
-
if (enabled)
|
|
112
|
-
|
|
93
|
+
if (enabled) debug(message)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function error (err) {
|
|
97
|
+
if (typeof err !== 'object' || !err) {
|
|
98
|
+
err = String(err)
|
|
99
|
+
} else if (!err.stack) {
|
|
100
|
+
err = String(err.message || err)
|
|
113
101
|
}
|
|
102
|
+
|
|
103
|
+
if (typeof err === 'string') {
|
|
104
|
+
err = new Error(err)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
withNoop(() => logger.error(err))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function warn (message) {
|
|
111
|
+
if (!logger.warn) return debug(message)
|
|
112
|
+
withNoop(() => logger.warn(message))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function info (message) {
|
|
116
|
+
if (!logger.info) return debug(message)
|
|
117
|
+
withNoop(() => logger.info(message))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function debug (message) {
|
|
121
|
+
withNoop(() => logger.debug(message))
|
|
114
122
|
}
|
|
115
123
|
|
|
116
|
-
module.exports = { use, toggle, reset }
|
|
124
|
+
module.exports = { use, toggle, reset, error, warn, info, debug }
|
|
@@ -8,6 +8,7 @@ const os = require('os')
|
|
|
8
8
|
const Client = require('./dogstatsd')
|
|
9
9
|
const log = require('./log')
|
|
10
10
|
const Histogram = require('./histogram')
|
|
11
|
+
const { performance } = require('perf_hooks')
|
|
11
12
|
|
|
12
13
|
const INTERVAL = 10 * 1000
|
|
13
14
|
|
|
@@ -20,6 +21,7 @@ let cpuUsage
|
|
|
20
21
|
let gauges
|
|
21
22
|
let counters
|
|
22
23
|
let histograms
|
|
24
|
+
let elu
|
|
23
25
|
|
|
24
26
|
reset()
|
|
25
27
|
|
|
@@ -259,6 +261,21 @@ function captureHistograms () {
|
|
|
259
261
|
})
|
|
260
262
|
}
|
|
261
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Gathers and reports Event Loop Utilization (ELU) since last run
|
|
266
|
+
*
|
|
267
|
+
* ELU is a measure of how busy the event loop is, like running JavaScript or
|
|
268
|
+
* waiting on *Sync functions. The value is between 0 (idle) and 1 (exhausted).
|
|
269
|
+
*
|
|
270
|
+
* performance.eventLoopUtilization available in Node.js >= v14.10, >= v12.19, >= v16
|
|
271
|
+
*/
|
|
272
|
+
const captureELU = ('eventLoopUtilization' in performance) ? () => {
|
|
273
|
+
// if elu is undefined (first run) the measurement is from start of process
|
|
274
|
+
elu = performance.eventLoopUtilization(elu)
|
|
275
|
+
|
|
276
|
+
client.gauge('runtime.node.event_loop.utilization', elu.utilization)
|
|
277
|
+
} : () => {}
|
|
278
|
+
|
|
262
279
|
function captureCommonMetrics () {
|
|
263
280
|
captureMemoryUsage()
|
|
264
281
|
captureProcess()
|
|
@@ -266,6 +283,7 @@ function captureCommonMetrics () {
|
|
|
266
283
|
captureGauges()
|
|
267
284
|
captureCounters()
|
|
268
285
|
captureHistograms()
|
|
286
|
+
captureELU()
|
|
269
287
|
}
|
|
270
288
|
|
|
271
289
|
function captureNativeMetrics () {
|
|
@@ -32,6 +32,11 @@ class DatadogSpan {
|
|
|
32
32
|
this._processor = processor
|
|
33
33
|
this._prioritySampler = prioritySampler
|
|
34
34
|
this._store = storage.getStore()
|
|
35
|
+
this._duration = undefined
|
|
36
|
+
|
|
37
|
+
// For internal use only. You probably want `context()._name`.
|
|
38
|
+
// This name property is not updated when the span name changes.
|
|
39
|
+
// This is necessary for span count metrics.
|
|
35
40
|
this._name = operationName
|
|
36
41
|
|
|
37
42
|
this._spanContext = this._createContext(parent)
|
|
@@ -12,7 +12,7 @@ class DatadogSpanContext {
|
|
|
12
12
|
this._name = props.name
|
|
13
13
|
this._isFinished = props.isFinished || false
|
|
14
14
|
this._tags = props.tags || {}
|
|
15
|
-
this._sampling = props.sampling
|
|
15
|
+
this._sampling = Object.assign({}, props.sampling)
|
|
16
16
|
this._baggageItems = props.baggageItems || {}
|
|
17
17
|
this._traceparent = props.traceparent
|
|
18
18
|
this._tracestate = props.tracestate
|
|
@@ -28,17 +28,17 @@ loadChannel.subscribe(({ name }) => {
|
|
|
28
28
|
const Plugin = plugins[name]
|
|
29
29
|
|
|
30
30
|
if (!Plugin || typeof Plugin !== 'function') return
|
|
31
|
-
if (!pluginClasses[Plugin.
|
|
32
|
-
const envName = `DD_TRACE_${Plugin.
|
|
31
|
+
if (!pluginClasses[Plugin.id]) {
|
|
32
|
+
const envName = `DD_TRACE_${Plugin.id.toUpperCase()}_ENABLED`
|
|
33
33
|
const enabled = process.env[envName.replace(/[^a-z0-9_]/ig, '_')]
|
|
34
34
|
|
|
35
35
|
// TODO: remove the need to load the plugin class in order to disable the plugin
|
|
36
|
-
if (isFalse(enabled) || disabledPlugins.has(Plugin.
|
|
37
|
-
log.debug(`Plugin "${Plugin.
|
|
36
|
+
if (isFalse(enabled) || disabledPlugins.has(Plugin.id)) {
|
|
37
|
+
log.debug(`Plugin "${Plugin.id}" was disabled via configuration option.`)
|
|
38
38
|
|
|
39
|
-
pluginClasses[Plugin.
|
|
39
|
+
pluginClasses[Plugin.id] = null
|
|
40
40
|
} else {
|
|
41
|
-
pluginClasses[Plugin.
|
|
41
|
+
pluginClasses[Plugin.id] = Plugin
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
})
|
|
@@ -56,7 +56,7 @@ module.exports = class PluginManager {
|
|
|
56
56
|
|
|
57
57
|
if (!Plugin || typeof Plugin !== 'function') return
|
|
58
58
|
|
|
59
|
-
this.loadPlugin(Plugin.
|
|
59
|
+
this.loadPlugin(Plugin.id)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
loadChannel.subscribe(this._loadedSubscriber)
|
|
@@ -12,7 +12,7 @@ const {
|
|
|
12
12
|
TEST_MODULE_ID,
|
|
13
13
|
TEST_SESSION_ID,
|
|
14
14
|
TEST_COMMAND,
|
|
15
|
-
|
|
15
|
+
TEST_MODULE
|
|
16
16
|
} = require('./util/test')
|
|
17
17
|
const Plugin = require('./plugin')
|
|
18
18
|
const { COMPONENT } = require('../constants')
|
|
@@ -22,13 +22,13 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
22
22
|
constructor (...args) {
|
|
23
23
|
super(...args)
|
|
24
24
|
|
|
25
|
-
this.addSub(`ci:${this.constructor.
|
|
25
|
+
this.addSub(`ci:${this.constructor.id}:itr-configuration`, ({ onDone }) => {
|
|
26
26
|
if (!this.tracer._exporter || !this.tracer._exporter.getItrConfiguration) {
|
|
27
27
|
return onDone({ err: new Error('CI Visibility was not initialized correctly') })
|
|
28
28
|
}
|
|
29
29
|
this.tracer._exporter.getItrConfiguration(this.testConfiguration, (err, itrConfig) => {
|
|
30
30
|
if (err) {
|
|
31
|
-
log.error(`
|
|
31
|
+
log.error(`Intelligent Test Runner configuration could not be fetched. ${err.message}`)
|
|
32
32
|
} else {
|
|
33
33
|
this.itrConfig = itrConfig
|
|
34
34
|
}
|
|
@@ -36,40 +36,40 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
36
36
|
})
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
-
this.addSub(`ci:${this.constructor.
|
|
39
|
+
this.addSub(`ci:${this.constructor.id}:test-suite:skippable`, ({ onDone }) => {
|
|
40
40
|
if (!this.tracer._exporter || !this.tracer._exporter.getSkippableSuites) {
|
|
41
41
|
return onDone({ err: new Error('CI Visibility was not initialized correctly') })
|
|
42
42
|
}
|
|
43
43
|
this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
|
|
44
44
|
if (err) {
|
|
45
|
-
log.error(`
|
|
45
|
+
log.error(`Skippable suites could not be fetched. ${err.message}`)
|
|
46
46
|
}
|
|
47
47
|
onDone({ err, skippableSuites })
|
|
48
48
|
})
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
this.addSub(`ci:${this.constructor.
|
|
51
|
+
this.addSub(`ci:${this.constructor.id}:session:start`, ({ command, frameworkVersion, rootDir }) => {
|
|
52
52
|
const childOf = getTestParentSpan(this.tracer)
|
|
53
|
-
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
|
|
54
|
-
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
|
|
53
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion, this.constructor.id)
|
|
54
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion, this.constructor.id)
|
|
55
55
|
|
|
56
56
|
this.command = command
|
|
57
57
|
this.frameworkVersion = frameworkVersion
|
|
58
58
|
// only for playwright
|
|
59
59
|
this.rootDir = rootDir
|
|
60
60
|
|
|
61
|
-
this.testSessionSpan = this.tracer.startSpan(`${this.constructor.
|
|
61
|
+
this.testSessionSpan = this.tracer.startSpan(`${this.constructor.id}.test_session`, {
|
|
62
62
|
childOf,
|
|
63
63
|
tags: {
|
|
64
|
-
[COMPONENT]: this.constructor.
|
|
64
|
+
[COMPONENT]: this.constructor.id,
|
|
65
65
|
...this.testEnvironmentMetadata,
|
|
66
66
|
...testSessionSpanMetadata
|
|
67
67
|
}
|
|
68
68
|
})
|
|
69
|
-
this.testModuleSpan = this.tracer.startSpan(`${this.constructor.
|
|
69
|
+
this.testModuleSpan = this.tracer.startSpan(`${this.constructor.id}.test_module`, {
|
|
70
70
|
childOf: this.testSessionSpan,
|
|
71
71
|
tags: {
|
|
72
|
-
[COMPONENT]: this.constructor.
|
|
72
|
+
[COMPONENT]: this.constructor.id,
|
|
73
73
|
...this.testEnvironmentMetadata,
|
|
74
74
|
...testModuleSpanMetadata
|
|
75
75
|
}
|
|
@@ -79,7 +79,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
79
79
|
|
|
80
80
|
configure (config) {
|
|
81
81
|
super.configure(config)
|
|
82
|
-
this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.
|
|
82
|
+
this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
|
|
83
83
|
this.codeOwnersEntries = getCodeOwnersFileEntries()
|
|
84
84
|
|
|
85
85
|
const {
|
|
@@ -110,7 +110,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
110
110
|
|
|
111
111
|
let testTags = {
|
|
112
112
|
...getTestCommonTags(testName, testSuite, this.frameworkVersion),
|
|
113
|
-
[COMPONENT]: this.constructor.
|
|
113
|
+
[COMPONENT]: this.constructor.id,
|
|
114
114
|
...extraTags
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -128,10 +128,13 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
128
128
|
const suiteTags = {
|
|
129
129
|
[TEST_SUITE_ID]: testSuiteSpan.context().toSpanId(),
|
|
130
130
|
[TEST_SESSION_ID]: testSuiteSpan.context().toTraceId(),
|
|
131
|
-
[TEST_MODULE_ID]: testSuiteSpan.context()._parentId.toString(10),
|
|
132
131
|
[TEST_COMMAND]: testSuiteSpan.context()._tags[TEST_COMMAND],
|
|
133
|
-
[
|
|
132
|
+
[TEST_MODULE]: this.constructor.id
|
|
134
133
|
}
|
|
134
|
+
if (testSuiteSpan.context()._parentId) {
|
|
135
|
+
suiteTags[TEST_MODULE_ID] = testSuiteSpan.context()._parentId.toString(10)
|
|
136
|
+
}
|
|
137
|
+
|
|
135
138
|
testTags = {
|
|
136
139
|
...testTags,
|
|
137
140
|
...suiteTags
|
|
@@ -139,7 +142,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
const testSpan = this.tracer
|
|
142
|
-
.startSpan(`${this.constructor.
|
|
145
|
+
.startSpan(`${this.constructor.id}.test`, {
|
|
143
146
|
childOf,
|
|
144
147
|
tags: {
|
|
145
148
|
...this.testEnvironmentMetadata,
|
|
@@ -39,6 +39,7 @@ module.exports = {
|
|
|
39
39
|
get 'jest-environment-node' () { return require('../../../datadog-plugin-jest/src') },
|
|
40
40
|
get 'jest-environment-jsdom' () { return require('../../../datadog-plugin-jest/src') },
|
|
41
41
|
get 'jest-jasmine2' () { return require('../../../datadog-plugin-jest/src') },
|
|
42
|
+
get 'jest-worker' () { return require('../../../datadog-plugin-jest/src') },
|
|
42
43
|
get 'koa' () { return require('../../../datadog-plugin-koa/src') },
|
|
43
44
|
get 'koa-router' () { return require('../../../datadog-plugin-koa/src') },
|
|
44
45
|
get 'kafkajs' () { return require('../../../datadog-plugin-kafkajs/src') },
|
|
@@ -39,7 +39,7 @@ module.exports = class LogPlugin extends Plugin {
|
|
|
39
39
|
constructor (...args) {
|
|
40
40
|
super(...args)
|
|
41
41
|
|
|
42
|
-
this.addSub(`apm:${this.constructor.
|
|
42
|
+
this.addSub(`apm:${this.constructor.id}:log`, (arg) => {
|
|
43
43
|
const store = storage.getStore()
|
|
44
44
|
const span = store && store.span
|
|
45
45
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { CLIENT_PORT_KEY } = require('../constants')
|
|
3
4
|
const TracingPlugin = require('./tracing')
|
|
4
5
|
|
|
5
6
|
// TODO: Exit span on finish when AsyncResource instances are removed.
|
|
@@ -23,7 +24,7 @@ class OutgoingPlugin extends TracingPlugin {
|
|
|
23
24
|
|
|
24
25
|
span.addTags({
|
|
25
26
|
'out.host': hostname,
|
|
26
|
-
|
|
27
|
+
[CLIENT_PORT_KEY]: port
|
|
27
28
|
})
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -9,7 +9,7 @@ class TracingPlugin extends Plugin {
|
|
|
9
9
|
constructor (...args) {
|
|
10
10
|
super(...args)
|
|
11
11
|
|
|
12
|
-
this.component = this.constructor.component || this.constructor.
|
|
12
|
+
this.component = this.constructor.component || this.constructor.id
|
|
13
13
|
this.operation = this.constructor.operation
|
|
14
14
|
|
|
15
15
|
this.addTraceSub('start', message => {
|
|
@@ -534,6 +534,18 @@ module.exports = {
|
|
|
534
534
|
}
|
|
535
535
|
}
|
|
536
536
|
|
|
537
|
+
if (env.TEAMCITY_VERSION) {
|
|
538
|
+
const { BUILD_URL, TEAMCITY_BUILDCONF_NAME, DATADOG_BUILD_ID } = env
|
|
539
|
+
tags = {
|
|
540
|
+
[CI_PROVIDER_NAME]: 'teamcity',
|
|
541
|
+
[CI_JOB_URL]: BUILD_URL,
|
|
542
|
+
[CI_JOB_NAME]: TEAMCITY_BUILDCONF_NAME,
|
|
543
|
+
[CI_ENV_VARS]: JSON.stringify({
|
|
544
|
+
DATADOG_BUILD_ID
|
|
545
|
+
})
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
537
549
|
normalizeTag(tags, CI_WORKSPACE_PATH, resolveTilde)
|
|
538
550
|
normalizeTag(tags, GIT_REPOSITORY_URL, filterSensitiveInfoFromRepository)
|
|
539
551
|
normalizeTag(tags, GIT_BRANCH, normalizeRef)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const cp = require('child_process')
|
|
2
2
|
|
|
3
3
|
const sanitizedExec = (cmd, options = {}) => {
|
|
4
4
|
try {
|
|
5
|
-
return execSync(cmd, options).toString().replace(/(\r\n|\n|\r)/gm, '')
|
|
5
|
+
return cp.execSync(cmd, options).toString().replace(/(\r\n|\n|\r)/gm, '')
|
|
6
6
|
} catch (e) {
|
|
7
7
|
return ''
|
|
8
8
|
}
|
|
@@ -21,6 +21,19 @@ const {
|
|
|
21
21
|
|
|
22
22
|
const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB
|
|
23
23
|
|
|
24
|
+
function isShallowRepository () {
|
|
25
|
+
return sanitizedExec('git rev-parse --is-shallow-repository', { stdio: 'pipe' }) === 'true'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function unshallowRepository () {
|
|
29
|
+
try {
|
|
30
|
+
execSync('git config remote.origin.partialclonefilter "blob:none"', { stdio: 'pipe' })
|
|
31
|
+
execSync('git fetch --shallow-since="1 month ago" --update-shallow --refetch', { stdio: 'pipe' })
|
|
32
|
+
} catch (err) {
|
|
33
|
+
log.error(err)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
function getRepositoryUrl () {
|
|
25
38
|
return sanitizedExec('git config --get remote.origin.url', { stdio: 'pipe' })
|
|
26
39
|
}
|
|
@@ -146,5 +159,7 @@ module.exports = {
|
|
|
146
159
|
getRepositoryUrl,
|
|
147
160
|
generatePackFilesForCommits,
|
|
148
161
|
getCommitsToUpload,
|
|
149
|
-
GIT_REV_LIST_MAX_BUFFER
|
|
162
|
+
GIT_REV_LIST_MAX_BUFFER,
|
|
163
|
+
isShallowRepository,
|
|
164
|
+
unshallowRepository
|
|
150
165
|
}
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
const BlockList = require('./ip_blocklist')
|
|
4
4
|
const net = require('net')
|
|
5
|
-
const log = require('../../log')
|
|
6
5
|
|
|
7
6
|
const ipHeaderList = [
|
|
8
7
|
'x-forwarded-for',
|
|
9
8
|
'x-real-ip',
|
|
10
|
-
'client-ip',
|
|
9
|
+
'true-client-ip',
|
|
10
|
+
'x-client-ip',
|
|
11
11
|
'x-forwarded',
|
|
12
|
-
'x-cluster-client-ip',
|
|
13
12
|
'forwarded-for',
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
13
|
+
'x-cluster-client-ip',
|
|
14
|
+
'fastly-client-ip',
|
|
15
|
+
'cf-connecting-ip',
|
|
16
|
+
'cf-connecting-ipv6'
|
|
17
17
|
]
|
|
18
18
|
|
|
19
19
|
const privateCIDRs = [
|
|
@@ -41,36 +41,31 @@ function extractIp (config, req) {
|
|
|
41
41
|
const headers = req.headers
|
|
42
42
|
if (config.clientIpHeader) {
|
|
43
43
|
if (!headers) return
|
|
44
|
-
const header = headers[config.clientIpHeader]
|
|
45
|
-
if (!header) return
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
const ip = findFirstIp(headers[config.clientIpHeader])
|
|
46
|
+
return ip.public || ip.private
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
let firstPrivateIp
|
|
51
50
|
if (headers) {
|
|
52
51
|
for (let i = 0; i < ipHeaderList.length; i++) {
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const firstIp = findFirstIp(headers[ipHeaderList[i]])
|
|
53
|
+
|
|
54
|
+
if (firstIp.public) {
|
|
55
|
+
return firstIp.public
|
|
56
|
+
} else if (!firstPrivateIp && firstIp.private) {
|
|
57
|
+
firstPrivateIp = firstIp.private
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
const header = headers[foundHeaders[0]]
|
|
61
|
-
const firstIp = findFirstIp(header)
|
|
62
|
-
|
|
63
|
-
if (firstIp) return firstIp
|
|
64
|
-
} else if (foundHeaders.length > 1) {
|
|
65
|
-
log.error(`Cannot find client IP: multiple IP headers detected ${foundHeaders}`)
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return req.socket && req.socket.remoteAddress
|
|
62
|
+
return firstPrivateIp || (req.socket && req.socket.remoteAddress)
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
function findFirstIp (str) {
|
|
73
|
-
|
|
66
|
+
const result = {}
|
|
67
|
+
if (!str) return result
|
|
68
|
+
|
|
74
69
|
const splitted = str.split(',')
|
|
75
70
|
|
|
76
71
|
for (let i = 0; i < splitted.length; i++) {
|
|
@@ -83,14 +78,15 @@ function findFirstIp (str) {
|
|
|
83
78
|
|
|
84
79
|
if (!privateIPMatcher.check(chunk, type === 6 ? 'ipv6' : 'ipv4')) {
|
|
85
80
|
// it's public, return it immediately
|
|
86
|
-
|
|
81
|
+
result.public = chunk
|
|
82
|
+
break
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
// it's private, only save the first one found
|
|
90
|
-
if (!
|
|
86
|
+
if (!result.private) result.private = chunk
|
|
91
87
|
}
|
|
92
88
|
|
|
93
|
-
return
|
|
89
|
+
return result
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
module.exports = {
|
|
@@ -38,10 +38,11 @@ const TEST_CODE_OWNERS = 'test.codeowners'
|
|
|
38
38
|
const TEST_SOURCE_FILE = 'test.source.file'
|
|
39
39
|
const LIBRARY_VERSION = 'library_version'
|
|
40
40
|
const TEST_COMMAND = 'test.command'
|
|
41
|
-
const
|
|
41
|
+
const TEST_MODULE = 'test.module'
|
|
42
42
|
const TEST_SESSION_ID = 'test_session_id'
|
|
43
43
|
const TEST_MODULE_ID = 'test_module_id'
|
|
44
44
|
const TEST_SUITE_ID = 'test_suite_id'
|
|
45
|
+
const TEST_TOOLCHAIN = 'test.toolchain'
|
|
45
46
|
|
|
46
47
|
const CI_APP_ORIGIN = 'ciapp-test'
|
|
47
48
|
|
|
@@ -55,6 +56,10 @@ const TEST_MODULE_CODE_COVERAGE_ENABLED = 'test_module.code_coverage.enabled'
|
|
|
55
56
|
|
|
56
57
|
const TEST_CODE_COVERAGE_LINES_TOTAL = 'test.codecov_lines_total'
|
|
57
58
|
|
|
59
|
+
// jest worker variables
|
|
60
|
+
const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
|
|
61
|
+
const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
|
|
62
|
+
|
|
58
63
|
module.exports = {
|
|
59
64
|
TEST_CODE_OWNERS,
|
|
60
65
|
TEST_FRAMEWORK,
|
|
@@ -70,6 +75,8 @@ module.exports = {
|
|
|
70
75
|
TEST_SOURCE_FILE,
|
|
71
76
|
CI_APP_ORIGIN,
|
|
72
77
|
LIBRARY_VERSION,
|
|
78
|
+
JEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
79
|
+
JEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
73
80
|
getTestEnvironmentMetadata,
|
|
74
81
|
getTestParametersString,
|
|
75
82
|
finishAllTraceSpans,
|
|
@@ -82,11 +89,12 @@ module.exports = {
|
|
|
82
89
|
getTestModuleCommonTags,
|
|
83
90
|
getTestSuiteCommonTags,
|
|
84
91
|
TEST_COMMAND,
|
|
92
|
+
TEST_TOOLCHAIN,
|
|
85
93
|
TEST_SESSION_ID,
|
|
86
94
|
TEST_MODULE_ID,
|
|
87
95
|
TEST_SUITE_ID,
|
|
88
96
|
TEST_ITR_TESTS_SKIPPED,
|
|
89
|
-
|
|
97
|
+
TEST_MODULE,
|
|
90
98
|
TEST_SESSION_ITR_SKIPPING_ENABLED,
|
|
91
99
|
TEST_SESSION_CODE_COVERAGE_ENABLED,
|
|
92
100
|
TEST_MODULE_ITR_SKIPPING_ENABLED,
|
|
@@ -99,6 +107,15 @@ module.exports = {
|
|
|
99
107
|
fromCoverageMapToCoverage
|
|
100
108
|
}
|
|
101
109
|
|
|
110
|
+
// Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
|
|
111
|
+
function getPkgManager () {
|
|
112
|
+
try {
|
|
113
|
+
return process.env.npm_config_user_agent.split(' ')[0].replace('/', '-')
|
|
114
|
+
} catch (e) {
|
|
115
|
+
return ''
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
102
119
|
function getTestEnvironmentMetadata (testFramework, config) {
|
|
103
120
|
// TODO: eventually these will come from the tracer (generally available)
|
|
104
121
|
const ciMetadata = getCIMetadata()
|
|
@@ -261,28 +278,30 @@ function getTestLevelCommonTags (command, testFrameworkVersion) {
|
|
|
261
278
|
}
|
|
262
279
|
}
|
|
263
280
|
|
|
264
|
-
function getTestSessionCommonTags (command, testFrameworkVersion) {
|
|
281
|
+
function getTestSessionCommonTags (command, testFrameworkVersion, testFramework) {
|
|
265
282
|
return {
|
|
266
283
|
[SPAN_TYPE]: 'test_session_end',
|
|
267
284
|
[RESOURCE_NAME]: `test_session.${command}`,
|
|
285
|
+
[TEST_MODULE]: testFramework,
|
|
286
|
+
[TEST_TOOLCHAIN]: getPkgManager(),
|
|
268
287
|
...getTestLevelCommonTags(command, testFrameworkVersion)
|
|
269
288
|
}
|
|
270
289
|
}
|
|
271
290
|
|
|
272
|
-
function getTestModuleCommonTags (command, testFrameworkVersion) {
|
|
291
|
+
function getTestModuleCommonTags (command, testFrameworkVersion, testFramework) {
|
|
273
292
|
return {
|
|
274
293
|
[SPAN_TYPE]: 'test_module_end',
|
|
275
294
|
[RESOURCE_NAME]: `test_module.${command}`,
|
|
276
|
-
[
|
|
295
|
+
[TEST_MODULE]: testFramework,
|
|
277
296
|
...getTestLevelCommonTags(command, testFrameworkVersion)
|
|
278
297
|
}
|
|
279
298
|
}
|
|
280
299
|
|
|
281
|
-
function getTestSuiteCommonTags (command, testFrameworkVersion, testSuite) {
|
|
300
|
+
function getTestSuiteCommonTags (command, testFrameworkVersion, testSuite, testFramework) {
|
|
282
301
|
return {
|
|
283
302
|
[SPAN_TYPE]: 'test_suite_end',
|
|
284
303
|
[RESOURCE_NAME]: `test_suite.${testSuite}`,
|
|
285
|
-
[
|
|
304
|
+
[TEST_MODULE]: testFramework,
|
|
286
305
|
[TEST_SUITE]: testSuite,
|
|
287
306
|
...getTestLevelCommonTags(command, testFrameworkVersion)
|
|
288
307
|
}
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
const log = require('./log')
|
|
4
4
|
const { profiler } = require('./profiling')
|
|
5
5
|
|
|
6
|
+
// Stop profiler upon exit in order to collect and export the current profile
|
|
7
|
+
process.once('beforeExit', () => { profiler.stop() })
|
|
8
|
+
|
|
6
9
|
module.exports = {
|
|
7
10
|
start: config => {
|
|
8
11
|
const { service, version, env, url, hostname, port, tags } = config
|