newrelic 13.2.1 → 13.3.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/NEWS.md +47 -7
- package/api.js +1 -1
- package/lib/instrumentation/@azure/functions.js +8 -46
- package/lib/instrumentation/core/http-outbound.js +26 -10
- package/lib/instrumentation/core/http.js +20 -118
- package/lib/instrumentations.js +0 -14
- package/lib/otel/logs/index.js +80 -0
- package/lib/otel/metrics/index.js +119 -0
- package/lib/otel/setup-signal.js +37 -0
- package/lib/otel/setup.js +15 -25
- package/lib/otel/{attr-reconciler.js → traces/attr-reconciler.js} +2 -2
- package/lib/otel/{exception-mapping.js → traces/exception-mapping.js} +1 -1
- package/lib/otel/traces/index.js +40 -0
- package/lib/otel/{rules.js → traces/rules.js} +1 -1
- package/lib/otel/{segment-synthesis.js → traces/segment-synthesis.js} +5 -4
- package/lib/otel/{segments → traces/segments}/consumer.js +4 -4
- package/lib/otel/{segments → traces/segments}/database.js +6 -6
- package/lib/otel/{segments → traces/segments}/http-external.js +11 -8
- package/lib/otel/traces/segments/index.js +22 -0
- package/lib/otel/{segments → traces/segments}/internal.js +1 -1
- package/lib/otel/{segments → traces/segments}/producer.js +2 -2
- package/lib/otel/{segments → traces/segments}/server.js +4 -4
- package/lib/otel/{segments → traces/segments}/utils.js +1 -1
- package/lib/otel/{span-processor.js → traces/span-processor.js} +13 -19
- package/lib/otel/{transformation-rules.json → traces/transformation-rules.json} +3 -2
- package/lib/otel/{utils.js → traces/utils.js} +2 -1
- package/lib/serverless/api-gateway.js +1 -1
- package/lib/serverless/aws-lambda.js +7 -68
- package/lib/shim/webframework-shim/middleware.js +1 -1
- package/lib/shimmer.js +1 -1
- package/lib/subscriber-configs.js +2 -1
- package/lib/subscribers/base.js +30 -0
- package/lib/subscribers/elasticsearch/config.js +1 -0
- package/lib/subscribers/mcp-sdk/client-request.js +66 -0
- package/lib/subscribers/mcp-sdk/config.js +13 -75
- package/lib/subscribers/openai/base.js +21 -0
- package/lib/subscribers/openai/chat-responses.js +15 -0
- package/lib/subscribers/openai/chat.js +85 -0
- package/lib/subscribers/openai/client.js +31 -0
- package/lib/subscribers/openai/config.js +85 -0
- package/lib/subscribers/openai/embeddings.js +54 -0
- package/lib/subscribers/openai/utils.js +349 -0
- package/lib/transaction/index.js +158 -56
- package/lib/transaction/trace/segment.js +5 -2
- package/lib/util/urltils.js +158 -192
- package/lib/utilization/common.js +0 -6
- package/package.json +1 -1
- package/lib/instrumentation/openai.js +0 -482
- package/lib/otel/logs/bootstrap-logs.js +0 -84
- package/lib/otel/metrics/bootstrap-metrics.js +0 -117
- package/lib/otel/segments/index.js +0 -22
- package/lib/subscribers/mcp-sdk/client-prompt.js +0 -23
- package/lib/subscribers/mcp-sdk/client-resource.js +0 -24
- package/lib/subscribers/mcp-sdk/client-tool.js +0 -23
- package/lib/subscribers/mcp-sdk/client.js +0 -29
- /package/lib/otel/{constants.js → traces/constants.js} +0 -0
- /package/lib/otel/{sampler.js → traces/sampler.js} +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const defaultLogger = require('#agentlib/logger.js').child({ component: 'opentelemetry-bridge' })
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* SetupSignal is an interface to standardize how we bootstrap OpenTelemetry
|
|
12
|
+
* observability signals within the OTEL bridge. Subclasses are expected to
|
|
13
|
+
* implement their setup in the constructor, and to provide a `.teardown`
|
|
14
|
+
* method that properly cleans up any created resources (i.e. unblocks the
|
|
15
|
+
* parent singleton managed by the OTEL packages from being garbage collected).
|
|
16
|
+
*/
|
|
17
|
+
class SetupSignal {
|
|
18
|
+
agent
|
|
19
|
+
logger
|
|
20
|
+
|
|
21
|
+
coreApi = require('@opentelemetry/api')
|
|
22
|
+
|
|
23
|
+
constructor({ agent, logger = defaultLogger } = {}) {
|
|
24
|
+
if (Object.prototype.toString.call(agent) !== '[object Agent]') {
|
|
25
|
+
throw Error('must provide an instance of the New Relic agent')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.agent = agent
|
|
29
|
+
this.logger = logger
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
teardown() {
|
|
33
|
+
this.logger.warn('teardown method is not implemented')
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = SetupSignal
|
package/lib/otel/setup.js
CHANGED
|
@@ -6,18 +6,17 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const opentelemetry = require('@opentelemetry/api')
|
|
9
|
-
const logsApi = require('@opentelemetry/api-logs')
|
|
10
|
-
const { BasicTracerProvider } = require('@opentelemetry/sdk-trace-base')
|
|
11
9
|
|
|
12
|
-
const
|
|
13
|
-
const
|
|
10
|
+
const SetupLogs = require('./logs/index.js')
|
|
11
|
+
const SetupMetrics = require('./metrics/index.js')
|
|
12
|
+
const SetupTraces = require('./traces/index.js')
|
|
14
13
|
const ContextManager = require('./context-manager')
|
|
15
14
|
const TracePropagator = require('./trace-propagator')
|
|
16
15
|
const defaultLogger = require('../logger').child({ component: 'opentelemetry-bridge' })
|
|
17
16
|
const createOtelLogger = require('./logger')
|
|
18
17
|
const interceptSpanKey = require('./span-key-interceptor')
|
|
19
|
-
|
|
20
|
-
const
|
|
18
|
+
|
|
19
|
+
const signals = []
|
|
21
20
|
|
|
22
21
|
function setupOtel(agent, logger = defaultLogger) {
|
|
23
22
|
if (agent.config.opentelemetry_bridge.enabled !== true) {
|
|
@@ -38,19 +37,22 @@ function setupOtel(agent, logger = defaultLogger) {
|
|
|
38
37
|
opentelemetry.propagation.setGlobalPropagator(new TracePropagator(agent))
|
|
39
38
|
|
|
40
39
|
if (agent.config.opentelemetry_bridge.traces.enabled === true) {
|
|
41
|
-
|
|
40
|
+
const signal = new SetupTraces({ agent })
|
|
41
|
+
signals.push(signal)
|
|
42
42
|
} else {
|
|
43
43
|
logger.debug('`opentelemetry_bridge.traces` is not enabled, skipping')
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if (agent.config.opentelemetry_bridge.metrics.enabled === true) {
|
|
47
|
-
|
|
47
|
+
const signal = new SetupMetrics({ agent })
|
|
48
|
+
signals.push(signal)
|
|
48
49
|
} else {
|
|
49
50
|
logger.debug('`opentelemetry_bridge.metrics` is not enabled, skipping')
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
if (agent.config.opentelemetry_bridge.logs.enabled === true) {
|
|
53
|
-
|
|
54
|
+
const signal = new SetupLogs({ agent })
|
|
55
|
+
signals.push(signal)
|
|
54
56
|
} else {
|
|
55
57
|
logger.debug('`opentelemetry_bridge.logs` is not enabled, skipping')
|
|
56
58
|
}
|
|
@@ -60,30 +62,18 @@ function setupOtel(agent, logger = defaultLogger) {
|
|
|
60
62
|
.incrementCallCount()
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
function bootstrapTraces(agent) {
|
|
64
|
-
opentelemetry.trace.setGlobalTracerProvider(new BasicTracerProvider({
|
|
65
|
-
sampler: new NrSampler(),
|
|
66
|
-
spanProcessors: [new NrSpanProcessor(agent)],
|
|
67
|
-
generalLimits: {
|
|
68
|
-
attributeValueLengthLimit: 4095
|
|
69
|
-
}
|
|
70
|
-
}))
|
|
71
|
-
|
|
72
|
-
agent.metrics
|
|
73
|
-
.getOrCreateMetric('Supportability/Nodejs/OpenTelemetryBridge/Traces')
|
|
74
|
-
.incrementCallCount()
|
|
75
|
-
}
|
|
76
|
-
|
|
77
65
|
function teardownOtel(agent) {
|
|
78
66
|
if (agent?.config?.opentelemetry_bridge?.enabled !== true) {
|
|
79
67
|
return
|
|
80
68
|
}
|
|
81
69
|
|
|
82
|
-
|
|
70
|
+
for (const signal of signals) {
|
|
71
|
+
signal.teardown()
|
|
72
|
+
}
|
|
73
|
+
|
|
83
74
|
opentelemetry.context.disable()
|
|
84
75
|
opentelemetry.propagation.disable()
|
|
85
76
|
opentelemetry.diag.disable()
|
|
86
|
-
logsApi.logs.disable()
|
|
87
77
|
}
|
|
88
78
|
|
|
89
79
|
module.exports = {
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const urltils = require('
|
|
9
|
-
const constants = require('./constants')
|
|
8
|
+
const urltils = require('#agentlib/util/urltils.js')
|
|
9
|
+
const constants = require('./constants.js')
|
|
10
10
|
|
|
11
11
|
const hostKeys = [
|
|
12
12
|
constants.ATTR_NET_HOST_NAME,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const { BasicTracerProvider } = require('@opentelemetry/sdk-trace-base')
|
|
9
|
+
|
|
10
|
+
const defaultLogger = require('../../logger').child({ component: 'opentelemetry-traces' })
|
|
11
|
+
const SetupSignal = require('../setup-signal.js')
|
|
12
|
+
const NrSampler = require('./sampler.js')
|
|
13
|
+
const NrSpanProcessor = require('./span-processor.js')
|
|
14
|
+
|
|
15
|
+
class SetupTraces extends SetupSignal {
|
|
16
|
+
constructor({ agent, logger = defaultLogger } = {}) {
|
|
17
|
+
super({ agent, logger })
|
|
18
|
+
|
|
19
|
+
const sampler = new NrSampler()
|
|
20
|
+
const spanProcessor = new NrSpanProcessor(agent)
|
|
21
|
+
const traceProvider = new BasicTracerProvider({
|
|
22
|
+
sampler,
|
|
23
|
+
spanProcessors: [spanProcessor],
|
|
24
|
+
generalLimits: {
|
|
25
|
+
attributeValueLengthLimit: 4_095
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
this.coreApi.trace.setGlobalTracerProvider(traceProvider)
|
|
29
|
+
|
|
30
|
+
agent.metrics
|
|
31
|
+
.getOrCreateMetric('Supportability/Nodejs/OpenTelemetryBridge/Traces')
|
|
32
|
+
.incrementCallCount()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
teardown() {
|
|
36
|
+
this.coreApi.trace.disable()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = SetupTraces
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const { SpanKind } = require('@opentelemetry/api')
|
|
9
|
-
const srcJson = require('./transformation-rules')
|
|
9
|
+
const srcJson = require('./transformation-rules.json')
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Mapping rules are stored, and provided to the agent, as JSON. We call these
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
|
-
|
|
8
|
-
const defaultLogger = require('
|
|
7
|
+
|
|
8
|
+
const defaultLogger = require('#agentlib/logger.js').child({ component: 'segment-synthesizer' })
|
|
9
|
+
const { RulesEngine } = require('./rules.js')
|
|
9
10
|
const {
|
|
10
11
|
createConsumerSegment,
|
|
11
12
|
createDbSegment,
|
|
@@ -13,7 +14,7 @@ const {
|
|
|
13
14
|
createInternalSegment,
|
|
14
15
|
createProducerSegment,
|
|
15
16
|
createServerSegment
|
|
16
|
-
} = require('./segments')
|
|
17
|
+
} = require('./segments/index.js')
|
|
17
18
|
|
|
18
19
|
class SegmentSynthesizer {
|
|
19
20
|
constructor(agent, { logger = defaultLogger } = {}) {
|
|
@@ -43,7 +44,7 @@ class SegmentSynthesizer {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
case 'external': {
|
|
46
|
-
return createHttpExternalSegment(this.agent, otelSpan, rule)
|
|
47
|
+
return createHttpExternalSegment(this.agent, otelSpan, rule, this.logger)
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
case 'internal': {
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
module.exports = createConsumerSegment
|
|
9
9
|
|
|
10
|
-
const Transaction = require('
|
|
11
|
-
const recorder = require('
|
|
12
|
-
const { propagateTraceContext } = require('./utils')
|
|
13
|
-
const createInternalSegment = require('./internal')
|
|
10
|
+
const Transaction = require('#agentlib/transaction/index.js')
|
|
11
|
+
const recorder = require('#agentlib/metrics/recorders/message-transaction.js')
|
|
12
|
+
const { propagateTraceContext } = require('./utils.js')
|
|
13
|
+
const createInternalSegment = require('./internal.js')
|
|
14
14
|
|
|
15
15
|
function createConsumerSegment(agent, otelSpan, rule) {
|
|
16
16
|
const activeTx = agent.tracer.getTransaction()
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const parseSql = require('
|
|
9
|
-
const recordQueryMetrics = require('
|
|
10
|
-
const recordOperationMetrics = require('
|
|
11
|
-
const ParsedStatement = require('
|
|
12
|
-
const metrics = require('
|
|
13
|
-
const { transformTemplate } = require('../utils')
|
|
8
|
+
const parseSql = require('#agentlib/db/query-parsers/sql.js')
|
|
9
|
+
const recordQueryMetrics = require('#agentlib/metrics/recorders/database.js')
|
|
10
|
+
const recordOperationMetrics = require('#agentlib/metrics/recorders/database-operation.js')
|
|
11
|
+
const ParsedStatement = require('#agentlib/db/parsed-statement.js')
|
|
12
|
+
const metrics = require('#agentlib/metrics/names.js')
|
|
13
|
+
const { transformTemplate } = require('../utils.js')
|
|
14
14
|
|
|
15
15
|
module.exports = function createDbSegment(agent, otelSpan, rule) {
|
|
16
16
|
const context = agent.tracer.getContext()
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const recordExternal = require('
|
|
9
|
-
const urltils = require('
|
|
10
|
-
const { transformTemplate } = require('../utils')
|
|
11
|
-
const { UNKNOWN } = require('../constants')
|
|
8
|
+
const recordExternal = require('#agentlib/metrics/recorders/http_external.js')
|
|
9
|
+
const urltils = require('#agentlib/util/urltils.js')
|
|
10
|
+
const { transformTemplate } = require('../utils.js')
|
|
11
|
+
const { UNKNOWN } = require('../constants.js')
|
|
12
12
|
|
|
13
13
|
function assignHost(otelSpan, segmentTransformation) {
|
|
14
14
|
let host = UNKNOWN
|
|
@@ -23,18 +23,21 @@ function assignHost(otelSpan, segmentTransformation) {
|
|
|
23
23
|
return host
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
module.exports = function createHttpExternalSegment(agent, otelSpan, rule) {
|
|
26
|
+
module.exports = function createHttpExternalSegment(agent, otelSpan, rule, logger) {
|
|
27
27
|
const context = agent.tracer.getContext()
|
|
28
28
|
const segmentTransformation = rule.segmentTransformation
|
|
29
29
|
|
|
30
30
|
const host = assignHost(otelSpan, segmentTransformation)
|
|
31
31
|
const url = otelSpan?.attributes[segmentTransformation?.url]
|
|
32
32
|
const system = otelSpan?.attributes[segmentTransformation?.system] ?? 'http'
|
|
33
|
-
let parsedUrl
|
|
34
33
|
let obfuscatedPath = `/${UNKNOWN}`
|
|
35
34
|
if (url) {
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
try {
|
|
36
|
+
const parsedUrl = new URL(url)
|
|
37
|
+
obfuscatedPath = urltils.obfuscatePath(agent.config, parsedUrl.pathname)
|
|
38
|
+
} catch (err) {
|
|
39
|
+
logger.debug('Could not parse URL %s: %s', url, err.message)
|
|
40
|
+
}
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
const name = transformTemplate(segmentTransformation?.name?.template, { host, path: obfuscatedPath, ...otelSpan?.attributes })
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
const createConsumerSegment = require('./consumer.js')
|
|
9
|
+
const createDbSegment = require('./database.js')
|
|
10
|
+
const createHttpExternalSegment = require('./http-external.js')
|
|
11
|
+
const createProducerSegment = require('./producer.js')
|
|
12
|
+
const createServerSegment = require('./server.js')
|
|
13
|
+
const createInternalSegment = require('./internal.js')
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
createConsumerSegment,
|
|
17
|
+
createDbSegment,
|
|
18
|
+
createHttpExternalSegment,
|
|
19
|
+
createInternalSegment,
|
|
20
|
+
createProducerSegment,
|
|
21
|
+
createServerSegment
|
|
22
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
|
-
const genericRecorder = require('
|
|
7
|
+
const genericRecorder = require('#agentlib/metrics/recorders/generic.js')
|
|
8
8
|
|
|
9
9
|
module.exports = function createInternalSegment(agent, otelSpan, rule) {
|
|
10
10
|
const context = agent.tracer.getContext()
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const genericRecorder = require('
|
|
9
|
-
const { transformTemplate } = require('../utils')
|
|
8
|
+
const genericRecorder = require('#agentlib/metrics/recorders/generic.js')
|
|
9
|
+
const { transformTemplate } = require('../utils.js')
|
|
10
10
|
|
|
11
11
|
module.exports = function createProducerSegment(agent, otelSpan, rule) {
|
|
12
12
|
const context = agent.tracer.getContext()
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const Transaction = require('
|
|
9
|
-
const httpRecorder = require('
|
|
10
|
-
const { propagateTraceContext } = require('./utils')
|
|
11
|
-
const createInternalSegment = require('./internal')
|
|
8
|
+
const Transaction = require('#agentlib/transaction/index.js')
|
|
9
|
+
const httpRecorder = require('#agentlib/metrics/recorders/http.js')
|
|
10
|
+
const { propagateTraceContext } = require('./utils.js')
|
|
11
|
+
const createInternalSegment = require('./internal.js')
|
|
12
12
|
|
|
13
13
|
module.exports = function createServerSegment(agent, otelSpan, rule) {
|
|
14
14
|
const activeTx = agent.tracer.getTransaction()
|
|
@@ -7,19 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
const { hrTimeToMilliseconds } = require('@opentelemetry/core')
|
|
9
9
|
const { SpanKind } = require('@opentelemetry/api')
|
|
10
|
-
const urltils = require('
|
|
10
|
+
const urltils = require('#agentlib/util/urltils.js')
|
|
11
11
|
|
|
12
|
-
const AttributeReconciler = require('./attr-reconciler')
|
|
13
|
-
const SegmentSynthesizer = require('./segment-synthesis')
|
|
14
|
-
const { otelSynthesis } = require('
|
|
15
|
-
const {
|
|
16
|
-
const
|
|
17
|
-
const defaultLogger = require('../logger').child({ component: 'span-processor' })
|
|
12
|
+
const AttributeReconciler = require('./attr-reconciler.js')
|
|
13
|
+
const SegmentSynthesizer = require('./segment-synthesis.js')
|
|
14
|
+
const { otelSynthesis } = require('#agentlib/symbols.js')
|
|
15
|
+
const { assignToTarget, buildRuleMappings, extractAttributeValue, processRegex, transformTemplate } = require('./utils.js')
|
|
16
|
+
const defaultLogger = require('#agentlib/logger.js').child({ component: 'span-processor' })
|
|
18
17
|
|
|
19
18
|
const {
|
|
20
19
|
SPAN_STATUS_CODE
|
|
21
20
|
} = require('./constants')
|
|
22
|
-
const exceptionAttr = require('./exception-mapping')
|
|
21
|
+
const exceptionAttr = require('./exception-mapping.js')
|
|
23
22
|
|
|
24
23
|
module.exports = class NrSpanProcessor {
|
|
25
24
|
#reconciler
|
|
@@ -215,24 +214,19 @@ module.exports = class NrSpanProcessor {
|
|
|
215
214
|
|
|
216
215
|
try {
|
|
217
216
|
const requestUrl = new URL(httpUrl)
|
|
218
|
-
transaction.parsedUrl = requestUrl
|
|
219
217
|
transaction.url = urltils.obfuscatePath(this.agent.config, requestUrl.pathname)
|
|
220
218
|
transaction.applyUserNamingRules(requestUrl.pathname)
|
|
221
|
-
|
|
219
|
+
// If `http.route` was not emitted on server span, name the transaction from the path
|
|
220
|
+
// to avoid transactions being named `*`
|
|
221
|
+
transaction.nameState.appendPathIfEmpty(requestUrl.pathname)
|
|
222
|
+
} catch (err) {
|
|
223
|
+
this.logger.debug('Could not parse URL from span for transaction URL: %s, err: %s', httpUrl, err.message)
|
|
222
224
|
transaction.url = httpUrl
|
|
223
225
|
}
|
|
224
226
|
|
|
225
|
-
transaction.trace.attributes.addAttribute(DESTINATIONS.TRANS_COMMON, 'request.uri', transaction.url)
|
|
226
|
-
|
|
227
|
-
// If `http.route` was not emitted on server span, name the transaction from the path
|
|
228
|
-
// to avoid transactions being named `*`
|
|
229
|
-
if (transaction.parsedUrl) {
|
|
230
|
-
transaction.nameState.appendPathIfEmpty(transaction.parsedUrl?.path)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
227
|
// Add the status code to transaction name
|
|
234
228
|
if (transaction.statusCode) {
|
|
235
|
-
transaction.
|
|
229
|
+
transaction.finalizeNameFromWeb(transaction.statusCode)
|
|
236
230
|
}
|
|
237
231
|
}
|
|
238
232
|
}
|
|
@@ -731,8 +731,9 @@
|
|
|
731
731
|
],
|
|
732
732
|
"segment": {
|
|
733
733
|
"host": "server.address",
|
|
734
|
+
"url": "url.full",
|
|
734
735
|
"name": {
|
|
735
|
-
"template": "External/${
|
|
736
|
+
"template": "External/${host}${path}"
|
|
736
737
|
}
|
|
737
738
|
}
|
|
738
739
|
},
|
|
@@ -798,7 +799,7 @@
|
|
|
798
799
|
"host": "net.peer.name",
|
|
799
800
|
"url": "http.url",
|
|
800
801
|
"name": {
|
|
801
|
-
"template": "External/${
|
|
802
|
+
"template": "External/${host}${path}"
|
|
802
803
|
}
|
|
803
804
|
}
|
|
804
805
|
},
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
const { DESTINATIONS } = require('#agentlib/config/attribute-filter.js')
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Transforms a template string by replacing placeholders with values from the data object.
|
|
@@ -62,7 +62,7 @@ function normalizeQueryStringParameters(event) {
|
|
|
62
62
|
!event.multiValueQueryStringParameters ||
|
|
63
63
|
Object.keys(event.multiValueQueryStringParameters).length === 0
|
|
64
64
|
) {
|
|
65
|
-
return event.queryStringParameters
|
|
65
|
+
return event.queryStringParameters ?? {}
|
|
66
66
|
}
|
|
67
67
|
return Object.fromEntries(
|
|
68
68
|
Object.entries(event.multiValueQueryStringParameters).map(([param, value]) => {
|
|
@@ -6,13 +6,11 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const apiGateway = require('./api-gateway')
|
|
9
|
-
const headerAttributes = require('../header-attributes')
|
|
10
9
|
const get = require('../util/get')
|
|
11
10
|
const logger = require('../logger').child({ component: 'aws-lambda' })
|
|
12
11
|
const recordBackground = require('../metrics/recorders/other')
|
|
13
12
|
const recordWeb = require('../metrics/recorders/http')
|
|
14
13
|
const TransactionShim = require('../shim/transaction-shim')
|
|
15
|
-
const urltils = require('../util/urltils')
|
|
16
14
|
const specs = require('../shim/specs')
|
|
17
15
|
|
|
18
16
|
// CONSTANTS
|
|
@@ -255,7 +253,7 @@ class AwsLambda {
|
|
|
255
253
|
|
|
256
254
|
if (isApiGatewayLambdaProxy) {
|
|
257
255
|
const webRequest = new apiGateway.LambdaProxyWebRequest(event)
|
|
258
|
-
setWebRequest(
|
|
256
|
+
setWebRequest(transaction, webRequest)
|
|
259
257
|
resultProcessor = getApiGatewayLambdaProxyResultProcessor(transaction)
|
|
260
258
|
}
|
|
261
259
|
const cbIndex = args.length - 1
|
|
@@ -411,57 +409,21 @@ function getApiGatewayLambdaProxyResultProcessor(transaction) {
|
|
|
411
409
|
return function processApiGatewayLambdaProxyResponse(response) {
|
|
412
410
|
if (apiGateway.isValidLambdaProxyResponse(response)) {
|
|
413
411
|
const webResponse = new apiGateway.LambdaProxyWebResponse(response)
|
|
414
|
-
|
|
412
|
+
transaction.finalizeWeb({ end: false, statusCode: webResponse.statusCode, headers: webResponse.headers })
|
|
415
413
|
} else {
|
|
416
414
|
logger.debug('Did not contain a valid API Gateway Lambda Proxy response.')
|
|
417
415
|
}
|
|
418
416
|
}
|
|
419
417
|
}
|
|
420
418
|
|
|
421
|
-
function setWebRequest(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
transaction.url = urltils.scrub(request.url.path)
|
|
427
|
-
transaction.verb = request.method
|
|
428
|
-
transaction.trace.attributes.addAttribute(
|
|
429
|
-
ATTR_DEST.TRANS_COMMON,
|
|
430
|
-
'request.method',
|
|
431
|
-
request.method
|
|
432
|
-
)
|
|
433
|
-
|
|
434
|
-
segment.addSpanAttribute('request.method', request.method)
|
|
435
|
-
|
|
436
|
-
transaction.port = request.url.port
|
|
419
|
+
function setWebRequest(transaction, request) {
|
|
420
|
+
// make a fake URL to scrub the path from a URL object
|
|
421
|
+
const absoluteUrl = `http://localhost${request.url.path}`
|
|
422
|
+
transaction.initializeWeb({ absoluteUrl, method: request.method, port: request.url.port, transport: request?.transportType?.toUpperCase(), headers: request.headers })
|
|
437
423
|
|
|
438
424
|
// These are only query parameters, from lib/serverless/api-gateway.js
|
|
425
|
+
// Not handled in `transaction.initializeWeb` because the query params are not on the absoluteUrl
|
|
439
426
|
transaction.addRequestParameters(request.url.requestParameters)
|
|
440
|
-
|
|
441
|
-
// URL is sent as an agent attribute with transaction events
|
|
442
|
-
transaction.trace.attributes.addAttribute(
|
|
443
|
-
ATTR_DEST.TRANS_EVENT | ATTR_DEST.ERROR_EVENT,
|
|
444
|
-
'request.uri',
|
|
445
|
-
request.url.path
|
|
446
|
-
)
|
|
447
|
-
|
|
448
|
-
segment.addSpanAttribute('request.uri', request.url.path)
|
|
449
|
-
|
|
450
|
-
headerAttributes.collectRequestHeaders(request.headers, transaction)
|
|
451
|
-
|
|
452
|
-
if (shim.agent.config.distributed_tracing.enabled) {
|
|
453
|
-
const lowercaseHeaders = lowercaseObjectKeys(request.headers)
|
|
454
|
-
|
|
455
|
-
const transportType = request.transportType && request.transportType.toUpperCase()
|
|
456
|
-
transaction.acceptDistributedTraceHeaders(transportType, lowercaseHeaders)
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
function lowercaseObjectKeys(original) {
|
|
461
|
-
return Object.keys(original).reduce((destination, key) => {
|
|
462
|
-
destination[key.toLowerCase()] = original[key]
|
|
463
|
-
return destination
|
|
464
|
-
}, {})
|
|
465
427
|
}
|
|
466
428
|
|
|
467
429
|
function endTransaction(transaction, enderIndex) {
|
|
@@ -490,27 +452,4 @@ function endTransaction(transaction, enderIndex) {
|
|
|
490
452
|
}
|
|
491
453
|
}
|
|
492
454
|
|
|
493
|
-
function setWebResponse(transaction, response) {
|
|
494
|
-
transaction.statusCode = response.statusCode
|
|
495
|
-
|
|
496
|
-
const responseCode = String(response.statusCode)
|
|
497
|
-
|
|
498
|
-
if (/^\d+$/.test(responseCode)) {
|
|
499
|
-
transaction.trace.attributes.addAttribute(
|
|
500
|
-
ATTR_DEST.TRANS_COMMON,
|
|
501
|
-
'http.statusCode',
|
|
502
|
-
responseCode
|
|
503
|
-
)
|
|
504
|
-
|
|
505
|
-
// We are adding http.statusCode to base segment as
|
|
506
|
-
// we found in testing async invoked lambdas, the
|
|
507
|
-
// active segment is not available at this point.
|
|
508
|
-
const segment = transaction.baseSegment
|
|
509
|
-
|
|
510
|
-
segment.addSpanAttribute('http.statusCode', responseCode)
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
headerAttributes.collectResponseHeaders(response.headers, transaction)
|
|
514
|
-
}
|
|
515
|
-
|
|
516
455
|
module.exports = AwsLambda
|
|
@@ -70,7 +70,7 @@ function copyParams({ spec, shim, fn, fnName, args, req }) {
|
|
|
70
70
|
? null
|
|
71
71
|
: spec.params.call(this, shim, fn, fnName, args, req)
|
|
72
72
|
|
|
73
|
-
// Route parameters are handled here, query parameters are handled in lib/transaction/index.js#
|
|
73
|
+
// Route parameters are handled here, query parameters are handled in lib/transaction/index.js#finalizeNameFromWeb as part of finalization
|
|
74
74
|
return shim.prefixRouteParameters(params)
|
|
75
75
|
}
|
|
76
76
|
|
package/lib/shimmer.js
CHANGED
|
@@ -11,7 +11,8 @@ const subscribers = {
|
|
|
11
11
|
...require('./subscribers/elasticsearch/config'),
|
|
12
12
|
...require('./subscribers/ioredis/config'),
|
|
13
13
|
...require('./subscribers/mcp-sdk/config'),
|
|
14
|
-
...require('./subscribers/
|
|
14
|
+
...require('./subscribers/openai/config'),
|
|
15
|
+
...require('./subscribers/pino/config')
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
module.exports = subscribers
|