@depup/elastic-apm-node 4.15.0-depup.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.
Files changed (154) hide show
  1. package/LICENSE +26 -0
  2. package/NOTICE.md +442 -0
  3. package/README.md +48 -0
  4. package/changes.json +78 -0
  5. package/index.d.ts +398 -0
  6. package/index.js +11 -0
  7. package/lib/InflightEventSet.js +53 -0
  8. package/lib/activation-method.js +119 -0
  9. package/lib/agent.js +941 -0
  10. package/lib/apm-client/apm-client.js +313 -0
  11. package/lib/apm-client/http-apm-client/CHANGELOG.md +271 -0
  12. package/lib/apm-client/http-apm-client/README.md +485 -0
  13. package/lib/apm-client/http-apm-client/central-config.js +41 -0
  14. package/lib/apm-client/http-apm-client/container-info.js +111 -0
  15. package/lib/apm-client/http-apm-client/detect-hostname.js +96 -0
  16. package/lib/apm-client/http-apm-client/index.js +1975 -0
  17. package/lib/apm-client/http-apm-client/logging.js +31 -0
  18. package/lib/apm-client/http-apm-client/ndjson.js +20 -0
  19. package/lib/apm-client/http-apm-client/truncate.js +434 -0
  20. package/lib/apm-client/noop-apm-client.js +73 -0
  21. package/lib/async-hooks-polyfill.js +58 -0
  22. package/lib/cloud-metadata/aws.js +175 -0
  23. package/lib/cloud-metadata/azure.js +123 -0
  24. package/lib/cloud-metadata/callback-coordination.js +159 -0
  25. package/lib/cloud-metadata/gcp.js +133 -0
  26. package/lib/cloud-metadata/index.js +175 -0
  27. package/lib/config/config.js +458 -0
  28. package/lib/config/normalizers.js +701 -0
  29. package/lib/config/schema.js +1007 -0
  30. package/lib/constants.js +35 -0
  31. package/lib/errors.js +303 -0
  32. package/lib/filters/sanitize-field-names.js +69 -0
  33. package/lib/http-request.js +249 -0
  34. package/lib/instrumentation/azure-functions.js +519 -0
  35. package/lib/instrumentation/context.js +56 -0
  36. package/lib/instrumentation/dropped-spans-stats.js +112 -0
  37. package/lib/instrumentation/elasticsearch-shared.js +63 -0
  38. package/lib/instrumentation/express-utils.js +91 -0
  39. package/lib/instrumentation/generic-span.js +322 -0
  40. package/lib/instrumentation/http-shared.js +424 -0
  41. package/lib/instrumentation/ids.js +39 -0
  42. package/lib/instrumentation/index.js +1127 -0
  43. package/lib/instrumentation/modules/@apollo/server.js +30 -0
  44. package/lib/instrumentation/modules/@aws-sdk/client-dynamodb.js +143 -0
  45. package/lib/instrumentation/modules/@aws-sdk/client-s3.js +230 -0
  46. package/lib/instrumentation/modules/@aws-sdk/client-sns.js +197 -0
  47. package/lib/instrumentation/modules/@aws-sdk/client-sqs.js +336 -0
  48. package/lib/instrumentation/modules/@elastic/elasticsearch.js +343 -0
  49. package/lib/instrumentation/modules/@hapi/hapi.js +221 -0
  50. package/lib/instrumentation/modules/@opentelemetry/api.js +86 -0
  51. package/lib/instrumentation/modules/@opentelemetry/sdk-metrics.js +79 -0
  52. package/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js +178 -0
  53. package/lib/instrumentation/modules/@redis/client/dist/lib/client/index.js +49 -0
  54. package/lib/instrumentation/modules/@smithy/smithy-client.js +198 -0
  55. package/lib/instrumentation/modules/_lambda-handler.js +40 -0
  56. package/lib/instrumentation/modules/apollo-server-core.js +49 -0
  57. package/lib/instrumentation/modules/aws-sdk/dynamodb.js +155 -0
  58. package/lib/instrumentation/modules/aws-sdk/s3.js +184 -0
  59. package/lib/instrumentation/modules/aws-sdk/sns.js +232 -0
  60. package/lib/instrumentation/modules/aws-sdk/sqs.js +361 -0
  61. package/lib/instrumentation/modules/aws-sdk.js +76 -0
  62. package/lib/instrumentation/modules/bluebird.js +93 -0
  63. package/lib/instrumentation/modules/cassandra-driver.js +280 -0
  64. package/lib/instrumentation/modules/elasticsearch.js +191 -0
  65. package/lib/instrumentation/modules/express-graphql.js +66 -0
  66. package/lib/instrumentation/modules/express-queue.js +28 -0
  67. package/lib/instrumentation/modules/express.js +162 -0
  68. package/lib/instrumentation/modules/fastify.js +172 -0
  69. package/lib/instrumentation/modules/finalhandler.js +41 -0
  70. package/lib/instrumentation/modules/generic-pool.js +85 -0
  71. package/lib/instrumentation/modules/graphql.js +256 -0
  72. package/lib/instrumentation/modules/handlebars.js +22 -0
  73. package/lib/instrumentation/modules/http.js +112 -0
  74. package/lib/instrumentation/modules/http2.js +320 -0
  75. package/lib/instrumentation/modules/https.js +68 -0
  76. package/lib/instrumentation/modules/ioredis.js +94 -0
  77. package/lib/instrumentation/modules/jade.js +18 -0
  78. package/lib/instrumentation/modules/kafkajs.js +476 -0
  79. package/lib/instrumentation/modules/knex.js +91 -0
  80. package/lib/instrumentation/modules/koa-router.js +74 -0
  81. package/lib/instrumentation/modules/koa.js +15 -0
  82. package/lib/instrumentation/modules/memcached.js +99 -0
  83. package/lib/instrumentation/modules/mimic-response.js +45 -0
  84. package/lib/instrumentation/modules/mongodb/lib/cmap/connection_pool.js +40 -0
  85. package/lib/instrumentation/modules/mongodb-core.js +206 -0
  86. package/lib/instrumentation/modules/mongodb.js +259 -0
  87. package/lib/instrumentation/modules/mysql.js +200 -0
  88. package/lib/instrumentation/modules/mysql2.js +140 -0
  89. package/lib/instrumentation/modules/pg.js +148 -0
  90. package/lib/instrumentation/modules/pug.js +18 -0
  91. package/lib/instrumentation/modules/redis.js +176 -0
  92. package/lib/instrumentation/modules/restify.js +52 -0
  93. package/lib/instrumentation/modules/tedious.js +159 -0
  94. package/lib/instrumentation/modules/undici.js +270 -0
  95. package/lib/instrumentation/modules/ws.js +59 -0
  96. package/lib/instrumentation/noop-transaction.js +81 -0
  97. package/lib/instrumentation/run-context/AbstractRunContextManager.js +215 -0
  98. package/lib/instrumentation/run-context/AsyncHooksRunContextManager.js +106 -0
  99. package/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js +73 -0
  100. package/lib/instrumentation/run-context/BasicRunContextManager.js +82 -0
  101. package/lib/instrumentation/run-context/RunContext.js +151 -0
  102. package/lib/instrumentation/run-context/index.js +23 -0
  103. package/lib/instrumentation/shimmer.js +123 -0
  104. package/lib/instrumentation/span-compression.js +239 -0
  105. package/lib/instrumentation/span.js +621 -0
  106. package/lib/instrumentation/template-shared.js +43 -0
  107. package/lib/instrumentation/timer.js +84 -0
  108. package/lib/instrumentation/transaction.js +571 -0
  109. package/lib/lambda.js +992 -0
  110. package/lib/load-source-map.js +100 -0
  111. package/lib/logging.js +212 -0
  112. package/lib/metrics/index.js +92 -0
  113. package/lib/metrics/platforms/generic/index.js +40 -0
  114. package/lib/metrics/platforms/generic/process-cpu.js +22 -0
  115. package/lib/metrics/platforms/generic/process-top.js +157 -0
  116. package/lib/metrics/platforms/generic/stats.js +34 -0
  117. package/lib/metrics/platforms/generic/system-cpu.js +51 -0
  118. package/lib/metrics/platforms/linux/index.js +19 -0
  119. package/lib/metrics/platforms/linux/stats.js +213 -0
  120. package/lib/metrics/queue.js +90 -0
  121. package/lib/metrics/registry.js +52 -0
  122. package/lib/metrics/reporter.js +119 -0
  123. package/lib/metrics/runtime.js +77 -0
  124. package/lib/middleware/connect.js +16 -0
  125. package/lib/opentelemetry-bridge/OTelBridgeNonRecordingSpan.js +150 -0
  126. package/lib/opentelemetry-bridge/OTelBridgeRunContext.js +124 -0
  127. package/lib/opentelemetry-bridge/OTelContextManager.js +82 -0
  128. package/lib/opentelemetry-bridge/OTelSpan.js +344 -0
  129. package/lib/opentelemetry-bridge/OTelTracer.js +201 -0
  130. package/lib/opentelemetry-bridge/OTelTracerProvider.js +25 -0
  131. package/lib/opentelemetry-bridge/README.md +244 -0
  132. package/lib/opentelemetry-bridge/index.js +15 -0
  133. package/lib/opentelemetry-bridge/oblog.js +23 -0
  134. package/lib/opentelemetry-bridge/opentelemetry-core-mini/README.md +3 -0
  135. package/lib/opentelemetry-bridge/opentelemetry-core-mini/internal/validators.js +52 -0
  136. package/lib/opentelemetry-bridge/opentelemetry-core-mini/trace/TraceState.js +109 -0
  137. package/lib/opentelemetry-bridge/otelutils.js +99 -0
  138. package/lib/opentelemetry-bridge/setup.js +76 -0
  139. package/lib/opentelemetry-metrics/ElasticApmMetricExporter.js +285 -0
  140. package/lib/opentelemetry-metrics/index.js +50 -0
  141. package/lib/parsers.js +225 -0
  142. package/lib/propwrap.js +147 -0
  143. package/lib/stacktraces.js +537 -0
  144. package/lib/symbols.js +15 -0
  145. package/lib/tracecontext/index.js +118 -0
  146. package/lib/tracecontext/traceparent.js +185 -0
  147. package/lib/tracecontext/tracestate.js +388 -0
  148. package/lib/wildcard-matcher.js +52 -0
  149. package/loader.mjs +7 -0
  150. package/package.json +299 -0
  151. package/start.d.ts +8 -0
  152. package/start.js +29 -0
  153. package/types/aws-lambda.d.ts +98 -0
  154. package/types/connect.d.ts +23 -0
