dd-trace 4.18.0 → 5.6.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/CONTRIBUTING.md +98 -0
- package/LICENSE-3rdparty.csv +4 -5
- package/MIGRATING.md +15 -0
- package/README.md +20 -140
- package/ci/cypress/after-run.js +1 -0
- package/ci/cypress/after-spec.js +1 -0
- package/ci/init.js +1 -4
- package/ext/kinds.d.ts +1 -0
- package/ext/kinds.js +2 -1
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +6 -1
- package/index.d.ts +1523 -1460
- package/package.json +19 -19
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-core/src/utils/src/get.js +11 -0
- package/packages/datadog-core/src/utils/src/has.js +14 -0
- package/packages/datadog-core/src/utils/src/kebabcase.js +16 -0
- package/packages/datadog-core/src/utils/src/pick.js +11 -0
- package/packages/datadog-core/src/utils/src/set.js +16 -0
- package/packages/datadog-core/src/utils/src/uniq.js +5 -0
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/amqplib.js +2 -2
- package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
- package/packages/datadog-instrumentations/src/child_process.js +150 -0
- package/packages/datadog-instrumentations/src/couchbase.js +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +163 -46
- package/packages/datadog-instrumentations/src/dns.js +2 -1
- package/packages/datadog-instrumentations/src/express.js +20 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/grpc/client.js +56 -36
- package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/http/server.js +7 -4
- package/packages/datadog-instrumentations/src/http2/client.js +3 -1
- package/packages/datadog-instrumentations/src/http2/server.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +239 -52
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/mocha.js +154 -18
- package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
- package/packages/datadog-instrumentations/src/mongoose.js +23 -10
- package/packages/datadog-instrumentations/src/mquery.js +65 -0
- package/packages/datadog-instrumentations/src/net.js +10 -2
- package/packages/datadog-instrumentations/src/next.js +35 -9
- package/packages/datadog-instrumentations/src/playwright.js +110 -16
- package/packages/datadog-instrumentations/src/restify.js +14 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- package/packages/datadog-plugin-aerospike/src/index.js +113 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +13 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +163 -27
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +46 -8
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +129 -22
- package/packages/datadog-plugin-child_process/src/index.js +91 -0
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +125 -0
- package/packages/datadog-plugin-cucumber/src/index.js +70 -13
- package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
- package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -454
- package/packages/datadog-plugin-cypress/src/support.js +50 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
- package/packages/datadog-plugin-graphql/src/index.js +1 -6
- package/packages/datadog-plugin-graphql/src/resolve.js +28 -18
- package/packages/datadog-plugin-grpc/src/client.js +16 -2
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-jest/src/index.js +118 -12
- package/packages/datadog-plugin-jest/src/util.js +38 -16
- package/packages/datadog-plugin-kafkajs/src/consumer.js +76 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -8
- package/packages/datadog-plugin-mocha/src/index.js +87 -17
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/datadog-plugin-playwright/src/index.js +71 -8
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -1
- package/packages/datadog-plugin-rhea/src/producer.js +10 -0
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +5 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +61 -0
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
- package/packages/dd-trace/src/appsec/blocking.js +95 -43
- package/packages/dd-trace/src/appsec/channels.js +7 -3
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -28
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +10 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
- package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +13 -2
- package/packages/dd-trace/src/appsec/iast/index.js +15 -5
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +10 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +19 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +41 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
- package/packages/dd-trace/src/appsec/index.js +49 -33
- package/packages/dd-trace/src/appsec/recommended.json +1763 -106
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +42 -16
- package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
- package/packages/dd-trace/src/appsec/reporter.js +51 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +11 -8
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
- package/packages/dd-trace/src/ci-visibility/{intelligent-test-runner/get-itr-configuration.js → early-flake-detection/get-known-tests.js} +17 -22
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +25 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +95 -37
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +134 -61
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +37 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +131 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
- package/packages/dd-trace/src/config.js +561 -470
- package/packages/dd-trace/src/data_streams_context.js +1 -1
- package/packages/dd-trace/src/datastreams/pathway.js +58 -1
- package/packages/dd-trace/src/datastreams/processor.js +196 -27
- package/packages/dd-trace/src/datastreams/writer.js +11 -5
- package/packages/dd-trace/src/dogstatsd.js +3 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -6
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
- package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
- package/packages/dd-trace/src/exporters/common/request.js +21 -3
- package/packages/dd-trace/src/format.js +30 -2
- package/packages/dd-trace/src/id.js +12 -0
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +1 -1
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +104 -4
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +16 -7
- package/packages/dd-trace/src/opentracing/span.js +48 -4
- package/packages/dd-trace/src/opentracing/span_context.js +15 -6
- package/packages/dd-trace/src/opentracing/tracer.js +4 -3
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +78 -19
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +7 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +6 -19
- package/packages/dd-trace/src/plugins/util/git.js +104 -22
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +60 -10
- package/packages/dd-trace/src/plugins/util/url.js +26 -0
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +30 -38
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +77 -24
- package/packages/dd-trace/src/profiling/exporters/agent.js +77 -31
- package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
- package/packages/dd-trace/src/profiling/profiler.js +33 -22
- package/packages/dd-trace/src/profiling/profilers/events.js +270 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +45 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +18 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +146 -70
- package/packages/dd-trace/src/proxy.js +56 -24
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/sampling_rule.js +130 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/span_processor.js +9 -1
- package/packages/dd-trace/src/span_sampler.js +6 -64
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/startup-log.js +7 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
- package/packages/dd-trace/src/telemetry/index.js +182 -53
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +65 -7
- package/packages/dd-trace/src/tracer.js +12 -5
- package/register.js +4 -0
- package/scripts/install_plugin_modules.js +11 -3
- package/scripts/st.js +105 -0
- package/packages/datadog-instrumentations/src/child-process.js +0 -30
- package/packages/dd-trace/src/plugins/util/exec.js +0 -13
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -15,11 +15,20 @@ const {
|
|
|
15
15
|
TEST_MODULE,
|
|
16
16
|
getTestSuiteCommonTags,
|
|
17
17
|
TEST_STATUS,
|
|
18
|
-
TEST_SKIPPED_BY_ITR
|
|
18
|
+
TEST_SKIPPED_BY_ITR,
|
|
19
|
+
ITR_CORRELATION_ID
|
|
19
20
|
} = require('./util/test')
|
|
20
21
|
const Plugin = require('./plugin')
|
|
21
22
|
const { COMPONENT } = require('../constants')
|
|
22
23
|
const log = require('../log')
|
|
24
|
+
const {
|
|
25
|
+
incrementCountMetric,
|
|
26
|
+
distributionMetric,
|
|
27
|
+
TELEMETRY_EVENT_CREATED,
|
|
28
|
+
TELEMETRY_ITR_SKIPPED
|
|
29
|
+
} = require('../ci-visibility/telemetry')
|
|
30
|
+
const { CI_PROVIDER_NAME, GIT_REPOSITORY_URL, GIT_COMMIT_SHA, GIT_BRANCH, CI_WORKSPACE_PATH } = require('./util/tags')
|
|
31
|
+
const { OS_VERSION, OS_PLATFORM, OS_ARCHITECTURE, RUNTIME_NAME, RUNTIME_VERSION } = require('./util/env')
|
|
23
32
|
|
|
24
33
|
module.exports = class CiPlugin extends Plugin {
|
|
25
34
|
constructor (...args) {
|
|
@@ -27,29 +36,31 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
27
36
|
|
|
28
37
|
this.rootDir = process.cwd() // fallback in case :session:start events are not emitted
|
|
29
38
|
|
|
30
|
-
this.addSub(`ci:${this.constructor.id}:
|
|
31
|
-
if (!this.tracer._exporter || !this.tracer._exporter.
|
|
39
|
+
this.addSub(`ci:${this.constructor.id}:library-configuration`, ({ onDone }) => {
|
|
40
|
+
if (!this.tracer._exporter || !this.tracer._exporter.getLibraryConfiguration) {
|
|
32
41
|
return onDone({ err: new Error('CI Visibility was not initialized correctly') })
|
|
33
42
|
}
|
|
34
|
-
this.tracer._exporter.
|
|
43
|
+
this.tracer._exporter.getLibraryConfiguration(this.testConfiguration, (err, libraryConfig) => {
|
|
35
44
|
if (err) {
|
|
36
45
|
log.error(`Intelligent Test Runner configuration could not be fetched. ${err.message}`)
|
|
37
46
|
} else {
|
|
38
|
-
this.
|
|
47
|
+
this.libraryConfig = libraryConfig
|
|
39
48
|
}
|
|
40
|
-
onDone({ err,
|
|
49
|
+
onDone({ err, libraryConfig })
|
|
41
50
|
})
|
|
42
51
|
})
|
|
43
52
|
|
|
44
53
|
this.addSub(`ci:${this.constructor.id}:test-suite:skippable`, ({ onDone }) => {
|
|
45
|
-
if (!this.tracer._exporter
|
|
54
|
+
if (!this.tracer._exporter?.getSkippableSuites) {
|
|
46
55
|
return onDone({ err: new Error('CI Visibility was not initialized correctly') })
|
|
47
56
|
}
|
|
48
|
-
this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
|
|
57
|
+
this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites, itrCorrelationId) => {
|
|
49
58
|
if (err) {
|
|
50
59
|
log.error(`Skippable suites could not be fetched. ${err.message}`)
|
|
60
|
+
} else {
|
|
61
|
+
this.itrCorrelationId = itrCorrelationId
|
|
51
62
|
}
|
|
52
|
-
onDone({ err, skippableSuites })
|
|
63
|
+
onDone({ err, skippableSuites, itrCorrelationId })
|
|
53
64
|
})
|
|
54
65
|
})
|
|
55
66
|
|
|
@@ -71,6 +82,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
71
82
|
...testSessionSpanMetadata
|
|
72
83
|
}
|
|
73
84
|
})
|
|
85
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'session')
|
|
74
86
|
this.testModuleSpan = this.tracer.startSpan(`${this.constructor.id}.test_module`, {
|
|
75
87
|
childOf: this.testSessionSpan,
|
|
76
88
|
tags: {
|
|
@@ -79,12 +91,16 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
79
91
|
...testModuleSpanMetadata
|
|
80
92
|
}
|
|
81
93
|
})
|
|
94
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
|
|
82
95
|
})
|
|
83
96
|
|
|
84
97
|
this.addSub(`ci:${this.constructor.id}:itr:skipped-suites`, ({ skippedSuites, frameworkVersion }) => {
|
|
85
98
|
const testCommand = this.testSessionSpan.context()._tags[TEST_COMMAND]
|
|
86
99
|
skippedSuites.forEach((testSuite) => {
|
|
87
100
|
const testSuiteMetadata = getTestSuiteCommonTags(testCommand, frameworkVersion, testSuite, this.constructor.id)
|
|
101
|
+
if (this.itrCorrelationId) {
|
|
102
|
+
testSuiteMetadata[ITR_CORRELATION_ID] = this.itrCorrelationId
|
|
103
|
+
}
|
|
88
104
|
|
|
89
105
|
this.tracer.startSpan(`${this.constructor.id}.test_suite`, {
|
|
90
106
|
childOf: this.testModuleSpan,
|
|
@@ -97,25 +113,65 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
97
113
|
}
|
|
98
114
|
}).finish()
|
|
99
115
|
})
|
|
116
|
+
this.telemetry.count(TELEMETRY_ITR_SKIPPED, { testLevel: 'suite' }, skippedSuites.length)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
this.addSub(`ci:${this.constructor.id}:known-tests`, ({ onDone }) => {
|
|
120
|
+
if (!this.tracer._exporter?.getKnownTests) {
|
|
121
|
+
return onDone({ err: new Error('CI Visibility was not initialized correctly') })
|
|
122
|
+
}
|
|
123
|
+
this.tracer._exporter.getKnownTests(this.testConfiguration, (err, knownTests) => {
|
|
124
|
+
if (err) {
|
|
125
|
+
log.error(`Known tests could not be fetched. ${err.message}`)
|
|
126
|
+
}
|
|
127
|
+
onDone({ err, knownTests })
|
|
128
|
+
})
|
|
100
129
|
})
|
|
101
130
|
}
|
|
102
131
|
|
|
132
|
+
get telemetry () {
|
|
133
|
+
const testFramework = this.constructor.id
|
|
134
|
+
return {
|
|
135
|
+
ciVisEvent: function (name, testLevel, tags = {}) {
|
|
136
|
+
incrementCountMetric(name, {
|
|
137
|
+
testLevel,
|
|
138
|
+
testFramework,
|
|
139
|
+
isUnsupportedCIProvider: this.isUnsupportedCIProvider,
|
|
140
|
+
...tags
|
|
141
|
+
})
|
|
142
|
+
},
|
|
143
|
+
count: function (name, tags, value = 1) {
|
|
144
|
+
incrementCountMetric(name, tags, value)
|
|
145
|
+
},
|
|
146
|
+
distribution: function (name, tags, measure) {
|
|
147
|
+
distributionMetric(name, tags, measure)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
103
152
|
configure (config) {
|
|
104
153
|
super.configure(config)
|
|
105
154
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
|
|
106
|
-
this.codeOwnersEntries = getCodeOwnersFileEntries()
|
|
107
155
|
|
|
108
156
|
const {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
157
|
+
[GIT_REPOSITORY_URL]: repositoryUrl,
|
|
158
|
+
[GIT_COMMIT_SHA]: sha,
|
|
159
|
+
[OS_VERSION]: osVersion,
|
|
160
|
+
[OS_PLATFORM]: osPlatform,
|
|
161
|
+
[OS_ARCHITECTURE]: osArchitecture,
|
|
162
|
+
[RUNTIME_NAME]: runtimeName,
|
|
163
|
+
[RUNTIME_VERSION]: runtimeVersion,
|
|
164
|
+
[GIT_BRANCH]: branch,
|
|
165
|
+
[CI_PROVIDER_NAME]: ciProviderName,
|
|
166
|
+
[CI_WORKSPACE_PATH]: repositoryRoot
|
|
117
167
|
} = this.testEnvironmentMetadata
|
|
118
168
|
|
|
169
|
+
this.repositoryRoot = repositoryRoot || process.cwd()
|
|
170
|
+
|
|
171
|
+
this.codeOwnersEntries = getCodeOwnersFileEntries(repositoryRoot)
|
|
172
|
+
|
|
173
|
+
this.isUnsupportedCIProvider = !ciProviderName
|
|
174
|
+
|
|
119
175
|
this.testConfiguration = {
|
|
120
176
|
repositoryUrl,
|
|
121
177
|
sha,
|
|
@@ -124,7 +180,8 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
124
180
|
osArchitecture,
|
|
125
181
|
runtimeName,
|
|
126
182
|
runtimeVersion,
|
|
127
|
-
branch
|
|
183
|
+
branch,
|
|
184
|
+
testLevel: 'suite'
|
|
128
185
|
}
|
|
129
186
|
}
|
|
130
187
|
|
|
@@ -169,6 +226,8 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
169
226
|
}
|
|
170
227
|
}
|
|
171
228
|
|
|
229
|
+
this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'test', { hasCodeOwners: !!codeOwners })
|
|
230
|
+
|
|
172
231
|
const testSpan = this.tracer
|
|
173
232
|
.startSpan(`${this.constructor.id}.test`, {
|
|
174
233
|
childOf,
|
|
@@ -36,7 +36,7 @@ class DatabasePlugin extends StoragePlugin {
|
|
|
36
36
|
const { encodedDddbs, encodedDde, encodedDdps, encodedDdpv } = this.serviceTags
|
|
37
37
|
|
|
38
38
|
return `dddbs='${encodedDddbs}',dde='${encodedDde}',` +
|
|
39
|
-
|
|
39
|
+
`ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
getDbmServiceName (span, tracerService) {
|
|
@@ -17,11 +17,13 @@ module.exports = {
|
|
|
17
17
|
get '@opensearch-project/opensearch' () { return require('../../../datadog-plugin-opensearch/src') },
|
|
18
18
|
get '@redis/client' () { return require('../../../datadog-plugin-redis/src') },
|
|
19
19
|
get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
20
|
+
get 'aerospike' () { return require('../../../datadog-plugin-aerospike/src') },
|
|
20
21
|
get 'amqp10' () { return require('../../../datadog-plugin-amqp10/src') },
|
|
21
22
|
get 'amqplib' () { return require('../../../datadog-plugin-amqplib/src') },
|
|
22
23
|
get 'aws-sdk' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
23
24
|
get 'bunyan' () { return require('../../../datadog-plugin-bunyan/src') },
|
|
24
25
|
get 'cassandra-driver' () { return require('../../../datadog-plugin-cassandra-driver/src') },
|
|
26
|
+
get 'child_process' () { return require('../../../datadog-plugin-child_process/src') },
|
|
25
27
|
get 'connect' () { return require('../../../datadog-plugin-connect/src') },
|
|
26
28
|
get 'couchbase' () { return require('../../../datadog-plugin-couchbase/src') },
|
|
27
29
|
get 'cypress' () { return require('../../../datadog-plugin-cypress/src') },
|
|
@@ -58,6 +60,11 @@ module.exports = {
|
|
|
58
60
|
get 'mysql2' () { return require('../../../datadog-plugin-mysql2/src') },
|
|
59
61
|
get 'net' () { return require('../../../datadog-plugin-net/src') },
|
|
60
62
|
get 'next' () { return require('../../../datadog-plugin-next/src') },
|
|
63
|
+
get 'node:dns' () { return require('../../../datadog-plugin-dns/src') },
|
|
64
|
+
get 'node:http' () { return require('../../../datadog-plugin-http/src') },
|
|
65
|
+
get 'node:http2' () { return require('../../../datadog-plugin-http2/src') },
|
|
66
|
+
get 'node:https' () { return require('../../../datadog-plugin-http/src') },
|
|
67
|
+
get 'node:net' () { return require('../../../datadog-plugin-net/src') },
|
|
61
68
|
get 'oracledb' () { return require('../../../datadog-plugin-oracledb/src') },
|
|
62
69
|
get 'openai' () { return require('../../../datadog-plugin-openai/src') },
|
|
63
70
|
get 'paperplane' () { return require('../../../datadog-plugin-paperplane/src') },
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const URL = require('url').URL
|
|
2
|
-
|
|
3
1
|
const {
|
|
4
2
|
GIT_BRANCH,
|
|
5
3
|
GIT_COMMIT_SHA,
|
|
@@ -24,6 +22,7 @@ const {
|
|
|
24
22
|
CI_NODE_LABELS,
|
|
25
23
|
CI_NODE_NAME
|
|
26
24
|
} = require('./tags')
|
|
25
|
+
const { filterSensitiveInfoFromRepository } = require('./url')
|
|
27
26
|
|
|
28
27
|
// Receives a string with the form 'John Doe <john.doe@gmail.com>'
|
|
29
28
|
// and returns { name: 'John Doe', email: 'john.doe@gmail.com' }
|
|
@@ -67,20 +66,6 @@ function normalizeRef (ref) {
|
|
|
67
66
|
return ref.replace(/origin\/|refs\/heads\/|tags\//gm, '')
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
function filterSensitiveInfoFromRepository (repositoryUrl) {
|
|
71
|
-
if (repositoryUrl.startsWith('git@')) {
|
|
72
|
-
return repositoryUrl
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const { protocol, hostname, pathname } = new URL(repositoryUrl)
|
|
77
|
-
|
|
78
|
-
return `${protocol}//${hostname}${pathname}`
|
|
79
|
-
} catch (e) {
|
|
80
|
-
return ''
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
69
|
function resolveTilde (filePath) {
|
|
85
70
|
if (!filePath || typeof filePath !== 'string') {
|
|
86
71
|
return ''
|
|
@@ -271,20 +256,22 @@ module.exports = {
|
|
|
271
256
|
const ref = GITHUB_HEAD_REF || GITHUB_REF || ''
|
|
272
257
|
const refKey = ref.includes('tags/') ? GIT_TAG : GIT_BRANCH
|
|
273
258
|
|
|
259
|
+
// Both pipeline URL and job URL include GITHUB_SERVER_URL, which can include user credentials,
|
|
260
|
+
// so we pass them through `filterSensitiveInfoFromRepository`.
|
|
274
261
|
tags = {
|
|
275
262
|
[CI_PIPELINE_ID]: GITHUB_RUN_ID,
|
|
276
263
|
[CI_PIPELINE_NAME]: GITHUB_WORKFLOW,
|
|
277
264
|
[CI_PIPELINE_NUMBER]: GITHUB_RUN_NUMBER,
|
|
278
|
-
[CI_PIPELINE_URL]: pipelineURL,
|
|
265
|
+
[CI_PIPELINE_URL]: filterSensitiveInfoFromRepository(pipelineURL),
|
|
279
266
|
[CI_PROVIDER_NAME]: 'github',
|
|
280
267
|
[GIT_COMMIT_SHA]: GITHUB_SHA,
|
|
281
268
|
[GIT_REPOSITORY_URL]: repositoryURL,
|
|
282
|
-
[CI_JOB_URL]: jobUrl,
|
|
269
|
+
[CI_JOB_URL]: filterSensitiveInfoFromRepository(jobUrl),
|
|
283
270
|
[CI_JOB_NAME]: GITHUB_JOB,
|
|
284
271
|
[CI_WORKSPACE_PATH]: GITHUB_WORKSPACE,
|
|
285
272
|
[refKey]: ref,
|
|
286
273
|
[CI_ENV_VARS]: JSON.stringify({
|
|
287
|
-
GITHUB_SERVER_URL,
|
|
274
|
+
GITHUB_SERVER_URL: filterSensitiveInfoFromRepository(GITHUB_SERVER_URL),
|
|
288
275
|
GITHUB_REPOSITORY,
|
|
289
276
|
GITHUB_RUN_ID,
|
|
290
277
|
GITHUB_RUN_ATTEMPT
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const cp = require('child_process')
|
|
2
2
|
const os = require('os')
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const fs = require('fs')
|
|
5
5
|
|
|
6
6
|
const log = require('../../log')
|
|
7
|
-
const { sanitizedExec } = require('./exec')
|
|
8
7
|
const {
|
|
9
8
|
GIT_COMMIT_SHA,
|
|
10
9
|
GIT_BRANCH,
|
|
@@ -19,9 +18,52 @@ const {
|
|
|
19
18
|
GIT_COMMIT_AUTHOR_NAME,
|
|
20
19
|
CI_WORKSPACE_PATH
|
|
21
20
|
} = require('./tags')
|
|
21
|
+
const {
|
|
22
|
+
incrementCountMetric,
|
|
23
|
+
distributionMetric,
|
|
24
|
+
TELEMETRY_GIT_COMMAND,
|
|
25
|
+
TELEMETRY_GIT_COMMAND_MS,
|
|
26
|
+
TELEMETRY_GIT_COMMAND_ERRORS
|
|
27
|
+
} = require('../../ci-visibility/telemetry')
|
|
28
|
+
const { filterSensitiveInfoFromRepository } = require('./url')
|
|
29
|
+
const { storage } = require('../../../../datadog-core')
|
|
22
30
|
|
|
23
31
|
const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB
|
|
24
32
|
|
|
33
|
+
function sanitizedExec (
|
|
34
|
+
cmd,
|
|
35
|
+
flags,
|
|
36
|
+
operationMetric,
|
|
37
|
+
durationMetric,
|
|
38
|
+
errorMetric
|
|
39
|
+
) {
|
|
40
|
+
const store = storage.getStore()
|
|
41
|
+
storage.enterWith({ noop: true })
|
|
42
|
+
|
|
43
|
+
let startTime
|
|
44
|
+
if (operationMetric) {
|
|
45
|
+
incrementCountMetric(operationMetric.name, operationMetric.tags)
|
|
46
|
+
}
|
|
47
|
+
if (durationMetric) {
|
|
48
|
+
startTime = Date.now()
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const result = cp.execFileSync(cmd, flags, { stdio: 'pipe' }).toString().replace(/(\r\n|\n|\r)/gm, '')
|
|
52
|
+
if (durationMetric) {
|
|
53
|
+
distributionMetric(durationMetric.name, durationMetric.tags, Date.now() - startTime)
|
|
54
|
+
}
|
|
55
|
+
return result
|
|
56
|
+
} catch (e) {
|
|
57
|
+
if (errorMetric) {
|
|
58
|
+
incrementCountMetric(errorMetric.name, { ...errorMetric.tags, exitCode: e.status })
|
|
59
|
+
}
|
|
60
|
+
log.error(e)
|
|
61
|
+
return ''
|
|
62
|
+
} finally {
|
|
63
|
+
storage.enterWith(store)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
25
67
|
function isDirectory (path) {
|
|
26
68
|
try {
|
|
27
69
|
const stats = fs.statSync(path)
|
|
@@ -32,7 +74,13 @@ function isDirectory (path) {
|
|
|
32
74
|
}
|
|
33
75
|
|
|
34
76
|
function isShallowRepository () {
|
|
35
|
-
return sanitizedExec(
|
|
77
|
+
return sanitizedExec(
|
|
78
|
+
'git',
|
|
79
|
+
['rev-parse', '--is-shallow-repository'],
|
|
80
|
+
{ name: TELEMETRY_GIT_COMMAND, tags: { command: 'check_shallow' } },
|
|
81
|
+
{ name: TELEMETRY_GIT_COMMAND_MS, tags: { command: 'check_shallow' } },
|
|
82
|
+
{ name: TELEMETRY_GIT_COMMAND_ERRORS, tags: { command: 'check_shallow' } }
|
|
83
|
+
) === 'true'
|
|
36
84
|
}
|
|
37
85
|
|
|
38
86
|
function getGitVersion () {
|
|
@@ -71,50 +119,76 @@ function unshallowRepository () {
|
|
|
71
119
|
defaultRemoteName
|
|
72
120
|
]
|
|
73
121
|
|
|
122
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'unshallow' })
|
|
123
|
+
const start = Date.now()
|
|
74
124
|
try {
|
|
75
|
-
execFileSync('git', [
|
|
125
|
+
cp.execFileSync('git', [
|
|
76
126
|
...baseGitOptions,
|
|
77
127
|
revParseHead
|
|
78
128
|
], { stdio: 'pipe' })
|
|
79
|
-
} catch (
|
|
129
|
+
} catch (err) {
|
|
80
130
|
// If the local HEAD is a commit that has not been pushed to the remote, the above command will fail.
|
|
81
|
-
log.error(
|
|
131
|
+
log.error(err)
|
|
132
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'unshallow', exitCode: err.status })
|
|
82
133
|
const upstreamRemote = sanitizedExec('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'])
|
|
83
134
|
try {
|
|
84
|
-
execFileSync('git', [
|
|
135
|
+
cp.execFileSync('git', [
|
|
85
136
|
...baseGitOptions,
|
|
86
137
|
upstreamRemote
|
|
87
138
|
], { stdio: 'pipe' })
|
|
88
|
-
} catch (
|
|
139
|
+
} catch (err) {
|
|
89
140
|
// If the CI is working on a detached HEAD or branch tracking hasn’t been set up, the above command will fail.
|
|
90
|
-
log.error(
|
|
141
|
+
log.error(err)
|
|
142
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'unshallow', exitCode: err.status })
|
|
91
143
|
// We use sanitizedExec here because if this last option fails, we'll give up.
|
|
92
|
-
sanitizedExec(
|
|
144
|
+
sanitizedExec(
|
|
145
|
+
'git',
|
|
146
|
+
baseGitOptions,
|
|
147
|
+
null,
|
|
148
|
+
null,
|
|
149
|
+
{ name: TELEMETRY_GIT_COMMAND_ERRORS, tags: { command: 'unshallow' } } // we log the error in sanitizedExec
|
|
150
|
+
)
|
|
93
151
|
}
|
|
94
152
|
}
|
|
153
|
+
distributionMetric(TELEMETRY_GIT_COMMAND_MS, { command: 'unshallow' }, Date.now() - start)
|
|
95
154
|
}
|
|
96
155
|
|
|
97
156
|
function getRepositoryUrl () {
|
|
98
|
-
return sanitizedExec(
|
|
157
|
+
return sanitizedExec(
|
|
158
|
+
'git',
|
|
159
|
+
['config', '--get', 'remote.origin.url'],
|
|
160
|
+
{ name: TELEMETRY_GIT_COMMAND, tags: { command: 'get_repository' } },
|
|
161
|
+
{ name: TELEMETRY_GIT_COMMAND_MS, tags: { command: 'get_repository' } },
|
|
162
|
+
{ name: TELEMETRY_GIT_COMMAND_ERRORS, tags: { command: 'get_repository' } }
|
|
163
|
+
)
|
|
99
164
|
}
|
|
100
165
|
|
|
101
166
|
function getLatestCommits () {
|
|
167
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'get_local_commits' })
|
|
168
|
+
const startTime = Date.now()
|
|
102
169
|
try {
|
|
103
|
-
|
|
170
|
+
const result = cp.execFileSync('git', ['log', '--format=%H', '-n 1000', '--since="1 month ago"'], { stdio: 'pipe' })
|
|
104
171
|
.toString()
|
|
105
172
|
.split('\n')
|
|
106
173
|
.filter(commit => commit)
|
|
174
|
+
distributionMetric(TELEMETRY_GIT_COMMAND_MS, { command: 'get_local_commits' }, Date.now() - startTime)
|
|
175
|
+
return result
|
|
107
176
|
} catch (err) {
|
|
108
177
|
log.error(`Get latest commits failed: ${err.message}`)
|
|
178
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'get_local_commits', errorType: err.status })
|
|
109
179
|
return []
|
|
110
180
|
}
|
|
111
181
|
}
|
|
112
182
|
|
|
113
|
-
function
|
|
183
|
+
function getCommitsRevList (commitsToExclude, commitsToInclude) {
|
|
184
|
+
let result = []
|
|
185
|
+
|
|
114
186
|
const commitsToExcludeString = commitsToExclude.map(commit => `^${commit}`)
|
|
115
187
|
|
|
188
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'get_objects' })
|
|
189
|
+
const startTime = Date.now()
|
|
116
190
|
try {
|
|
117
|
-
|
|
191
|
+
result = cp.execFileSync(
|
|
118
192
|
'git',
|
|
119
193
|
[
|
|
120
194
|
'rev-list',
|
|
@@ -131,11 +205,14 @@ function getCommitsToUpload (commitsToExclude, commitsToInclude) {
|
|
|
131
205
|
.filter(commit => commit)
|
|
132
206
|
} catch (err) {
|
|
133
207
|
log.error(`Get commits to upload failed: ${err.message}`)
|
|
134
|
-
|
|
208
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'get_objects', errorType: err.status })
|
|
135
209
|
}
|
|
210
|
+
distributionMetric(TELEMETRY_GIT_COMMAND_MS, { command: 'get_objects' }, Date.now() - startTime)
|
|
211
|
+
return result
|
|
136
212
|
}
|
|
137
213
|
|
|
138
214
|
function generatePackFilesForCommits (commitsToUpload) {
|
|
215
|
+
let result = []
|
|
139
216
|
const tmpFolder = os.tmpdir()
|
|
140
217
|
|
|
141
218
|
if (!isDirectory(tmpFolder)) {
|
|
@@ -147,10 +224,12 @@ function generatePackFilesForCommits (commitsToUpload) {
|
|
|
147
224
|
const temporaryPath = path.join(tmpFolder, randomPrefix)
|
|
148
225
|
const cwdPath = path.join(process.cwd(), randomPrefix)
|
|
149
226
|
|
|
227
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'pack_objects' })
|
|
228
|
+
const startTime = Date.now()
|
|
150
229
|
// Generates pack files to upload and
|
|
151
230
|
// returns the ordered list of packfiles' paths
|
|
152
231
|
function execGitPackObjects (targetPath) {
|
|
153
|
-
return execFileSync(
|
|
232
|
+
return cp.execFileSync(
|
|
154
233
|
'git',
|
|
155
234
|
[
|
|
156
235
|
'pack-objects',
|
|
@@ -163,9 +242,10 @@ function generatePackFilesForCommits (commitsToUpload) {
|
|
|
163
242
|
}
|
|
164
243
|
|
|
165
244
|
try {
|
|
166
|
-
|
|
245
|
+
result = execGitPackObjects(temporaryPath)
|
|
167
246
|
} catch (err) {
|
|
168
247
|
log.error(err)
|
|
248
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'pack_objects', errorType: err.status })
|
|
169
249
|
/**
|
|
170
250
|
* The generation of pack files in the temporary folder (from `os.tmpdir()`)
|
|
171
251
|
* sometimes fails in certain CI setups with the error message
|
|
@@ -179,13 +259,15 @@ function generatePackFilesForCommits (commitsToUpload) {
|
|
|
179
259
|
* TODO: fix issue and remove workaround.
|
|
180
260
|
*/
|
|
181
261
|
try {
|
|
182
|
-
|
|
262
|
+
result = execGitPackObjects(cwdPath)
|
|
183
263
|
} catch (err) {
|
|
184
264
|
log.error(err)
|
|
265
|
+
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'pack_objects', errorType: err.status })
|
|
185
266
|
}
|
|
186
|
-
|
|
187
|
-
return []
|
|
188
267
|
}
|
|
268
|
+
distributionMetric(TELEMETRY_GIT_COMMAND_MS, { command: 'pack_objects' }, Date.now() - startTime)
|
|
269
|
+
|
|
270
|
+
return result
|
|
189
271
|
}
|
|
190
272
|
|
|
191
273
|
// If there is ciMetadata, it takes precedence.
|
|
@@ -214,7 +296,7 @@ function getGitMetadata (ciMetadata) {
|
|
|
214
296
|
|
|
215
297
|
return {
|
|
216
298
|
[GIT_REPOSITORY_URL]:
|
|
217
|
-
repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url']),
|
|
299
|
+
filterSensitiveInfoFromRepository(repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url'])),
|
|
218
300
|
[GIT_COMMIT_MESSAGE]:
|
|
219
301
|
commitMessage || sanitizedExec('git', ['show', '-s', '--format=%s']),
|
|
220
302
|
[GIT_COMMIT_AUTHOR_DATE]: authorDate,
|
|
@@ -235,7 +317,7 @@ module.exports = {
|
|
|
235
317
|
getLatestCommits,
|
|
236
318
|
getRepositoryUrl,
|
|
237
319
|
generatePackFilesForCommits,
|
|
238
|
-
|
|
320
|
+
getCommitsRevList,
|
|
239
321
|
GIT_REV_LIST_MAX_BUFFER,
|
|
240
322
|
isShallowRepository,
|
|
241
323
|
unshallowRepository
|
|
@@ -48,8 +48,8 @@ function extractIp (config, req) {
|
|
|
48
48
|
|
|
49
49
|
let firstPrivateIp
|
|
50
50
|
if (headers) {
|
|
51
|
-
for (
|
|
52
|
-
const firstIp = findFirstIp(headers[
|
|
51
|
+
for (const ipHeaderName of ipHeaderList) {
|
|
52
|
+
const firstIp = findFirstIp(headers[ipHeaderName])
|
|
53
53
|
|
|
54
54
|
if (firstIp.public) {
|
|
55
55
|
return firstIp.public
|
|
@@ -59,7 +59,7 @@ function extractIp (config, req) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
return firstPrivateIp ||
|
|
62
|
+
return firstPrivateIp || req.socket?.remoteAddress
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function findFirstIp (str) {
|
|
@@ -68,8 +68,8 @@ function findFirstIp (str) {
|
|
|
68
68
|
|
|
69
69
|
const splitted = str.split(',')
|
|
70
70
|
|
|
71
|
-
for (
|
|
72
|
-
const chunk =
|
|
71
|
+
for (const part of splitted) {
|
|
72
|
+
const chunk = part.trim()
|
|
73
73
|
|
|
74
74
|
// TODO: strip port and interface data ?
|
|
75
75
|
|
|
@@ -90,5 +90,6 @@ function findFirstIp (str) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
module.exports = {
|
|
93
|
-
extractIp
|
|
93
|
+
extractIp,
|
|
94
|
+
ipHeaderList
|
|
94
95
|
}
|