elastic-apm-http-client
Advanced tools
Comparing version 9.7.1 to 9.8.0
# elastic-apm-http-client changelog | ||
## v9.8.0 | ||
- Add `client.addMetadataFilter(fn)`. See the | ||
[APM agent issue](https://github.com/elastic/apm-agent-nodejs/issues/1916). | ||
## v9.7.1 | ||
@@ -4,0 +9,0 @@ |
79
index.js
@@ -12,2 +12,4 @@ 'use strict' | ||
const zlib = require('zlib') | ||
const Filters = require('object-filter-sequence') | ||
const querystring = require('querystring') | ||
@@ -75,5 +77,9 @@ const Writable = require('readable-stream').Writable | ||
this._configTimer = null | ||
this._encodedMetadata = null | ||
this._backoffReconnectCount = 0 | ||
this._intakeRequestGracefulExitFn = null // set in makeIntakeRequest | ||
// _encodedMetadata is pre-encoded JSON of metadata from `_conf.metadata` and | ||
// `_cloudMetadata` (asynchronously fetched via `_conf.cloudMetadataFetcher`) | ||
this._encodedMetadata = null | ||
this._cloudMetadata = null | ||
this._metadataFilters = new Filters() | ||
@@ -236,3 +242,3 @@ // Internal runtime stats for developer debugging/tuning. | ||
if (this._encodedMetadata) { | ||
this.updateEncodedMetadata() | ||
this._resetEncodedMetadata() | ||
} | ||
@@ -242,13 +248,36 @@ } | ||
/** | ||
* Updates the encoded metadata without refetching cloud metadata | ||
* Add a filter function used to filter the "metadata" object sent to APM | ||
* server. See the APM Agent `addMetadataFilter` documentation for details. | ||
* https://www.elastic.co/guide/en/apm/agent/nodejs/current/agent-api.html#apm-add-metadata-filter | ||
*/ | ||
Client.prototype.updateEncodedMetadata = function () { | ||
const oldMetadata = JSON.parse(this._encodedMetadata) | ||
const toEncode = { metadata: this._conf.metadata } | ||
if (oldMetadata.metadata.cloud) { | ||
toEncode.metadata.cloud = oldMetadata.metadata.cloud | ||
Client.prototype.addMetadataFilter = function (fn) { | ||
assert.strictEqual(typeof fn, 'function', 'fn arg must be a function') | ||
this._metadataFilters.push(fn) | ||
if (this._encodedMetadata) { | ||
this._resetEncodedMetadata() | ||
} | ||
this._encodedMetadata = this._encode(toEncode, Client.encoding.METADATA) | ||
} | ||
/** | ||
* (Re)set `_encodedMetadata` from this._conf.metadata and this._cloudMetadata. | ||
*/ | ||
Client.prototype._resetEncodedMetadata = function () { | ||
// Make a deep clone so that the originals are not modified when (a) adding | ||
// `.cloud` and (b) filtering. This isn't perf-sensitive code, so this JSON | ||
// cycle for cloning should suffice. | ||
let metadata = JSON.parse(JSON.stringify(this._conf.metadata)) | ||
if (this._cloudMetadata) { | ||
metadata.cloud = JSON.parse(JSON.stringify(this._cloudMetadata)) | ||
} | ||
// Possible filters from APM agent's `apm.addMetadataFilter()`. | ||
if (this._metadataFilters && this._metadataFilters.length > 0) { | ||
metadata = this._metadataFilters.process(metadata) | ||
this._log.trace({ filteredMetadata: metadata }, 'filtered metadata') | ||
} | ||
// This is the only code path that should set `_encodedMetadata`. | ||
this._encodedMetadata = this._encode({ metadata }, Client.encoding.METADATA) | ||
} | ||
Client.prototype._pollConfig = function () { | ||
@@ -915,28 +944,24 @@ const opts = this._conf.requestConfig | ||
/** | ||
* Fetches cloud metadata and encodes with other metadata | ||
* Fetches cloud metadata, if any, and encodes metadata (to `_encodedMetadata`). | ||
* | ||
* This method will encode the fetched cloud-metadata with other metadata | ||
* and memoize the data into the _encodedMetadata property. Data will | ||
* be "returned" to the calling function via the passed in callback. | ||
* | ||
* The cloudMetadataFetcher configuration values is an error first callback | ||
* that fetches the cloud metadata. | ||
* @param {function} cb - Called, with no arguments, when complete. | ||
*/ | ||
Client.prototype._fetchAndEncodeMetadata = function (cb) { | ||
const toEncode = { metadata: this._conf.metadata } | ||
if (!this._conf.cloudMetadataFetcher) { | ||
// no metadata fetcher from the agent -- encode our data and move on | ||
this._encodedMetadata = this._encode(toEncode, Client.encoding.METADATA) | ||
process.nextTick(cb, null, this._encodedMetadata) | ||
this._resetEncodedMetadata() | ||
process.nextTick(cb) | ||
} else { | ||
// agent provided a metadata fetcher function. Call it, use its return | ||
// return-via-callback value to set the cloud metadata and then move on | ||
this._conf.cloudMetadataFetcher.getCloudMetadata((err, cloudMetadata) => { | ||
if (!err && cloudMetadata) { | ||
toEncode.metadata.cloud = cloudMetadata | ||
if (err) { | ||
// We ignore this error (other than logging it). A common case, when | ||
// not running on one of the big 3 clouds, is "all callbacks failed", | ||
// which is *fine*. Because it is a common "error" we don't log the | ||
// stack trace. | ||
this._log.trace('getCloudMetadata err: %s', err) | ||
} else if (cloudMetadata) { | ||
this._cloudMetadata = cloudMetadata | ||
} | ||
this._encodedMetadata = this._encode(toEncode, Client.encoding.METADATA) | ||
cb(err, this._encodedMetadata) | ||
this._resetEncodedMetadata() | ||
cb() | ||
}) | ||
@@ -943,0 +968,0 @@ } |
{ | ||
"name": "elastic-apm-http-client", | ||
"version": "9.7.1", | ||
"version": "9.8.0", | ||
"description": "A low-level HTTP client for communicating with the Elastic APM intake API", | ||
@@ -28,2 +28,3 @@ "main": "index.js", | ||
"fast-stream-to-buffer": "^1.0.0", | ||
"object-filter-sequence": "^1.0.0", | ||
"readable-stream": "^3.4.0", | ||
@@ -30,0 +31,0 @@ "stream-chopper": "^3.0.1", |
@@ -60,3 +60,3 @@ # elastic-apm-http-client | ||
Data sent to the APM Server as part of the metadata package: | ||
Data sent to the APM Server as part of the [metadata object](https://www.elastic.co/guide/en/apm/server/current/metadata-api.html): | ||
@@ -264,2 +264,36 @@ - `agentName` - (required) The APM agent name | ||
### `client.addMetadataFilter(fn)` | ||
Add a filter function for the ["metadata" object](https://www.elastic.co/guide/en/apm/server/current/metadata-api.html) | ||
sent to APM server. This will be called once at client creation, and possibly | ||
again later if `client.config()` is called to reconfigure the client or | ||
`client.addMetadataFilter(fn)` is called to add additional filters. | ||
Here is an example of a filter that removes the `metadata.process.argv` field: | ||
```js | ||
apm.addMetadataFilter(function dropArgv(md) { | ||
if (md.process && md.process.argv) { | ||
delete md.process.argv | ||
} | ||
return md | ||
}) | ||
``` | ||
It is up to the user to ensure the returned object conforms to the | ||
[metadata schema](https://www.elastic.co/guide/en/apm/server/current/metadata-api.html), | ||
otherwise APM data injest will be broken. An example of that (when used with | ||
the Node.js APM agent) is this in the application's log: | ||
``` | ||
[2021-04-14T22:28:35.419Z] ERROR (elastic-apm-node): APM Server transport error (400): Unexpected APM Server response | ||
APM Server accepted 0 events in the last request | ||
Error: validation error: 'metadata' required | ||
Document: {"metadata":null} | ||
``` | ||
See the [APM Agent `addMetadataFilter` documentation](https://www.elastic.co/guide/en/apm/agent/nodejs/current/agent-api.html#apm-add-metadata-filter) | ||
for further details. | ||
### `client.sendSpan(span[, callback])` | ||
@@ -266,0 +300,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
73122
1471
368
9
+ Addedobject-filter-sequence@1.0.0(transitive)