@@ -0,0 +1,175 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+ const { getMetadataAws } = require('./aws');
9
+ const { getMetadataAzure } = require('./azure');
10
+ const { getMetadataGcp } = require('./gcp');
11
+ const { CallbackCoordination } = require('./callback-coordination');
12
+
13
+ const logging = require('../logging');
14
+
15
+ // we "ping" (in the colloquial sense, not the ICMP sense) the metadata
16
+ // servers by having a listener that expects the underlying socket to
17
+ // connect. CONNECT_TIMEOUT_MS control that time
18
+ const CONNECT_TIMEOUT_MS = 100;
19
+
20
+ // some of the metadata servers have a dedicated domain name. This
21
+ // value is added to the above socket ping to allow extra time for
22
+ // the DNS to resolve
23
+ const DNS_TIMEOUT_MS = 100;
24
+
25
+ // the metadata servers are HTTP services. This value is
26
+ // used as the timeout for the HTTP request that's
27
+ // made.
28
+ const HTTP_TIMEOUT_MS = 1000;
29
+
30
+ // timeout for the CallbackCoordination object -- this is a fallback to
31
+ // account for a catastrophic error in the CallbackCoordination object
32
+ const COORDINATION_TIMEOUT_MS = 3000;
33
+
34
+ class CloudMetadata {
35
+ constructor(cloudProvider, logger, serviceName) {
36
+ this.cloudProvider = cloudProvider;
37
+ this.logger = logger;
38
+ this.serviceName = serviceName;
39
+ }
40
+
41
+ /**
42
+ * Fetches Cloud Metadata
43
+ *
44
+ * The module's main entry-point/primary method. The getCloudMetadata function
45
+ * will query the cloud metadata servers and return (via a callback function)
46
+ * to final metadata object. This function may be called with a single
47
+ * argument.
48
+ *
49
+ * getCloudMetadata(function(err, metadata){
50
+ * //...
51
+ * })
52
+ *
53
+ * Or with two
54
+ *
55
+ * getCloudMetadata(config, function(err, metadata){
56
+ * //...
57
+ * })
58
+ *
59
+ * The config parameter is an object that contains information on the
60
+ * metadata servers.
61
+ */
62
+ getCloudMetadata(config, cb) {
63
+ // normalize arguments
64
+ if (!cb) {
65
+ cb = config;
66
+ config = {};
67
+ }
68
+
69
+ // fill in blanks if any expected keys are missing
70
+ config.aws = config.aws ? config.aws : null;
71
+ config.azure = config.azure ? config.azure : null;
72
+ config.gcp = config.gcp ? config.gcp : null;
73
+
74
+ const fetcher = new CallbackCoordination(
75
+ COORDINATION_TIMEOUT_MS,
76
+ this.logger,
77
+ );
78
+
79
+ if (this.shouldFetchGcp()) {
80
+ fetcher.schedule((fetcher) => {
81
+ const url = config.gcp;
82
+ getMetadataGcp(
83
+ CONNECT_TIMEOUT_MS + DNS_TIMEOUT_MS,
84
+ HTTP_TIMEOUT_MS,
85
+ this.logger,
86
+ url,
87
+ (err, result) => {
88
+ fetcher.recordResult(err, result);
89
+ },
90
+ );
91
+ });
92
+ }
93
+
94
+ if (this.shouldFetchAws()) {
95
+ fetcher.schedule((fetcher) => {
96
+ const url = config.aws;
97
+ getMetadataAws(
98
+ CONNECT_TIMEOUT_MS,
99
+ HTTP_TIMEOUT_MS,
100
+ this.logger,
101
+ url,
102
+ function (err, result) {
103
+ fetcher.recordResult(err, result);
104
+ },
105
+ );
106
+ });
107
+ }
108
+
109
+ if (this.shouldFetchAzure()) {
110
+ fetcher.schedule((fetcher) => {
111
+ const url = config.azure;
112
+ getMetadataAzure(
113
+ CONNECT_TIMEOUT_MS,
114
+ HTTP_TIMEOUT_MS,
115
+ this.logger,
116
+ url,
117
+ function (err, result) {
118
+ fetcher.recordResult(err, result);
119
+ },
120
+ );
121
+ });
122
+ }
123
+
124
+ fetcher.on('result', function (result) {
125
+ cb(null, result);
126
+ });
127
+
128
+ fetcher.on('error', function (err) {
129
+ cb(err);
130
+ });
131
+
132
+ fetcher.start();
133
+ }
134
+
135
+ shouldFetchGcp() {
136
+ return this.cloudProvider === 'auto' || this.cloudProvider === 'gcp';
137
+ }
138
+
139
+ shouldFetchAzure() {
140
+ return this.cloudProvider === 'auto' || this.cloudProvider === 'azure';
141
+ }
142
+
143
+ shouldFetchAws() {
144
+ return this.cloudProvider === 'auto' || this.cloudProvider === 'aws';
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Simple Command Line interface to fetch metadata
150
+ *
151
+ * $ node lib/cloud-metadata/index.js
152
+ *
153
+ * Will output metadata object or error if no servers are reachable
154
+ */
155
+ function main(args) {
156
+ const cloudMetadata = new CloudMetadata('auto', logging.createLogger('off'));
157
+ cloudMetadata.getCloudMetadata(function (err, metadata) {
158
+ if (err) {
159
+ console.log('could not fetch metadata, see error below');
160
+ console.log(err);
161
+ process.exit(1);
162
+ } else {
163
+ console.log('fetched the following metadata');
164
+ console.log(metadata);
165
+ process.exit(0);
166
+ }
167
+ });
168
+ }
169
+
170
+ if (require.main === module) {
171
+ main(process.argv);
172
+ }
173
+ module.exports = {
174
+ CloudMetadata,
175
+ };
@@ -0,0 +1,458 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const truncate = require('unicode-byte-truncate');
13
+
14
+ const { INTAKE_STRING_MAX_SIZE, REDACTED } = require('../constants');
15
+ const logging = require('../logging');
16
+ const { NoopApmClient } = require('../apm-client/noop-apm-client');
17
+ const { isLambdaExecutionEnvironment } = require('../lambda');
18
+ const {
19
+ isAzureFunctionsEnvironment,
20
+ } = require('../instrumentation/azure-functions');
21
+
22
+ const {
23
+ BOOL_OPTS,
24
+ NUM_OPTS,
25
+ DURATION_OPTS,
26
+ BYTES_OPTS,
27
+ MINUS_ONE_EQUAL_INFINITY,
28
+ ARRAY_OPTS,
29
+ KEY_VALUE_OPTS,
30
+ URL_OPTS,
31
+ getDefaultOptions,
32
+ getEnvironmentOptions,
33
+ getFileOptions,
34
+ setStartOptions,
35
+ getPreambleData,
36
+ readEnvOptions,
37
+ CENTRAL_CONFIG_OPTS,
38
+ } = require('./schema');
39
+
40
+ const {
41
+ normalizeUrls,
42
+ normalizeArrays,
43
+ normalizeBools,
44
+ normalizeBytes,
45
+ normalizeDurationOptions,
46
+ normalizeIgnoreOptions,
47
+ normalizeInfinity,
48
+ normalizeKeyValuePairs,
49
+ normalizeNumbers,
50
+ normalizeElasticsearchCaptureBodyUrls,
51
+ normalizeDisableMetrics,
52
+ normalizeSanitizeFieldNames,
53
+ normalizeCloudProvider,
54
+ normalizeCustomMetricsHistogramBoundaries,
55
+ normalizeTransactionSampleRate,
56
+ normalizeTraceContinuationStrategy,
57
+ normalizeContextManager,
58
+ normalizeSpanStackTraceMinDuration,
59
+ } = require('./normalizers');
60
+
61
+ const EXCLUDE_FIELDS = {
62
+ logger: true,
63
+ transport: true,
64
+ };
65
+ const REDACT_FIELDS = {
66
+ apiKey: true,
67
+ secretToken: true,
68
+ serverUrl: true,
69
+ };
70
+ const NICE_REGEXPS_FIELDS = {
71
+ disableMetricsRegExp: true,
72
+ ignoreUrlRegExp: true,
73
+ ignoreUserAgentRegExp: true,
74
+ transactionIgnoreUrlRegExp: true,
75
+ sanitizeFieldNamesRegExp: true,
76
+ ignoreMessageQueuesRegExp: true,
77
+ };
78
+
79
+ const confDefaultOptions = getDefaultOptions();
80
+ const confEnvOpts = getEnvironmentOptions();
81
+ let confFileOpts = getFileOptions();
82
+
83
+ // Configure a logger for the agent.
84
+ //
85
+ // This is separate from `createConfig` to allow the agent to have an early
86
+ // logger before `agent.start()` is called.
87
+ function configLogger(opts = {}) {
88
+ const logLevel =
89
+ confEnvOpts.logLevel ||
90
+ opts.logLevel ||
91
+ (confFileOpts && confFileOpts.logLevel) ||
92
+ confDefaultOptions.logLevel;
93
+
94
+ // `ELASTIC_APM_LOGGER=false` is provided as a mechanism to *disable* a
95
+ // custom logger for troubleshooting because a wrapped custom logger does
96
+ // not get structured log data.
97
+ // https://www.elastic.co/guide/en/apm/agent/nodejs/current/troubleshooting.html#debug-mode
98
+ let customLogger = null;
99
+ if (process.env.ELASTIC_APM_LOGGER !== 'false') {
100
+ customLogger = opts.logger || (confFileOpts && confFileOpts.logger);
101
+ }
102
+
103
+ return logging.createLogger(logLevel, customLogger);
104
+ }
105
+
106
+ // Create an initial configuration from DEFAULTS. This is used as a stand-in
107
+ // for Agent configuration until `agent.start(...)` is called.
108
+ function initialConfig(logger) {
109
+ const cfg = Object.assign({}, confDefaultOptions);
110
+
111
+ normalize(cfg, logger);
112
+
113
+ cfg.transport = new NoopApmClient();
114
+
115
+ return cfg;
116
+ }
117
+
118
+ function createConfig(opts, logger) {
119
+ return new Config(opts, logger);
120
+ }
121
+
122
+ class Config {
123
+ constructor(opts, logger) {
124
+ // TODO: remove this call once config and logging-preamble tests are refactored
125
+ readEnvOptions();
126
+
127
+ const isLambda = isLambdaExecutionEnvironment();
128
+ const envOptions = getEnvironmentOptions();
129
+
130
+ setStartOptions(opts);
131
+
132
+ Object.assign(
133
+ this,
134
+ confDefaultOptions, // default options
135
+ getFileOptions(), // options read from config file
136
+ opts, // options passed in to agent.start()
137
+ envOptions, // options read from environment variables
138
+ );
139
+
140
+ // The logger is used later in this function, so create/update it first.
141
+ // Unless a new custom `logger` was provided, we use the one created earlier
142
+ // in `configLogger()`.
143
+ const customLogger =
144
+ process.env.ELASTIC_APM_LOGGER === 'false' ? null : this.logger;
145
+ if (!customLogger && logger) {
146
+ logging.setLogLevel(logger, this.logLevel);
147
+ this.logger = logger;
148
+ } else {
149
+ this.logger = logging.createLogger(this.logLevel, customLogger);
150
+ }
151
+
152
+ // Fallback and validation handling for `serviceName` and `serviceVersion`.
153
+ if (this.serviceName) {
154
+ // A value here means an explicit value was given. Error out if invalid.
155
+ try {
156
+ validateServiceName(this.serviceName);
157
+ } catch (err) {
158
+ this.logger.error(
159
+ 'serviceName "%s" is invalid: %s',
160
+ this.serviceName,
161
+ err.message,
162
+ );
163
+ this.serviceName = null;
164
+ }
165
+ } else {
166
+ if (isLambda) {
167
+ this.serviceName = process.env.AWS_LAMBDA_FUNCTION_NAME;
168
+ } else if (isAzureFunctionsEnvironment && process.env.WEBSITE_SITE_NAME) {
169
+ this.serviceName = process.env.WEBSITE_SITE_NAME;
170
+ }
171
+ if (this.serviceName) {
172
+ try {
173
+ validateServiceName(this.serviceName);
174
+ } catch (err) {
175
+ this.logger.warn(
176
+ '"%s" is not a valid serviceName: %s',
177
+ this.serviceName,
178
+ err.message,
179
+ );
180
+ this.serviceName = null;
181
+ }
182
+ }
183
+ if (!this.serviceName) {
184
+ // Zero-conf support: use package.json#name, else
185
+ // `unknown-${service.agent.name}-service`.
186
+ try {
187
+ this.serviceName = serviceNameFromPackageJson();
188
+ } catch (err) {
189
+ this.logger.warn(err.message);
190
+ }
191
+ if (!this.serviceName) {
192
+ this.serviceName = 'unknown-nodejs-service';
193
+ }
194
+ }
195
+ }
196
+ if (this.serviceVersion) {
197
+ // pass
198
+ } else if (isLambda) {
199
+ this.serviceVersion = process.env.AWS_LAMBDA_FUNCTION_VERSION;
200
+ } else if (isAzureFunctionsEnvironment && process.env.WEBSITE_SITE_NAME) {
201
+ // Leave this empty. There isn't a meaningful service version field
202
+ // in Azure Functions envvars, and falling back to package.json ends up
203
+ // finding the version of the "azure-functions-core-tools" package.
204
+ } else {
205
+ // Zero-conf support: use package.json#version, if possible.
206
+ try {
207
+ this.serviceVersion = serviceVersionFromPackageJson();
208
+ } catch (err) {
209
+ // pass
210
+ }
211
+ }
212
+
213
+ normalize(this, this.logger);
214
+
215
+ if (isLambda || isAzureFunctionsEnvironment) {
216
+ // Override some config in AWS Lambda or Azure Functions environments.
217
+ this.metricsInterval = 0;
218
+ this.cloudProvider = 'none';
219
+ this.centralConfig = false;
220
+ }
221
+ if (this.metricsInterval === 0) {
222
+ this.breakdownMetrics = false;
223
+ }
224
+
225
+ this.loggingPreambleData = getPreambleData(this);
226
+ }
227
+
228
+ // Return a reasonably loggable object for this Config instance.
229
+ // Exclude undefined fields and complex objects like `logger`.
230
+ toJSON() {
231
+ const loggable = {};
232
+ for (const k in this) {
233
+ if (EXCLUDE_FIELDS[k] || this[k] === undefined) {
234
+ // pass
235
+ } else if (REDACT_FIELDS[k]) {
236
+ loggable[k] = REDACTED;
237
+ } else if (NICE_REGEXPS_FIELDS[k] && Array.isArray(this[k])) {
238
+ // JSON.stringify() on a RegExp is "{}", which isn't very helpful.
239
+ loggable[k] = this[k].map((r) =>
240
+ r instanceof RegExp ? r.toString() : r,
241
+ );
242
+ } else {
243
+ loggable[k] = this[k];
244
+ }
245
+ }
246
+ return loggable;
247
+ }
248
+
249
+ // Returns an object showing the current config, excluding default values.
250
+ getCurrConfig() {
251
+ const currConfig = {};
252
+
253
+ // Start with the values from the logging preamble. This selected keys
254
+ // that were specified, and handles redaction.
255
+ for (let [k, v] of Object.entries(this.loggingPreambleData.config)) {
256
+ currConfig[k] = v.value;
257
+ }
258
+
259
+ // Then add the current value of any var possibly set by central config.
260
+ currConfig.centralConfig = this.centralConfig;
261
+ if (this.centralConfig) {
262
+ for (let k of Object.values(CENTRAL_CONFIG_OPTS)) {
263
+ currConfig[k] = this[k];
264
+ }
265
+ }
266
+
267
+ return currConfig;
268
+ }
269
+ }
270
+
271
+ function validateServiceName(s) {
272
+ if (typeof s !== 'string') {
273
+ throw new Error('not a string');
274
+ } else if (!/^[a-zA-Z0-9 _-]+$/.test(s)) {
275
+ throw new Error(
276
+ 'contains invalid characters (allowed: a-z, A-Z, 0-9, _, -, <space>)',
277
+ );
278
+ }
279
+ }
280
+
281
+ // findPkgInfo() looks up from the script dir (or cwd) for a "package.json" file
282
+ // from which to load the name and version. It returns:
283
+ // {
284
+ // startDir: "<full path to starting dir>",
285
+ // path: "/the/full/path/to/package.json", // may be null
286
+ // data: {
287
+ // name: "<the package name>", // may be missing
288
+ // version: "<the package version>" // may be missing
289
+ // }
290
+ // }
291
+ let pkgInfoCache;
292
+ function findPkgInfo() {
293
+ if (pkgInfoCache === undefined) {
294
+ // Determine a good starting dir from which to look for a "package.json".
295
+ let startDir =
296
+ require.main &&
297
+ require.main.filename &&
298
+ path.dirname(require.main.filename);
299
+ if (!startDir && process.argv[1]) {
300
+ // 'require.main' is undefined if the agent is preloaded with `node
301
+ // --require elastic-apm-node/... script.js`.
302
+ startDir = path.dirname(process.argv[1]);
303
+ }
304
+ if (!startDir) {
305
+ startDir = process.cwd();
306
+ }
307
+ pkgInfoCache = {
308
+ startDir,
309
+ path: null,
310
+ data: {},
311
+ };
312
+
313
+ // Look up from the starting dir for a "package.json".
314
+ const { root } = path.parse(startDir);
315
+ let dir = startDir;
316
+ while (true) {
317
+ const pj = path.resolve(dir, 'package.json');
318
+ if (fs.existsSync(pj)) {
319
+ pkgInfoCache.path = pj;
320
+ break;
321
+ }
322
+ if (dir === root) {
323
+ break;
324
+ }
325
+ dir = path.dirname(dir);
326
+ }
327
+
328
+ // Attempt to load "name" and "version" from the package.json.
329
+ if (pkgInfoCache.path) {
330
+ try {
331
+ const data = JSON.parse(fs.readFileSync(pkgInfoCache.path));
332
+ if (data.name) {
333
+ // For backward compatibility, maintain the trimming done by
334
+ // https://github.com/npm/normalize-package-data#what-normalization-currently-entails
335
+ pkgInfoCache.data.name = data.name.trim();
336
+ }
337
+ if (data.version) {
338
+ pkgInfoCache.data.version = data.version;
339
+ }
340
+ } catch (_err) {
341
+ // Silently leave data empty.
342
+ }
343
+ }
344
+ }
345
+ return pkgInfoCache;
346
+ }
347
+
348
+ function serviceNameFromPackageJson() {
349
+ const pkg = findPkgInfo();
350
+ if (!pkg.path) {
351
+ throw new Error(
352
+ `could not infer serviceName: could not find package.json up from ${pkg.startDir}`,
353
+ );
354
+ }
355
+ if (!pkg.data.name) {
356
+ throw new Error(
357
+ `could not infer serviceName: "${pkg.path}" does not contain a "name"`,
358
+ );
359
+ }
360
+ if (typeof pkg.data.name !== 'string') {
361
+ throw new Error(
362
+ `could not infer serviceName: "name" in "${pkg.path}" is not a string`,
363
+ );
364
+ }
365
+ let serviceName = pkg.data.name;
366
+
367
+ // Normalize a namespaced npm package name, '@ns/name', to 'ns-name'.
368
+ const match = /^@([^/]+)\/([^/]+)$/.exec(serviceName);
369
+ if (match) {
370
+ serviceName = match[1] + '-' + match[2];
371
+ }
372
+
373
+ // Sanitize, by replacing invalid service name chars with an underscore.
374
+ const SERVICE_NAME_BAD_CHARS = /[^a-zA-Z0-9 _-]/g;
375
+ serviceName = serviceName.replace(SERVICE_NAME_BAD_CHARS, '_');
376
+
377
+ // Disallow some weird sanitized values. For example, it is better to
378
+ // have the fallback "unknown-{service.agent.name}-service" than "_" or
379
+ // "____" or " ".
380
+ const ALL_NON_ALPHANUMERIC = /^[ _-]*$/;
381
+ if (ALL_NON_ALPHANUMERIC.test(serviceName)) {
382
+ serviceName = null;
383
+ }
384
+ if (!serviceName) {
385
+ throw new Error(
386
+ `could not infer serviceName from name="${pkg.data.name}" in "${pkg.path}"`,
387
+ );
388
+ }
389
+
390
+ return serviceName;
391
+ }
392
+
393
+ function serviceVersionFromPackageJson() {
394
+ const pkg = findPkgInfo();
395
+ if (!pkg.path) {
396
+ throw new Error(
397
+ `could not infer serviceVersion: could not find package.json up from ${pkg.startDir}`,
398
+ );
399
+ }
400
+ if (!pkg.data.version) {
401
+ throw new Error(
402
+ `could not infer serviceVersion: "${pkg.path}" does not contain a "version"`,
403
+ );
404
+ }
405
+ if (typeof pkg.data.version !== 'string') {
406
+ throw new Error(
407
+ `could not infer serviceVersion: "version" in "${pkg.path}" is not a string`,
408
+ );
409
+ }
410
+ return pkg.data.version;
411
+ }
412
+
413
+ function normalize(opts, logger) {
414
+ const defaults = confDefaultOptions;
415
+
416
+ normalizeKeyValuePairs(opts, KEY_VALUE_OPTS, defaults, logger);
417
+ normalizeNumbers(opts, NUM_OPTS, defaults, logger);
418
+ normalizeInfinity(opts, MINUS_ONE_EQUAL_INFINITY, defaults, logger);
419
+ normalizeBytes(opts, BYTES_OPTS, defaults, logger);
420
+ normalizeArrays(opts, ARRAY_OPTS, defaults, logger);
421
+ normalizeDurationOptions(opts, DURATION_OPTS, defaults, logger);
422
+ normalizeBools(opts, BOOL_OPTS, defaults, logger);
423
+ normalizeIgnoreOptions(opts);
424
+ normalizeElasticsearchCaptureBodyUrls(opts);
425
+ normalizeDisableMetrics(opts);
426
+ normalizeSanitizeFieldNames(opts);
427
+ normalizeContextManager(opts, [], defaults, logger);
428
+ normalizeCloudProvider(opts, [], defaults, logger);
429
+ normalizeTransactionSampleRate(opts, [], defaults, logger);
430
+ normalizeTraceContinuationStrategy(opts, [], defaults, logger);
431
+ normalizeCustomMetricsHistogramBoundaries(opts, [], defaults, logger);
432
+ normalizeUrls(opts, URL_OPTS, defaults, logger);
433
+
434
+ // This must be after `normalizeDurationOptions()` and `normalizeBools()`
435
+ // because it synthesizes the deprecated `spanFramesMinDuration` and
436
+ // `captureSpanStackTraces` options into `spanStackTraceMinDuration`.
437
+ normalizeSpanStackTraceMinDuration(opts, [], defaults, logger);
438
+
439
+ truncateOptions(opts);
440
+ }
441
+
442
+ function truncateOptions(opts) {
443
+ if (opts.serviceVersion)
444
+ opts.serviceVersion = truncate(
445
+ String(opts.serviceVersion),
446
+ INTAKE_STRING_MAX_SIZE,
447
+ );
448
+ if (opts.hostname)
449
+ opts.hostname = truncate(String(opts.hostname), INTAKE_STRING_MAX_SIZE);
450
+ }
451
+
452
+ // Exports.
453
+ module.exports = {
454
+ configLogger,
455
+ initialConfig,
456
+ createConfig,
457
+ normalize,
458
+ };