newrelic 7.5.2 → 8.3.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/NEWS.md +4989 -4886
- package/THIRD_PARTY_NOTICES.md +625 -216
- package/api.js +105 -174
- package/bin/test-naming-rules.js +38 -32
- package/bin/tracetractor +0 -1
- package/index.js +12 -18
- package/lib/agent.js +108 -111
- package/lib/aggregators/base-aggregator.js +1 -1
- package/lib/aggregators/event-aggregator.js +6 -6
- package/lib/attributes.js +12 -13
- package/lib/collector/api.js +32 -42
- package/lib/collector/facts.js +67 -65
- package/lib/collector/http-agents.js +30 -27
- package/lib/collector/parse-response.js +1 -2
- package/lib/collector/remote-method.js +43 -36
- package/lib/collector/serverless.js +13 -18
- package/lib/collector/ssl/certificates.js +1056 -1056
- package/lib/config/attribute-filter.js +90 -82
- package/lib/config/default.js +30 -18
- package/lib/config/env.js +17 -12
- package/lib/config/harvest-config-validator.js +1 -1
- package/lib/config/index.js +160 -177
- package/lib/config/merge-server-config.js +7 -5
- package/lib/custom-events/custom-event-aggregator.js +1 -1
- package/lib/db/parse-sql.js +6 -9
- package/lib/db/parsed-statement.js +6 -13
- package/lib/db/query-parsers/sql.js +6 -9
- package/lib/db/query-sample.js +7 -3
- package/lib/db/query-trace-aggregator.js +12 -12
- package/lib/db/utils.js +1 -1
- package/lib/environment.js +173 -138
- package/lib/errors/error-collector.js +18 -31
- package/lib/errors/error-event-aggregator.js +1 -1
- package/lib/errors/error-trace-aggregator.js +2 -3
- package/lib/errors/helper.js +21 -30
- package/lib/errors/index.js +16 -28
- package/lib/feature_flags.js +5 -8
- package/lib/grpc/connection/states.js +6 -6
- package/lib/grpc/connection.js +35 -46
- package/lib/header-attributes.js +49 -53
- package/lib/instrumentation/amqplib.js +8 -17
- package/lib/instrumentation/bluebird.js +61 -20
- package/lib/instrumentation/cassandra-driver.js +2 -2
- package/lib/instrumentation/connect.js +4 -3
- package/lib/instrumentation/core/async_hooks.js +11 -4
- package/lib/instrumentation/core/child_process.js +20 -28
- package/lib/instrumentation/core/crypto.js +1 -7
- package/lib/instrumentation/core/dns.js +3 -7
- package/lib/instrumentation/core/domain.js +2 -8
- package/lib/instrumentation/core/fs.js +22 -37
- package/lib/instrumentation/core/globals.js +3 -7
- package/lib/instrumentation/core/http-outbound.js +15 -40
- package/lib/instrumentation/core/http.js +29 -63
- package/lib/instrumentation/core/inspector.js +6 -10
- package/lib/instrumentation/core/net.js +3 -1
- package/lib/instrumentation/core/timers.js +17 -24
- package/lib/instrumentation/core/zlib.js +2 -10
- package/lib/instrumentation/express.js +4 -2
- package/lib/instrumentation/fastify/spec-builders.js +5 -0
- package/lib/instrumentation/fastify.js +37 -10
- package/lib/instrumentation/hapi/hapi-17.js +9 -10
- package/lib/instrumentation/hapi.js +15 -15
- package/lib/instrumentation/ioredis.js +1 -2
- package/lib/instrumentation/memcached.js +39 -43
- package/lib/instrumentation/mongodb/common.js +218 -0
- package/lib/instrumentation/mongodb/constants.js +87 -0
- package/lib/instrumentation/mongodb/v2-mongo.js +110 -0
- package/lib/instrumentation/mongodb/v3-mongo.js +80 -0
- package/lib/instrumentation/mongodb/v4-mongo.js +90 -0
- package/lib/instrumentation/mongodb.js +20 -312
- package/lib/instrumentation/mysql.js +33 -26
- package/lib/instrumentation/oracle.js +10 -14
- package/lib/instrumentation/pg.js +30 -21
- package/lib/instrumentation/promise.js +20 -17
- package/lib/instrumentation/redis.js +30 -30
- package/lib/instrumentation/when.js +9 -1
- package/lib/instrumentations.js +24 -24
- package/lib/logger.js +1 -1
- package/lib/metrics/index.js +37 -17
- package/lib/metrics/mapper.js +9 -9
- package/lib/metrics/metric-aggregator.js +5 -10
- package/lib/metrics/names.js +8 -7
- package/lib/metrics/normalizer/rule.js +6 -7
- package/lib/metrics/normalizer/tx_segment.js +17 -13
- package/lib/metrics/normalizer.js +30 -33
- package/lib/metrics/recorders/custom.js +3 -1
- package/lib/metrics/recorders/distributed-trace.js +3 -18
- package/lib/metrics/recorders/generic.js +3 -2
- package/lib/metrics/recorders/http.js +4 -6
- package/lib/metrics/recorders/http_external.js +1 -3
- package/lib/metrics/recorders/message-transaction.js +2 -12
- package/lib/metrics/recorders/other.js +2 -12
- package/lib/parse-proc-cpuinfo.js +11 -16
- package/lib/parse-proc-meminfo.js +5 -3
- package/lib/prioritized-attributes.js +12 -17
- package/lib/priority-queue.js +1 -1
- package/lib/proxy/grpc.js +1 -1
- package/lib/reservoir.js +9 -3
- package/lib/sampler.js +12 -13
- package/lib/serverless/api-gateway.js +3 -3
- package/lib/serverless/aws-lambda.js +28 -37
- package/lib/shim/conglomerate-shim.js +4 -4
- package/lib/shim/datastore-shim.js +29 -38
- package/lib/shim/index.js +8 -9
- package/lib/shim/message-shim.js +111 -113
- package/lib/shim/promise-shim.js +18 -13
- package/lib/shim/shim.js +72 -66
- package/lib/shim/specs/index.js +18 -19
- package/lib/shim/transaction-shim.js +26 -36
- package/lib/shim/webframework-shim.js +25 -35
- package/lib/shimmer.js +184 -166
- package/lib/spans/create-span-event-aggregator.js +24 -44
- package/lib/spans/span-context.js +4 -10
- package/lib/spans/span-event-aggregator.js +68 -13
- package/lib/spans/span-event.js +5 -7
- package/lib/spans/span-streamer.js +10 -18
- package/lib/spans/streaming-span-event-aggregator.js +1 -1
- package/lib/spans/streaming-span-event.js +4 -4
- package/lib/stats/apdex.js +5 -11
- package/lib/stats/index.js +12 -17
- package/lib/system-info.js +7 -3
- package/lib/timer.js +30 -16
- package/lib/transaction/dt-payload.js +1 -1
- package/lib/transaction/handle.js +19 -19
- package/lib/transaction/index.js +94 -112
- package/lib/transaction/name-state.js +5 -6
- package/lib/transaction/trace/aggregator.js +78 -73
- package/lib/transaction/trace/exclusive-time-calculator.js +5 -9
- package/lib/transaction/trace/index.js +26 -24
- package/lib/transaction/trace/segment.js +39 -56
- package/lib/transaction/tracecontext.js +37 -45
- package/lib/transaction/tracer/index.js +79 -44
- package/lib/transaction/transaction-event-aggregator.js +29 -31
- package/lib/uninstrumented.js +4 -5
- package/lib/util/attribute-types.js +1 -5
- package/lib/util/byte-limit.js +0 -1
- package/lib/util/cat.js +5 -13
- package/lib/util/codec.js +8 -4
- package/lib/util/deep-equal.js +48 -18
- package/lib/util/flatten.js +5 -2
- package/lib/util/hashes.js +2 -2
- package/lib/util/label-parser.js +7 -13
- package/lib/util/logger.js +31 -13
- package/lib/util/process-version.js +1 -1
- package/lib/util/properties.js +1 -1
- package/lib/util/sql/obfuscate.js +7 -17
- package/lib/util/stream-sink.js +2 -3
- package/lib/util/urltils.js +9 -13
- package/lib/utilization/aws-info.js +2 -3
- package/lib/utilization/azure-info.js +32 -30
- package/lib/utilization/common.js +5 -4
- package/lib/utilization/docker-info.js +4 -6
- package/lib/utilization/gcp-info.js +36 -35
- package/lib/utilization/index.js +1 -1
- package/lib/utilization/kubernetes-info.js +2 -2
- package/lib/utilization/pcf-info.js +4 -4
- package/package.json +32 -18
- package/stub_api.js +8 -6
|
@@ -5,38 +5,35 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const psemver = require('../util/process-version')
|
|
9
8
|
const logger = require('../logger')
|
|
10
9
|
const SpanEventAggregator = require('./span-event-aggregator')
|
|
11
10
|
const StreamingSpanEventAggregator = require('./streaming-span-event-aggregator')
|
|
12
11
|
|
|
13
12
|
function createSpanEventAggregator(config, collector, metrics) {
|
|
14
|
-
const
|
|
13
|
+
const traceObserver = config.infinite_tracing.trace_observer
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// TODO: ideally this validation and configuration clearing would happen
|
|
19
|
-
// in the config. Since we don't currently have a way to generate
|
|
20
|
-
// support metrics in the config, keeping this related logic together here.
|
|
21
|
-
// If logic happened prior, could merely check for existence of trace_observer.host.
|
|
22
|
-
shouldCreateStreaming = validateInfiniteTracing()
|
|
15
|
+
if (traceObserver.host) {
|
|
16
|
+
traceObserver.host = traceObserver.host.trim()
|
|
23
17
|
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
trace_observer.host = ''
|
|
27
|
-
trace_observer.port = ''
|
|
18
|
+
if (typeof traceObserver.port !== 'string') {
|
|
19
|
+
traceObserver.port = String(traceObserver.port)
|
|
28
20
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
traceObserver.port = traceObserver.port.trim()
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return createStreamingAggregator(config, collector, metrics)
|
|
25
|
+
} catch (err) {
|
|
26
|
+
logger.warn(
|
|
27
|
+
err,
|
|
28
|
+
'Failed to create streaming span event aggregator for infinite tracing. ' +
|
|
29
|
+
'Reverting to standard span event aggregator and disabling infinite tracing'
|
|
30
|
+
)
|
|
31
|
+
config.infinite_tracing.trace_observer = {
|
|
32
|
+
host: '',
|
|
33
|
+
port: ''
|
|
34
|
+
}
|
|
35
|
+
return createStandardAggregator(config, collector, metrics)
|
|
36
36
|
}
|
|
37
|
-
trace_observer.port = trace_observer.port.trim()
|
|
38
|
-
|
|
39
|
-
return createStreamingAggregator(config, collector, metrics)
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
return createStandardAggregator(config, collector, metrics)
|
|
@@ -44,12 +41,10 @@ function createSpanEventAggregator(config, collector, metrics) {
|
|
|
44
41
|
|
|
45
42
|
function createStreamingAggregator(config, collector, metrics) {
|
|
46
43
|
logger.trace('Creating streaming span event aggregator for infinite tracing.')
|
|
47
|
-
|
|
48
|
-
// loading the class here to ensure its behind a feature flag
|
|
49
|
-
// and won't trigger a grpc load in node 8
|
|
50
44
|
const GrpcConnection = require('../grpc/connection')
|
|
51
|
-
const connection = new GrpcConnection(config.infinite_tracing.trace_observer, metrics)
|
|
52
45
|
const SpanStreamer = require('./span-streamer')
|
|
46
|
+
|
|
47
|
+
const connection = new GrpcConnection(config.infinite_tracing.trace_observer, metrics)
|
|
53
48
|
const spanStreamer = new SpanStreamer(
|
|
54
49
|
config.license_key,
|
|
55
50
|
connection,
|
|
@@ -63,9 +58,7 @@ function createStreamingAggregator(config, collector, metrics) {
|
|
|
63
58
|
span_streamer: spanStreamer
|
|
64
59
|
}
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return aggregator
|
|
61
|
+
return new StreamingSpanEventAggregator(opts, collector, metrics)
|
|
69
62
|
}
|
|
70
63
|
|
|
71
64
|
function createStandardAggregator(config, collector, metrics) {
|
|
@@ -76,20 +69,7 @@ function createStandardAggregator(config, collector, metrics) {
|
|
|
76
69
|
limit: config.event_harvest_config.harvest_limits.span_event_data
|
|
77
70
|
}
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
return aggregator
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function validateInfiniteTracing() {
|
|
84
|
-
// TODO: Remove semver check when Node 10 support dropped.
|
|
85
|
-
if (!psemver.satisfies('>=10.10.0')) {
|
|
86
|
-
logger.warn(
|
|
87
|
-
'Infinite tracing disabled: this version of Node is not supported (must be >=10.10.0)'
|
|
88
|
-
)
|
|
89
|
-
return false
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return true
|
|
72
|
+
return new SpanEventAggregator(opts, collector, metrics)
|
|
93
73
|
}
|
|
94
74
|
|
|
95
75
|
module.exports = createSpanEventAggregator
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const {MAXIMUM_CUSTOM_ATTRIBUTES} = require('../attributes')
|
|
9
|
-
const {PrioritizedAttributes, ATTRIBUTE_PRIORITY} = require('../prioritized-attributes')
|
|
10
|
-
const {DESTINATIONS} = require('../config/attribute-filter')
|
|
8
|
+
const { MAXIMUM_CUSTOM_ATTRIBUTES } = require('../attributes')
|
|
9
|
+
const { PrioritizedAttributes, ATTRIBUTE_PRIORITY } = require('../prioritized-attributes')
|
|
10
|
+
const { DESTINATIONS } = require('../config/attribute-filter')
|
|
11
11
|
|
|
12
12
|
// Scoping impacts memoization. We could decide to add a scope instead of including
|
|
13
13
|
// spans in segment scope in the future.
|
|
@@ -31,13 +31,7 @@ class SpanContext {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
addCustomAttribute(key, value, priority) {
|
|
34
|
-
this.customAttributes.addAttribute(
|
|
35
|
-
DESTINATIONS.SPAN_EVENT,
|
|
36
|
-
key,
|
|
37
|
-
value,
|
|
38
|
-
false,
|
|
39
|
-
priority
|
|
40
|
-
)
|
|
34
|
+
this.customAttributes.addAttribute(DESTINATIONS.SPAN_EVENT, key, value, false, priority)
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
/**
|
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const logger = require('../logger')
|
|
9
|
-
let spanLogger = null
|
|
8
|
+
const logger = require('../logger').child({ component: 'span_aggregator' })
|
|
10
9
|
const EventAggregator = require('../aggregators/event-aggregator')
|
|
11
10
|
const SpanEvent = require('./span-event')
|
|
12
11
|
const NAMES = require('../metrics/names')
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
const DEFAULT_SPAN_EVENT_LIMIT = 2000
|
|
14
|
+
// Used only when server value missing
|
|
15
|
+
const SPAN_EVENT_FALLBACK_MAX_LIMIT = 10000
|
|
14
16
|
|
|
15
17
|
class SpanEventAggregator extends EventAggregator {
|
|
16
18
|
constructor(opts, collector, metrics) {
|
|
@@ -18,8 +20,6 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
18
20
|
opts.method = opts.method || 'span_event_data'
|
|
19
21
|
opts.metricNames = opts.metricNames || NAMES.SPAN_EVENTS
|
|
20
22
|
|
|
21
|
-
spanLogger = logger.child({component: 'span_aggregator'})
|
|
22
|
-
|
|
23
23
|
super(opts, collector, metrics)
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
27
27
|
const events = this.events
|
|
28
28
|
|
|
29
29
|
if (events.length === 0) {
|
|
30
|
-
|
|
30
|
+
logger.debug('No span events to send.')
|
|
31
31
|
return
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -46,11 +46,14 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
send() {
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
if (logger.traceEnabled()) {
|
|
50
|
+
logger.trace(
|
|
51
|
+
{
|
|
52
|
+
spansCollected: this.length,
|
|
53
|
+
spansSeen: this.seen
|
|
54
|
+
},
|
|
55
|
+
'Entity stats on span harvest'
|
|
56
|
+
)
|
|
54
57
|
}
|
|
55
58
|
super.send()
|
|
56
59
|
}
|
|
@@ -61,7 +64,7 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
61
64
|
* @param {TraceSegment} segment - The segment to add.
|
|
62
65
|
* @param {string} [parentId=null] - The GUID of the parent span.
|
|
63
66
|
*
|
|
64
|
-
* @return {
|
|
67
|
+
* @return {boolean} True if the segment was added, or false if it was discarded.
|
|
65
68
|
*/
|
|
66
69
|
addSegment(segment, parentId, isRoot) {
|
|
67
70
|
// Check if the priority would be accepted before creating the event object.
|
|
@@ -76,7 +79,59 @@ class SpanEventAggregator extends EventAggregator {
|
|
|
76
79
|
const span = SpanEvent.fromSegment(segment, parentId || null, isRoot)
|
|
77
80
|
return this.add(span, tx.priority)
|
|
78
81
|
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Reconfigure the `SpanEventAggregator` based on values from server
|
|
85
|
+
*
|
|
86
|
+
* @param {Config} config
|
|
87
|
+
*/
|
|
88
|
+
reconfigure(config) {
|
|
89
|
+
super.reconfigure(config)
|
|
90
|
+
|
|
91
|
+
const { periodMs, limit } = this._getValidSpanConfiguration(config)
|
|
92
|
+
|
|
93
|
+
this.periodMs = periodMs
|
|
94
|
+
this.limit = limit
|
|
95
|
+
this._metrics.getOrCreateMetric(this._metricNames.LIMIT).recordValue(this.limit)
|
|
96
|
+
this._items.setLimit(this.limit)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Retrieves report period and harvest limits defined in `span_event_harvest_config`.
|
|
101
|
+
* When no `span_event_harvest_config` has been received from the server, applies an
|
|
102
|
+
* agent-defined fallback maximum to protect against collecting and sending too many spans.
|
|
103
|
+
*
|
|
104
|
+
* @param {Config} config
|
|
105
|
+
*/
|
|
106
|
+
_getValidSpanConfiguration(config) {
|
|
107
|
+
const spanHarvestConfig = config.span_event_harvest_config
|
|
108
|
+
if (spanHarvestConfig) {
|
|
109
|
+
logger.trace('Using span_event_harvest_config values.')
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
periodMs: spanHarvestConfig.report_period_ms,
|
|
113
|
+
limit: spanHarvestConfig.harvest_limit
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const configuredLimit = config.span_events.max_samples_stored || DEFAULT_SPAN_EVENT_LIMIT
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
periodMs: this.defaultPeriod,
|
|
121
|
+
limit: _enforceMaxLimit(configuredLimit, SPAN_EVENT_FALLBACK_MAX_LIMIT)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function _enforceMaxLimit(currentLimit, maxLimit) {
|
|
127
|
+
let spanLimit = currentLimit
|
|
128
|
+
if (spanLimit > maxLimit) {
|
|
129
|
+
spanLimit = maxLimit
|
|
130
|
+
|
|
131
|
+
logger.debug('Using maximum allowed span event limit of %s', maxLimit)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return spanLimit
|
|
79
135
|
}
|
|
80
136
|
|
|
81
137
|
module.exports = SpanEventAggregator
|
|
82
|
-
module.exports.LIMIT = LIMIT
|
package/lib/spans/span-event.js
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const Config = require('../config')
|
|
9
|
-
const {truncate} = require('../util/byte-limit')
|
|
9
|
+
const { truncate } = require('../util/byte-limit')
|
|
10
10
|
|
|
11
|
-
const {DESTINATIONS} = require('../config/attribute-filter')
|
|
11
|
+
const { DESTINATIONS } = require('../config/attribute-filter')
|
|
12
12
|
|
|
13
13
|
const HTTP_LIBRARY = 'http'
|
|
14
14
|
const CLIENT_KIND = 'client'
|
|
@@ -149,15 +149,13 @@ class SpanEvent {
|
|
|
149
149
|
toJSON() {
|
|
150
150
|
return [
|
|
151
151
|
_filterNulls(this.intrinsics),
|
|
152
|
-
this.customAttributes ?
|
|
153
|
-
_filterNulls(this.customAttributes) :
|
|
154
|
-
EMPTY_USER_ATTRS,
|
|
152
|
+
this.customAttributes ? _filterNulls(this.customAttributes) : EMPTY_USER_ATTRS,
|
|
155
153
|
_filterNulls(this.attributes)
|
|
156
154
|
]
|
|
157
155
|
}
|
|
158
156
|
|
|
159
157
|
addCustomAttribute(key, value, truncateExempt = false) {
|
|
160
|
-
const {attributeFilter} = Config.getInstance()
|
|
158
|
+
const { attributeFilter } = Config.getInstance()
|
|
161
159
|
const dest = attributeFilter.filterSegment(DESTINATIONS.SPAN_EVENT, key)
|
|
162
160
|
if (dest & DESTINATIONS.SPAN_EVENT) {
|
|
163
161
|
this.customAttributes[key] = truncateExempt ? value : _truncate(value)
|
|
@@ -165,7 +163,7 @@ class SpanEvent {
|
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
addAttribute(key, value, truncateExempt = false) {
|
|
168
|
-
const {attributeFilter} = Config.getInstance()
|
|
166
|
+
const { attributeFilter } = Config.getInstance()
|
|
169
167
|
const dest = attributeFilter.filterSegment(DESTINATIONS.SPAN_EVENT, key)
|
|
170
168
|
if (dest & DESTINATIONS.SPAN_EVENT) {
|
|
171
169
|
this.attributes[key] = truncateExempt ? value : _truncate(value)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
|
-
const logger = require('../logger').child({component: 'span-streamer'})
|
|
8
|
+
const logger = require('../logger').child({ component: 'span-streamer' })
|
|
9
9
|
const NAMES = require('../metrics/names').INFINITE_TRACING
|
|
10
10
|
|
|
11
11
|
const SPAN_DROP_MSG_INTERVAL_MS = 30000
|
|
@@ -14,25 +14,25 @@ const SPAN_DROP_MSG =
|
|
|
14
14
|
`Will not warn again for ${SPAN_DROP_MSG_INTERVAL_MS / 1000} seconds.`
|
|
15
15
|
|
|
16
16
|
class SpanStreamer {
|
|
17
|
-
constructor(
|
|
17
|
+
constructor(licenseKey, connection, metrics, queueSize) {
|
|
18
18
|
this.stream = null
|
|
19
|
-
this.license_key =
|
|
19
|
+
this.license_key = licenseKey
|
|
20
20
|
this.connection = connection
|
|
21
|
-
this.queue_size =
|
|
21
|
+
this.queue_size = queueSize
|
|
22
22
|
this.spans = []
|
|
23
23
|
this._metrics = metrics
|
|
24
24
|
this._writable = false
|
|
25
25
|
|
|
26
26
|
// 'connected' indicates a safely writeable stream.
|
|
27
27
|
// May still be mid-connect to gRPC server.
|
|
28
|
-
this.connection.on('connected', (stream) =>{
|
|
28
|
+
this.connection.on('connected', (stream) => {
|
|
29
29
|
logger.info('Span streamer connected')
|
|
30
30
|
this.stream = stream
|
|
31
31
|
this._writable = true
|
|
32
32
|
this.sendQueue()
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
this.connection.on('disconnected', () =>{
|
|
35
|
+
this.connection.on('disconnected', () => {
|
|
36
36
|
logger.info('Span streamer disconnected')
|
|
37
37
|
this.stream = null
|
|
38
38
|
this._writable = false
|
|
@@ -110,8 +110,7 @@ class SpanStreamer {
|
|
|
110
110
|
// average time to drain from when we first notice.
|
|
111
111
|
const drainCompleted = Date.now()
|
|
112
112
|
const drainDurationMs = drainCompleted - waitDrainStart
|
|
113
|
-
this._metrics.getOrCreateMetric(NAMES.DRAIN_DURATION)
|
|
114
|
-
.recordValue(drainDurationMs / 1000)
|
|
113
|
+
this._metrics.getOrCreateMetric(NAMES.DRAIN_DURATION).recordValue(drainDurationMs / 1000)
|
|
115
114
|
|
|
116
115
|
// Once the 'drain' event fires we can begin writing to the stream again
|
|
117
116
|
this._writable = true
|
|
@@ -131,18 +130,11 @@ class SpanStreamer {
|
|
|
131
130
|
this.send(nextObject.toStreamingFormat())
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
logger.trace(
|
|
135
|
-
'Finished sending spans from queue. Items left in queue: %s',
|
|
136
|
-
this.spans.length
|
|
137
|
-
)
|
|
133
|
+
logger.trace('Finished sending spans from queue. Items left in queue: %s', this.spans.length)
|
|
138
134
|
}
|
|
139
135
|
|
|
140
|
-
connect(
|
|
141
|
-
this.connection.setConnectionDetails(
|
|
142
|
-
this.license_key,
|
|
143
|
-
agent_run_id,
|
|
144
|
-
requestHeadersMap
|
|
145
|
-
)
|
|
136
|
+
connect(agentRunId, requestHeadersMap) {
|
|
137
|
+
this.connection.setConnectionDetails(this.license_key, agentRunId, requestHeadersMap)
|
|
146
138
|
|
|
147
139
|
this.connection.connectSpans()
|
|
148
140
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const Aggregator = require('../aggregators/base-aggregator')
|
|
9
9
|
const StreamingSpanEvent = require('./streaming-span-event')
|
|
10
|
-
const logger = require('../logger').child({component: 'streaming-span-event-aggregator'})
|
|
10
|
+
const logger = require('../logger').child({ component: 'streaming-span-event-aggregator' })
|
|
11
11
|
|
|
12
12
|
const SEND_WARNING =
|
|
13
13
|
'send() is not currently supported on streaming span event aggregator. ' +
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
'use strict'
|
|
7
7
|
|
|
8
8
|
const StreamingSpanAttributes = require('./streaming-span-attributes')
|
|
9
|
-
const {truncate} = require('../util/byte-limit')
|
|
9
|
+
const { truncate } = require('../util/byte-limit')
|
|
10
10
|
const Config = require('../config')
|
|
11
11
|
|
|
12
|
-
const {DESTINATIONS} = require('../config/attribute-filter')
|
|
12
|
+
const { DESTINATIONS } = require('../config/attribute-filter')
|
|
13
13
|
|
|
14
14
|
const HTTP_LIBRARY = 'http'
|
|
15
15
|
const CLIENT_KIND = 'client'
|
|
@@ -88,7 +88,7 @@ class StreamingSpanEvent {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
_checkFilter(key) {
|
|
91
|
-
const {attributeFilter} = Config.getInstance()
|
|
91
|
+
const { attributeFilter } = Config.getInstance()
|
|
92
92
|
const dest = attributeFilter.filterSegment(DESTINATIONS.SPAN_EVENT, key)
|
|
93
93
|
return dest & DESTINATIONS.SPAN_EVENT
|
|
94
94
|
}
|
|
@@ -128,7 +128,7 @@ class StreamingSpanEvent {
|
|
|
128
128
|
let span = null
|
|
129
129
|
if (StreamingHttpSpanEvent.isHttpSegment(segment)) {
|
|
130
130
|
span = new StreamingHttpSpanEvent(traceId, agentAttributes, customAttributes)
|
|
131
|
-
}
|
|
131
|
+
} else if (StreamingDatastoreSpanEvent.isDatastoreSegment(segment)) {
|
|
132
132
|
span = new StreamingDatastoreSpanEvent(traceId, agentAttributes, customAttributes)
|
|
133
133
|
} else {
|
|
134
134
|
span = new StreamingSpanEvent(traceId, agentAttributes, customAttributes)
|
package/lib/stats/apdex.js
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
*/
|
|
13
13
|
var FROM_MILLIS = 1e-3
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
function ApdexStats(apdexT) {
|
|
17
16
|
if (!apdexT && apdexT !== 0) {
|
|
18
17
|
throw new Error('Apdex summary must be created with apdexT.')
|
|
@@ -35,8 +34,10 @@ ApdexStats.prototype.recordValue = function recordValue(time, overrideApdex) {
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
ApdexStats.prototype.recordValueInMillis =
|
|
39
|
-
|
|
37
|
+
ApdexStats.prototype.recordValueInMillis = function recordValueInMillis(
|
|
38
|
+
timeInMillis,
|
|
39
|
+
overrideApdex
|
|
40
|
+
) {
|
|
40
41
|
this.recordValue(timeInMillis * FROM_MILLIS, overrideApdex * FROM_MILLIS)
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -71,14 +72,7 @@ ApdexStats.prototype.merge = function merge(other) {
|
|
|
71
72
|
* load times, respectively.
|
|
72
73
|
*/
|
|
73
74
|
ApdexStats.prototype.toJSON = function toJSON() {
|
|
74
|
-
return [
|
|
75
|
-
this.satisfying,
|
|
76
|
-
this.tolerating,
|
|
77
|
-
this.frustrating,
|
|
78
|
-
this.apdexT,
|
|
79
|
-
this.apdexT,
|
|
80
|
-
0
|
|
81
|
-
]
|
|
75
|
+
return [this.satisfying, this.tolerating, this.frustrating, this.apdexT, this.apdexT, 0]
|
|
82
76
|
}
|
|
83
77
|
|
|
84
78
|
module.exports = ApdexStats
|
package/lib/stats/index.js
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
var BYTES_PER_MB = 1024 * 1024
|
|
14
14
|
var FROM_MILLIS = 1e-3
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
/**
|
|
18
17
|
* Simple container for tracking running statistics for a metric.
|
|
19
18
|
*/
|
|
@@ -35,8 +34,12 @@ function Stats() {
|
|
|
35
34
|
*/
|
|
36
35
|
Stats.prototype.recordValue = function recordValue(totalTime, exclusiveTime) {
|
|
37
36
|
// even if a caller messes up, don't break everything else
|
|
38
|
-
if (totalTime !== 0 && !totalTime)
|
|
39
|
-
|
|
37
|
+
if (totalTime !== 0 && !totalTime) {
|
|
38
|
+
totalTime = 0
|
|
39
|
+
}
|
|
40
|
+
if (exclusiveTime !== 0 && !exclusiveTime) {
|
|
41
|
+
exclusiveTime = totalTime
|
|
42
|
+
}
|
|
40
43
|
|
|
41
44
|
if (this.callCount > 0) {
|
|
42
45
|
this.min = Math.min(totalTime, this.min)
|
|
@@ -45,7 +48,7 @@ Stats.prototype.recordValue = function recordValue(totalTime, exclusiveTime) {
|
|
|
45
48
|
}
|
|
46
49
|
this.max = Math.max(totalTime, this.max)
|
|
47
50
|
|
|
48
|
-
this.sumOfSquares +=
|
|
51
|
+
this.sumOfSquares += totalTime * totalTime
|
|
49
52
|
++this.callCount
|
|
50
53
|
this.total += totalTime
|
|
51
54
|
this.totalExclusive += exclusiveTime
|
|
@@ -57,10 +60,7 @@ Stats.prototype.recordValue = function recordValue(totalTime, exclusiveTime) {
|
|
|
57
60
|
*/
|
|
58
61
|
Stats.prototype.recordValueInMillis = recordValueInMillis
|
|
59
62
|
function recordValueInMillis(totalTime, exclusiveTime) {
|
|
60
|
-
this.recordValue(
|
|
61
|
-
totalTime * FROM_MILLIS,
|
|
62
|
-
exclusiveTime >= 0 ? exclusiveTime * FROM_MILLIS : null
|
|
63
|
-
)
|
|
63
|
+
this.recordValue(totalTime * FROM_MILLIS, exclusiveTime >= 0 ? exclusiveTime * FROM_MILLIS : null)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
Stats.prototype.recordValueInBytes = function recordValueInBytes(bytes, exclusiveBytes) {
|
|
@@ -69,7 +69,9 @@ Stats.prototype.recordValueInBytes = function recordValueInBytes(bytes, exclusiv
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
Stats.prototype.incrementCallCount = function incrementCallCount(count) {
|
|
72
|
-
if (typeof count === 'undefined')
|
|
72
|
+
if (typeof count === 'undefined') {
|
|
73
|
+
count = 1
|
|
74
|
+
}
|
|
73
75
|
this.callCount += count
|
|
74
76
|
}
|
|
75
77
|
|
|
@@ -113,14 +115,7 @@ Stats.prototype.merge = function merge(other) {
|
|
|
113
115
|
* running sum of squares.
|
|
114
116
|
*/
|
|
115
117
|
Stats.prototype.toJSON = function toJSON() {
|
|
116
|
-
return [
|
|
117
|
-
this.callCount,
|
|
118
|
-
this.total,
|
|
119
|
-
this.totalExclusive,
|
|
120
|
-
this.min,
|
|
121
|
-
this.max,
|
|
122
|
-
this.sumOfSquares
|
|
123
|
-
]
|
|
118
|
+
return [this.callCount, this.total, this.totalExclusive, this.min, this.max, this.sumOfSquares]
|
|
124
119
|
}
|
|
125
120
|
|
|
126
121
|
module.exports = Stats
|
package/lib/system-info.js
CHANGED
|
@@ -9,7 +9,7 @@ var exec = require('child_process').exec
|
|
|
9
9
|
var readProc = require('./utilization/common').readProc
|
|
10
10
|
var getBootId = require('./utilization/docker-info').getBootId
|
|
11
11
|
var utilization = require('./utilization')
|
|
12
|
-
var logger = require('./logger.js').child({component: 'system-info'})
|
|
12
|
+
var logger = require('./logger.js').child({ component: 'system-info' })
|
|
13
13
|
var os = require('os')
|
|
14
14
|
var parseCpuInfo = require('./parse-proc-cpuinfo')
|
|
15
15
|
var parseMemInfo = require('./parse-proc-meminfo')
|
|
@@ -193,14 +193,18 @@ function getKernelVersion(callback) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
function getSysctlValue(names, callback) {
|
|
196
|
-
if (!names)
|
|
196
|
+
if (!names) {
|
|
197
|
+
return callback(null)
|
|
198
|
+
}
|
|
197
199
|
var returned = false
|
|
198
200
|
var ran = 0
|
|
199
201
|
names.forEach(function sysctlName(name) {
|
|
200
202
|
exec('sysctl -n ' + name, respond)
|
|
201
203
|
|
|
202
204
|
function respond(err, stdout, stderr) {
|
|
203
|
-
if (returned)
|
|
205
|
+
if (returned) {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
204
208
|
if (err) {
|
|
205
209
|
logger.debug('Error when trying to run: sysctl -n %s: %s', name, err.message)
|
|
206
210
|
callback(null)
|
package/lib/timer.js
CHANGED
|
@@ -20,10 +20,9 @@ var PENDING = 1
|
|
|
20
20
|
var RUNNING = 2
|
|
21
21
|
var STOPPED = 3
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
function hrToMillis(hr) {
|
|
25
24
|
// process.hrTime gives you [second, nanosecond] duration pairs
|
|
26
|
-
return
|
|
25
|
+
return hr[0] * 1e3 + hr[1] / 1e6
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
/**
|
|
@@ -45,7 +44,9 @@ function Timer() {
|
|
|
45
44
|
* Uses process.hrtime if available, Date.now() otherwise.
|
|
46
45
|
*/
|
|
47
46
|
Timer.prototype.begin = function begin() {
|
|
48
|
-
if (this.state > PENDING)
|
|
47
|
+
if (this.state > PENDING) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
49
50
|
|
|
50
51
|
this.start = Date.now()
|
|
51
52
|
this.hrstart = process.hrtime()
|
|
@@ -56,8 +57,12 @@ Timer.prototype.begin = function begin() {
|
|
|
56
57
|
* End measurement.
|
|
57
58
|
*/
|
|
58
59
|
Timer.prototype.end = function end() {
|
|
59
|
-
if (this.state > RUNNING)
|
|
60
|
-
|
|
60
|
+
if (this.state > RUNNING) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
if (this.state === PENDING) {
|
|
64
|
+
this.begin()
|
|
65
|
+
}
|
|
61
66
|
this.hrDuration = process.hrtime(this.hrstart)
|
|
62
67
|
this.touched = true
|
|
63
68
|
this.state = STOPPED
|
|
@@ -68,8 +73,12 @@ Timer.prototype.end = function end() {
|
|
|
68
73
|
*/
|
|
69
74
|
Timer.prototype.touch = function touch() {
|
|
70
75
|
this.touched = true
|
|
71
|
-
if (this.state > RUNNING)
|
|
72
|
-
|
|
76
|
+
if (this.state > RUNNING) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
if (this.state === PENDING) {
|
|
80
|
+
this.begin()
|
|
81
|
+
}
|
|
73
82
|
|
|
74
83
|
this.hrDuration = process.hrtime(this.hrstart)
|
|
75
84
|
}
|
|
@@ -79,12 +88,18 @@ Timer.prototype.touch = function touch() {
|
|
|
79
88
|
* "now". Returns a boolean indicating whether the end time changed.
|
|
80
89
|
*/
|
|
81
90
|
Timer.prototype.softEnd = function softEnd() {
|
|
82
|
-
if (this.state > RUNNING)
|
|
83
|
-
|
|
91
|
+
if (this.state > RUNNING) {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
if (this.state === PENDING) {
|
|
95
|
+
this.begin()
|
|
96
|
+
}
|
|
84
97
|
|
|
85
98
|
this.state = STOPPED
|
|
86
99
|
|
|
87
|
-
if (this.touched)
|
|
100
|
+
if (this.touched) {
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
88
103
|
this.hrDuration = process.hrtime(this.hrstart)
|
|
89
104
|
this.touched = true
|
|
90
105
|
return true
|
|
@@ -146,7 +161,7 @@ Timer.prototype.setDurationInMillis = function setDurationInMillis(duration, sta
|
|
|
146
161
|
// is the assumption being made here. since hrstart isn't used
|
|
147
162
|
// anywhere except to calculate duration, and we are setting duration
|
|
148
163
|
// this is fine.
|
|
149
|
-
this.hrstart = [Math.floor(start / 1e3), start % 1e3 * 1e6]
|
|
164
|
+
this.hrstart = [Math.floor(start / 1e3), (start % 1e3) * 1e6]
|
|
150
165
|
if (start != null) {
|
|
151
166
|
this.start = start
|
|
152
167
|
}
|
|
@@ -157,7 +172,9 @@ Timer.prototype.setDurationInMillis = function setDurationInMillis(duration, sta
|
|
|
157
172
|
* how long it ran (if it's been ended or touched).
|
|
158
173
|
*/
|
|
159
174
|
Timer.prototype.getDurationInMillis = function getDurationInMillis() {
|
|
160
|
-
if (this.state === PENDING)
|
|
175
|
+
if (this.state === PENDING) {
|
|
176
|
+
return 0
|
|
177
|
+
}
|
|
161
178
|
|
|
162
179
|
// only set by setDurationInMillis
|
|
163
180
|
if (this.durationInMillis !== null && this.durationInMillis >= 0) {
|
|
@@ -195,7 +212,6 @@ Timer.prototype.startedRelativeTo = function startedRelativeTo(other) {
|
|
|
195
212
|
var s = this.hrstart[0] - other.hrstart[0]
|
|
196
213
|
var ns = this.hrstart[1] - other.hrstart[1]
|
|
197
214
|
|
|
198
|
-
|
|
199
215
|
return hrToMillis([s, ns])
|
|
200
216
|
}
|
|
201
217
|
|
|
@@ -206,9 +222,7 @@ Timer.prototype.startedRelativeTo = function startedRelativeTo(other) {
|
|
|
206
222
|
* Returns true if this timer ends after the other.
|
|
207
223
|
*/
|
|
208
224
|
Timer.prototype.endsAfter = function compare(other) {
|
|
209
|
-
return
|
|
210
|
-
(other.getDurationInMillis() + other.start)
|
|
225
|
+
return this.getDurationInMillis() + this.start > other.getDurationInMillis() + other.start
|
|
211
226
|
}
|
|
212
227
|
|
|
213
|
-
|
|
214
228
|
module.exports = Timer
|