@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,485 @@
1
+ # http-apm-client
2
+
3
+ A low-level HTTP client for communicating with the Elastic APM intake
4
+ API version 2. This code was moved here from the once-separate
5
+ [Elastic APM HTTP client repo](https://github.com/elastic/apm-nodejs-http-client)
6
+
7
+
8
+ ## Example Usage
9
+
10
+ ```js
11
+ const { HttpApmClient } = require('path/to/lib/http-apm-client')
12
+
13
+ const client = new HttpApmClient({
14
+ serviceName: 'My App',
15
+ agentName: 'my-nodejs-agent',
16
+ agentVersion: require('./package.json').version,
17
+ userAgent: 'My Custom Elastic APM Agent'
18
+ // ... other options.
19
+ })
20
+
21
+ const span = {
22
+ name: 'SELECT FROM users',
23
+ duration: 42,
24
+ start: 0,
25
+ type: 'db.mysql.query'
26
+ }
27
+
28
+ client.sendSpan(span)
29
+ ```
30
+
31
+ ## API
32
+
33
+ ### `new HttpApmClient(options)`
34
+
35
+ Construct a new `client` object. Data given to the client will be
36
+ converted to ndjson, compressed using gzip, and streamed to the APM
37
+ Server.
38
+
39
+ Arguments:
40
+
41
+ - `options` - An object containing config options (see below). All options
42
+ are optional, except those marked "(required)".
43
+
44
+ Data sent to the APM Server as part of the [metadata object](https://www.elastic.co/guide/en/apm/server/current/metadata-api.html).
45
+ See also the "Cloud & Extra Metadata" section below.
46
+
47
+ - `agentName` - (required) The APM agent name
48
+ - `agentVersion` - (required) The APM agent version
49
+ - `agentActivationMethod` - An enum string ([spec](https://github.com/elastic/apm/blob/main/specs/agents/metadata.md#activation-method)) that identifies the way this agent was activated/started
50
+ - `serviceName` - (required) The name of the service being instrumented
51
+ - `serviceNodeName` - Unique name of the service being instrumented
52
+ - `serviceVersion` - The version of the service being instrumented
53
+ - `frameworkName` - If the service being instrumented is running a
54
+ specific framework, use this config option to log its name
55
+ - `frameworkVersion` - If the service being instrumented is running a
56
+ specific framework, use this config option to log its version
57
+ - `configuredHostname` - A user-configured hostname, if any, e.g. from the `ELASTIC_APM_HOSTNAME` envvar.
58
+ See <https://github.com/elastic/apm/blob/main/specs/agents/metadata.md#hostname>.
59
+ - `environment` - Environment name (e.g. 'development', 'production')
60
+ - `containerId` - Docker container id, if not given will be parsed from `/proc/self/cgroup`
61
+ - `kubernetesNodeName` - Kubernetes node name
62
+ - `kubernetesNamespace` - Kubernetes namespace
63
+ - `kubernetesPodName` - Kubernetes pod name, if not given will be the hostname
64
+ - `kubernetesPodUID` - Kubernetes pod id, if not given will be parsed from `/proc/self/cgroup`
65
+ - `globalLabels` - An object of key/value pairs to use to label all data reported (only applied when using APM Server 7.1+)
66
+
67
+ HTTP client configuration:
68
+
69
+ - `userAgent` - (required) The HTTP user agent that your module should
70
+ identify itself as
71
+ - `secretToken` - The Elastic APM intake API secret token
72
+ - `apiKey` - Elastic APM API key
73
+ - `serverUrl` - The APM Server URL (default: `http://127.0.0.1:8200`)
74
+ - `headers` - An object containing extra HTTP headers that should be
75
+ used when making HTTP requests to he APM Server
76
+ - `rejectUnauthorized` - Set to `false` if the client shouldn't verify
77
+ the APM Server TLS certificates (default: `true`)
78
+ - `serverCaCert` - The CA certificate used to verify the APM Server's
79
+ TLS certificate, and has the same requirements as the `ca` option
80
+ of [`tls.createSecureContext`](https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options).
81
+ - `serverTimeout` - HTTP request timeout in milliseconds. If no data is
82
+ sent or received on the socket for this amount of time, the request
83
+ will be aborted. It's not recommended to set a `serverTimeout` lower
84
+ than the `time` config option. That might result in healthy requests
85
+ being aborted prematurely. (default: `15000` ms)
86
+ - `keepAlive` - If set the `false` the client will not reuse sockets
87
+ between requests (default: `true`)
88
+ - `keepAliveMsecs` - When using the `keepAlive` option, specifies the
89
+ initial delay for TCP Keep-Alive packets. Ignored when the `keepAlive`
90
+ option is `false` or `undefined` (default: `1000` ms)
91
+ - `maxSockets` - Maximum number of sockets to allow per host (default:
92
+ `Infinity`)
93
+ - `maxFreeSockets` - Maximum number of sockets to leave open in a free
94
+ state. Only relevant if `keepAlive` is set to `true` (default: `256`)
95
+ - `freeSocketTimeout` - A number of milliseconds of inactivity on a free
96
+ (kept-alive) socket after which to timeout and recycle the socket. Set this to
97
+ a value less than the HTTP Keep-Alive timeout of the APM server to avoid
98
+ [ECONNRESET exceptions](https://medium.com/ssense-tech/reduce-networking-errors-in-nodejs-23b4eb9f2d83).
99
+ This defaults to 4000ms to be less than the [node.js HTTP server default of
100
+ 5s](https://nodejs.org/api/http.html#serverkeepalivetimeout) (useful when
101
+ using a Node.js-based mock APM server) and the [Go lang Dialer `KeepAlive`
102
+ default of 15s](https://pkg.go.dev/net#Dialer) (when talking to the Elastic
103
+ APM Lambda extension). (default: `4000`)
104
+
105
+ Cloud & Extra Metadata Configuration. Zero or one of the following three
106
+ options may be used.
107
+
108
+ - `cloudMetadataFetcher` - An object with a `getCloudMetadata(cb)` method
109
+ for fetching metadata related to the current cloud environment. The callback
110
+ is of the form `function (err, cloudMetadata)` and the returned `cloudMetadata`
111
+ will be set on `metadata.cloud` for intake requests to APM Server. If
112
+ provided, this client will not begin any intake requests until the callback
113
+ is called.
114
+ - `expectExtraMetadata` - A boolean option to indicate that the client should
115
+ not allow any intake requests to begin until `cloud.setExtraMetadata(...)`
116
+ has been called. It is the responsibility of the caller to call
117
+ `cloud.setExtraMetadata()`. If not, then the Client will never perform an
118
+ intake request.
119
+ - `extraMetadata` - An object with extra metadata to merge into the metadata
120
+ object created from the individual fields above.
121
+
122
+ APM Agent Configuration via Kibana:
123
+
124
+ - `centralConfig` - Whether or not the client should poll the APM
125
+ Server regularly for new agent configuration. If set to `true`, the
126
+ `config` event will be emitted when there's an update to an agent config
127
+ option (default: `false`). _Requires APM Server v7.3 or later and that
128
+ the APM Server is configured with `kibana.enabled: true`._
129
+
130
+ Streaming configuration:
131
+
132
+ - `size` - The maxiumum compressed body size (in bytes) of each HTTP
133
+ request to the APM Server. An overshoot of up to the size of the
134
+ internal zlib buffer should be expected as the buffer is flushed after
135
+ this limit is reached. The default zlib buffer size is 16kB. (default:
136
+ `768000` bytes)
137
+ - `time` - The maxiumum number of milliseconds a streaming HTTP request
138
+ to the APM Server can be ongoing before it's ended. Set to `-1` to
139
+ disable (default: `10000` ms)
140
+ - `bufferWindowTime` - Objects written in quick succession are buffered
141
+ and grouped into larger clusters that can be processed as a whole.
142
+ This config option controls the maximum time that buffer can live
143
+ before it's flushed (counted in milliseconds). Set to `-1` for no
144
+ buffering (default: `20` ms)
145
+ - `bufferWindowSize` - Objects written in quick succession are buffered
146
+ and grouped into larger clusters that can be processed as a whole.
147
+ This config option controls the maximum size of that buffer (counted
148
+ in number of objects). Set to `-1` for no max size (default: `50`
149
+ objects)
150
+ - `maxQueueSize` - The maximum number of buffered events (transactions,
151
+ spans, errors, metricsets). Events are buffered when the agent can't keep
152
+ up with sending them to the APM Server or if the APM server is down.
153
+ If the queue is full, events are rejected which means transactions, spans,
154
+ etc. will be lost. This guards the application from consuming unbounded
155
+ memory, possibly overusing CPU (spent on serializing events), and possibly
156
+ crashing in case the APM server is unavailable for a long period of time. A
157
+ lower value will decrease the heap overhead of the agent, while a higher
158
+ value makes it less likely to lose events in case of a temporary spike in
159
+ throughput. (default: 1024)
160
+ - `intakeResTimeout` - The time (in milliseconds) by which a response from the
161
+ [APM Server events intake API](https://www.elastic.co/guide/en/apm/server/current/events-api.html)
162
+ is expected *after all the event data for that request has been sent*. This
163
+ allows a smaller timeout than `serverTimeout` to handle an APM server that
164
+ is accepting connections but is slow to respond. (default: `10000` ms)
165
+ - `intakeResTimeoutOnEnd` - The same as `intakeResTimeout`, but used when
166
+ the client has ended, hence for the possible last request to APM server. This
167
+ is typically a lower value to not hang an ending process that is waiting for
168
+ that APM server request to complete. (default: `1000` ms)
169
+
170
+ Data sanitizing configuration:
171
+
172
+ - `truncateKeywordsAt` - Maximum size in unicode characters for strings stored
173
+ as Elasticsearch keywords. Strings larger than this will be trucated
174
+ (default: `1024`)
175
+ - `truncateLongFieldsAt` - The maximum size in unicode characters for a
176
+ specific set of long string fields. String values above this length will be
177
+ truncated. Default: `10000`. This applies to the following fields:
178
+ - `transaction.context.request.body`, `error.context.request.body`
179
+ - `transaction.context.message.body`, `span.context.message.body`, `error.context.message.body`
180
+ - `span.context.db.statement`
181
+ - `error.exception.message` (unless `truncateErrorMessagesAt` is specified)
182
+ - `error.log.message` (unless `truncateErrorMessagesAt` is specified)
183
+ - `truncateStringsAt` - The maximum size in unicode characters for strings.
184
+ String values above this length will be truncated (default: `1024`)
185
+ - `truncateErrorMessagesAt` - **DEPRECATED:** prefer `truncateLongFieldsAt`.
186
+ The maximum size in unicode characters for error messages. Messages above this
187
+ length will be truncated. Set to `-1` to disable truncation. This applies to
188
+ the following properties: `error.exception.message` and `error.log.message`.
189
+ (default: `2048`)
190
+
191
+ Other options:
192
+
193
+ - `logger` - A [pino](https://getpino.io) logger to use for trace and
194
+ debug-level logging.
195
+ - `payloadLogFile` - Specify a file path to which a copy of all data
196
+ sent to the APM Server should be written. The data will be in ndjson
197
+ format and will be uncompressed. Note that using this option can
198
+ impact performance.
199
+ - `apmServerVersion` - A string version to assume is the version of the
200
+ APM Server at `serverUrl`. This option is typically only used for testing.
201
+ Normally this client will fetch the APM Server version at startup via a
202
+ `GET /` request. Setting this option avoids that request.
203
+
204
+ ### Event: `config`
205
+
206
+ Emitted every time a change to the agent config is pulled from the APM
207
+ Server. The listener is passed the updated config options as a key/value
208
+ object.
209
+
210
+ Each key is the lowercase version of the environment variable, without
211
+ the `ELASTIC_APM_` prefix, e.g. `transaction_sample_rate` instead of
212
+ `ELASTIC_APM_TRANSACTION_SAMPLE_RATE`.
213
+
214
+ If no central configuration is set up for the given `serviceName` /
215
+ `environment` when the client is started, this event will be emitted
216
+ once with an empty object. This will also happen after central
217
+ configuration for the given `serviceName` / `environment` is deleted.
218
+
219
+ ### Event: `close`
220
+
221
+ The `close` event is emitted when the client and any of its underlying
222
+ resources have been closed. The event indicates that no more events will
223
+ be emitted, and no more data can be sent by the client.
224
+
225
+ ### Event: `error`
226
+
227
+ Emitted if an error occurs. The listener callback is passed a single
228
+ Error argument when called.
229
+
230
+ ### Event: `finish`
231
+
232
+ The `finish` event is emitted after the `client.end()` method has been
233
+ called, and all data has been flushed to the underlying system.
234
+
235
+ ### Event: `request-error`
236
+
237
+ Emitted if an error occurs while communicating with the APM Server. The
238
+ listener callback is passed a single Error argument when called.
239
+
240
+ The request to the APM Server that caused the error is terminated and
241
+ the data included in that request is lost. This is normally only
242
+ important to consider for requests to the Intake API.
243
+
244
+ If a non-2xx response was received from the APM Server, the status code
245
+ will be available on `error.code`.
246
+
247
+ For requests to the Intake API where the response is a structured error
248
+ message, the `error` object will have the following properties:
249
+
250
+ - `error.accepted` - An integer indicating how many events was accepted
251
+ as part of the failed request. If 100 events was sent to the APM
252
+ Server as part of the request, and the error reports only 98 as
253
+ accepted, it means that two events either wasn't received or couldn't
254
+ be processed for some reason
255
+ - `error.errors` - An array of error messages. Each element in the array
256
+ is an object containing a `message` property (String) and an optional
257
+ `document` property (String). If the `document` property is given it
258
+ will contain the failed event as it was received by the APM Server
259
+
260
+ If the response contained an error body that could not be parsed by the
261
+ client, the raw body will be available on `error.response`.
262
+
263
+ The client is not closed when the `request-error` event is emitted.
264
+
265
+ ### `client.sent`
266
+
267
+ An integer indicating the number of events (spans, transactions, errors, or
268
+ metricsets) sent by the client. An event is considered sent when the HTTP
269
+ request used to transmit it has ended. Note that errors in requests to APM
270
+ server may mean this value is not the same as the number of events *accepted*
271
+ by the APM server.
272
+
273
+ ### `client.config(options)`
274
+
275
+ Update the configuration given to the `Client` constructor. All
276
+ configuration options can be updated except:
277
+
278
+ - `size`
279
+ - `time`
280
+ - `keepAlive`
281
+ - `keepAliveMsecs`
282
+ - `maxSockets`
283
+ - `maxFreeSockets`
284
+ - `centralConfig`
285
+
286
+ ### `client.supportsKeepingUnsampledTransaction()`
287
+
288
+ This method returns a boolean indicating whether the remote APM Server (per
289
+ the configured `serverUrl`) is of a version that requires unsampled transactions
290
+ to be sent.
291
+
292
+ This defaults to `true` if the remote APM server version is not known -- either
293
+ because the background fetch of the APM Server version hasn't yet completed,
294
+ or the version could not be fetched.
295
+
296
+ ### `client.supportsActivationMethodField()`
297
+
298
+ This method returns a boolean indicating whether the remote APM Server (per
299
+ the configured `serverUrl`) is of a version that supports the
300
+ `metadata.service.agent.activation_method` field. This is true for APM server
301
+ versions >=8.7.1. It defaults to true if the APM server version is not (yet)
302
+ known.
303
+
304
+ ### `client.addMetadataFilter(fn)`
305
+
306
+ Add a filter function for the ["metadata" object](https://www.elastic.co/guide/en/apm/server/current/metadata-api.html)
307
+ sent to APM server. This will be called once at client creation, and possibly
308
+ again later if `client.config()` is called to reconfigure the client or
309
+ `client.addMetadataFilter(fn)` is called to add additional filters.
310
+
311
+ Here is an example of a filter that removes the `metadata.process.argv` field:
312
+
313
+ ```js
314
+ apm.addMetadataFilter(function dropArgv(md) {
315
+ if (md.process && md.process.argv) {
316
+ delete md.process.argv
317
+ }
318
+ return md
319
+ })
320
+ ```
321
+
322
+ It is up to the user to ensure the returned object conforms to the
323
+ [metadata schema](https://www.elastic.co/guide/en/apm/server/current/metadata-api.html),
324
+ otherwise APM data injest will be broken. An example of that (when used with
325
+ the Node.js APM agent) is this in the application's log:
326
+
327
+ ```
328
+ [2021-04-14T22:28:35.419Z] ERROR (elastic-apm-node): APM Server transport error (400): Unexpected APM Server response
329
+ APM Server accepted 0 events in the last request
330
+ Error: validation error: 'metadata' required
331
+ Document: {"metadata":null}
332
+ ```
333
+
334
+ See the [APM Agent `addMetadataFilter` documentation](https://www.elastic.co/guide/en/apm/agent/nodejs/current/agent-api.html#apm-add-metadata-filter)
335
+ for further details.
336
+
337
+ ### `client.setExtraMetadata([metadata])`
338
+
339
+ Add extra metadata to be included in the "metadata" object sent to APM Server in
340
+ intake requests. The given `metadata` object is merged into the metadata
341
+ determined from the client configuration.
342
+
343
+ The reason this exists is to allow some metadata to be provided asynchronously,
344
+ especially in combination with the `expectExtraMetadata` configuration option
345
+ to ensure that event data is not sent to APM Server until this extra metadata
346
+ is provided. For example, in an AWS Lambda function some metadata is not
347
+ available until the first function invocation -- which is some async time after
348
+ Client creation.
349
+
350
+ ### `client.lambdaStart()`
351
+
352
+ Tells the client that a Lambda function invocation has started.
353
+ See [Notes on Lambda Usage](#notes-on-lambda-usage) below.
354
+
355
+ ### `client.lambdaShouldRegisterTransactions()`
356
+
357
+ This returns a boolean indicating if the APM agent -- when running in a Lambda
358
+ environment -- should bother calling `client.lambdaRegisterTransaction(...)`.
359
+ This can help the APM agent avoid some processing gathering transaction data.
360
+
361
+ Typically the reason this would return `false` is when the Lambda extension is
362
+ too old to support registering transactions.
363
+
364
+
365
+ ### `client.lambdaRegisterTransaction(transaction, awsRequestId)`
366
+
367
+ Tells the Lambda Extension about the ongoing transaction, so that data can be
368
+ used to report the transaction in certain error cases -- e.g. a Lambda handler
369
+ timeout. See [Notes on Lambda Usage](#notes-on-lambda-usage) below.
370
+
371
+ Arguments:
372
+
373
+ - `transaction` - A transaction object that can be serialized to JSON.
374
+ - `awsRequestId` - The AWS request ID for this invocation. This is a UUID
375
+ available on the Lambda context object.
376
+
377
+ ### `client.sendSpan(span[, callback])`
378
+
379
+ Send a span to the APM Server.
380
+
381
+ Arguments:
382
+
383
+ - `span` - A span object that can be serialized to JSON
384
+ - `callback` - Callback is called when the `span` have been flushed to
385
+ the underlying system
386
+
387
+ ### `client.sendTransaction(transaction[, callback])`
388
+
389
+ Send a transaction to the APM Server.
390
+
391
+ Arguments:
392
+
393
+ - `transaction` - A transaction object that can be serialized to JSON
394
+ - `callback` - Callback is called when the `transaction` have been
395
+ flushed to the underlying system
396
+
397
+ ### `client.sendError(error[, callback])`
398
+
399
+ Send a error to the APM Server.
400
+
401
+ Arguments:
402
+
403
+ - `error` - A error object that can be serialized to JSON
404
+ - `callback` - Callback is called when the `error` have been flushed to
405
+ the underlying system
406
+
407
+ ### `client.sendMetricSet(metricset[, callback])`
408
+
409
+ Send a metricset to the APM Server.
410
+
411
+ Arguments:
412
+
413
+ - `error` - A error object that can be serialized to JSON
414
+ - `callback` - Callback is called when the `metricset` have been flushed to
415
+ the underlying system
416
+
417
+ ### `client.flush([opts,] [callback])`
418
+
419
+ Flush the internal buffer and end the current HTTP request to the APM
420
+ Server. If no HTTP request is in process nothing happens. In an AWS Lambda
421
+ environment this will also initiate a quicker shutdown of the intake request,
422
+ because the APM agent always flushes at the end of a Lambda handler.
423
+
424
+ Arguments:
425
+
426
+ - `opts`:
427
+ - `opts.lambdaEnd` - An optional boolean to indicate if this is the final
428
+ flush at the end of the Lambda function invocation. The client will do
429
+ some extra handling if this is the case. See notes in `client.lambdaStart()`
430
+ above.
431
+ - `callback` - Callback is called when the internal buffer has been
432
+ flushed and the HTTP request ended. If no HTTP request is in progress
433
+ the callback is called in the next tick.
434
+
435
+ ### `client.end([callback])`
436
+
437
+ Calling the `client.end()` method signals that no more data will be sent
438
+ to the `client`. If the internal buffer contains any data, this is
439
+ flushed before ending.
440
+
441
+ Arguments:
442
+
443
+ - `callback` - If provided, the optional `callback` function is attached
444
+ as a listener for the 'finish' event
445
+
446
+ ### `client.destroy()`
447
+
448
+ Destroy the `client`. After this call, the client has ended and
449
+ subsequent calls to `sendSpan()`, `sendTransaction()`, `sendError()`,
450
+ `flush()`, or `end()` will result in an error.
451
+
452
+ ## Notes on Lambda usage
453
+
454
+ To properly handle [data flushing for instrumented Lambda functions](https://github.com/elastic/apm/blob/main/specs/agents/tracing-instrumentation-aws-lambda.md#data-flushing)
455
+ this Client should be used as follows in a Lambda environment.
456
+
457
+ 1. Ensure that metadata is set before any of the following calls. Typically
458
+ in Lambda this is done by (a) configuring the client with
459
+ `expectExtraMetadata` and (b) calling `setExtraMetadata()` at the start of
460
+ the first invocation.
461
+
462
+ 2. When a Lambda invocation starts, `client.lambdaStart()` must be called.
463
+ The Client prevents intake requests to APM Server when in a Lambda
464
+ environment when a function invocation is *not* active. This is to ensure
465
+ that an intake request does not accidentally span a period when a Lambda VM
466
+ is frozen, which can lead to timeouts and lost APM data.
467
+
468
+ 3. When the transaction for this Lambda invocation has been created,
469
+ `await client.lambdaRegisterTransaction(<transaction>, <awsRequestId>)` should be
470
+ called. This is used to pass transaction details to the Lambda Extension so
471
+ a transaction can be reported in certain failure modes (e.g. a Lambda
472
+ handler timeout).
473
+
474
+ `client.lambdaShouldRegisterTransactions()` can be used to avoid gathering
475
+ data for this call.
476
+
477
+ 4. When a Lambda invocation finishes, `client.flush({lambdaEnd: true}, cb)`
478
+ must be called.
479
+
480
+ The `lambdaEnd: true` tells the Client to (a) mark the lambda as inactive so
481
+ a subsequent intake request is not started until the next invocation, and
482
+ (b) signal the Elastic AWS Lambda Extension that this invocation is done.
483
+ The user's Lambda handler should not finish until `cb` is called. This
484
+ ensures that the extension receives tracing data and the end signal before
485
+ the Lambda Runtime freezes the VM.
@@ -0,0 +1,41 @@
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
+ // Central config-related utilities for the APM http client.
10
+
11
+ const INTERVAL_DEFAULT_S = 300; // 5 min
12
+ const INTERVAL_MIN_S = 5;
13
+ const INTERVAL_MAX_S = 86400; // 1d
14
+
15
+ /**
16
+ * Determine an appropriate delay until the next fetch of Central Config.
17
+ * Default to 5 minutes, minimum 5s, max 1d.
18
+ *
19
+ * The maximum of 1d ensures we don't get surprised by an overflow value to
20
+ * `setTimeout` per https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value
21
+ *
22
+ * @param {Number|undefined} seconds - A number of seconds, typically pulled
23
+ * from a `Cache-Control: max-age=${seconds}` header on a previous central
24
+ * config request.
25
+ * @returns {Number}
26
+ */
27
+ function getCentralConfigIntervalS(seconds) {
28
+ if (typeof seconds !== 'number' || isNaN(seconds) || seconds <= 0) {
29
+ return INTERVAL_DEFAULT_S;
30
+ }
31
+ return Math.min(Math.max(seconds, INTERVAL_MIN_S), INTERVAL_MAX_S);
32
+ }
33
+
34
+ module.exports = {
35
+ getCentralConfigIntervalS,
36
+
37
+ // These are exported for testing.
38
+ INTERVAL_DEFAULT_S,
39
+ INTERVAL_MIN_S,
40
+ INTERVAL_MAX_S,
41
+ };
@@ -0,0 +1,111 @@
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
+
11
+ const uuidSource =
12
+ '[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}';
13
+ const containerSource = '[0-9a-f]{64}';
14
+ const taskSource = '[0-9a-f]{32}';
15
+ const awsEcsSource = '[0-9a-f]{32}-[0-9]{1,10}';
16
+
17
+ const lineReg = /^(\d+):([^:]*):(.+)$/;
18
+ const podReg = new RegExp(`pod(${uuidSource})(?:.slice)?$`);
19
+ const containerReg = new RegExp(
20
+ `(${uuidSource}|${containerSource})(?:.scope)?$`,
21
+ );
22
+ const taskReg = new RegExp(`^/ecs/(${taskSource})/.*$`);
23
+
24
+ let ecsMetadata;
25
+ resetEcsMetadata(process.env.ECS_CONTAINER_METADATA_FILE);
26
+
27
+ function resetEcsMetadata(file) {
28
+ ecsMetadata = ecsMetadataSync(file);
29
+ }
30
+
31
+ function parseLine(line) {
32
+ const [id, groups, path] = (line.match(lineReg) || []).slice(1);
33
+ const data = { id, groups, path };
34
+ const parts = path.split('/');
35
+ const basename = parts.pop();
36
+ const controllers = groups.split(',');
37
+ if (controllers) data.controllers = controllers;
38
+
39
+ const containerId = (basename.match(containerReg) || [])[1];
40
+ if (containerId) data.containerId = containerId;
41
+
42
+ const podId = (parts.pop().match(podReg) || [])[1];
43
+ if (podId) data.podId = podId.replace(/_/g, '-');
44
+
45
+ const taskId = (path.match(taskReg) || [])[1];
46
+ if (taskId) data.taskId = taskId;
47
+
48
+ // if we reach the end and there's still no conatinerId match
49
+ // and there's not an ECS metadata file, try the ECS regular
50
+ // expression in order to get a container id in fargate
51
+ if (!containerId && !ecsMetadata) {
52
+ if (basename.match(awsEcsSource)) {
53
+ data.containerId = basename;
54
+ }
55
+ }
56
+ return data;
57
+ }
58
+
59
+ function parse(contents) {
60
+ const data = {
61
+ entries: [],
62
+ };
63
+
64
+ for (let line of contents.split('\n')) {
65
+ line = line.trim();
66
+ if (line) {
67
+ const lineData = parseLine(line);
68
+ data.entries.push(lineData);
69
+ if (lineData.containerId) {
70
+ data.containerId = lineData.containerId;
71
+ }
72
+ if (lineData.podId) {
73
+ data.podId = lineData.podId;
74
+ }
75
+ if (lineData.taskId) {
76
+ data.taskId = lineData.taskId;
77
+ if (ecsMetadata) {
78
+ data.containerId = ecsMetadata.ContainerID;
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ return data;
85
+ }
86
+
87
+ function containerInfo(pid = 'self') {
88
+ return new Promise((resolve) => {
89
+ fs.readFile(`/proc/${pid}/cgroup`, (err, data) => {
90
+ resolve(err ? undefined : parse(data.toString()));
91
+ });
92
+ });
93
+ }
94
+
95
+ function containerInfoSync(pid = 'self') {
96
+ try {
97
+ const data = fs.readFileSync(`/proc/${pid}/cgroup`);
98
+ return parse(data.toString());
99
+ } catch (err) {}
100
+ }
101
+
102
+ function ecsMetadataSync(ecsMetadataFile) {
103
+ try {
104
+ return ecsMetadataFile && JSON.parse(fs.readFileSync(ecsMetadataFile));
105
+ } catch (err) {}
106
+ }
107
+
108
+ module.exports = containerInfo;
109
+ containerInfo.sync = containerInfoSync;
110
+ containerInfo.parse = parse;
111
+ containerInfo.resetEcsMetadata = resetEcsMetadata; // Exported for testing-only.