in lib/apm-client/http-apm-client/index.js [96:226]
function Client(opts) {
if (!(this instanceof Client)) return new Client(opts);
Writable.call(this, { objectMode: true });
this._corkTimer = null;
this._agent = null;
this._activeIntakeReq = false;
this._onIntakeReqConcluded = null;
this._transport = null;
this._configTimer = null;
this._backoffReconnectCount = 0;
this._intakeRequestGracefulExitFn = null; // set in makeIntakeRequest
this._encodedMetadata = null;
this._cloudMetadata = null;
this._extraMetadata = null;
this._metadataFilters = new Filters();
// _lambdaActive indicates if a Lambda function invocation is active. It is
// only meaningful if `isLambdaExecutionEnvironment`.
this._lambdaActive = false;
// Whether to forward `.lambdaRegisterTransaction()` calls to the Lambda
// extension. This will be set false if a previous attempt failed.
this._lambdaShouldRegisterTransactions = true;
// Internal runtime stats for developer debugging/tuning.
this._numEvents = 0; // number of events given to the client
this._numEventsDropped = 0; // number of events dropped because overloaded
this._numEventsEnqueued = 0; // number of events written through to chopper
this.sent = 0; // number of events sent to APM server (not necessarily accepted)
this._slowWriteBatch = {
// data on slow or the slowest _writeBatch
numOver10Ms: 0,
// Data for the slowest _writeBatch:
encodeTimeMs: 0,
fullTimeMs: 0,
numEvents: 0,
numBytes: 0,
};
this.config(opts);
this._log = this._conf.logger || new NoopLogger();
// `_apmServerVersion` is one of:
// - `undefined`: the version has not yet been fetched
// - `null`: the APM server version is unknown, could not be determined
// - a semver.SemVer instance
this._apmServerVersion = this._conf.apmServerVersion
? new semver.SemVer(this._conf.apmServerVersion)
: undefined;
if (!this._apmServerVersion) {
this._fetchApmServerVersion();
}
const numExtraMdOpts = [
this._conf.cloudMetadataFetcher,
this._conf.expectExtraMetadata,
this._conf.extraMetadata,
].reduce((accum, curr) => (curr ? accum + 1 : accum), 0);
if (numExtraMdOpts > 1) {
throw new Error(
'it is an error to configure a Client with more than one of "cloudMetadataFetcher", "expectExtraMetadata", or "extraMetadata"',
);
} else if (this._conf.cloudMetadataFetcher) {
// Start stream in corked mode, uncork when cloud metadata is fetched and
// assigned. Also, the _maybeUncork will not uncork until _encodedMetadata
// is set.
this._log.trace('corking (cloudMetadataFetcher)');
this.cork();
this._fetchAndEncodeMetadata(() => {
// _fetchAndEncodeMetadata will have set/memoized the encoded
// metadata to the _encodedMetadata property.
// This reverses the cork() call in the constructor above. "Maybe" uncork,
// in case the client has been destroyed before this callback is called.
this._maybeUncork();
this._log.trace('uncorked (cloudMetadataFetcher)');
// the `cloud-metadata` event allows listeners to know when the
// agent has finished fetching and encoding its metadata for the
// first time
this.emit('cloud-metadata', this._encodedMetadata);
});
} else if (this._conf.expectExtraMetadata) {
// Uncorking will happen in the expected `.setExtraMetadata()` call.
this._log.trace('corking (expectExtraMetadata)');
this.cork();
} else if (this._conf.extraMetadata) {
this.setExtraMetadata(this._conf.extraMetadata);
} else {
this._resetEncodedMetadata();
}
this._chopper = new StreamChopper({
size: this._conf.size,
time: this._conf.time,
type: StreamChopper.overflow,
transform() {
return zlib.createGzip({
level: zlib.constants.Z_BEST_SPEED,
});
},
});
const onIntakeError = (err) => {
if (this.destroyed === false) {
this.emit('request-error', err);
}
};
this._chopper.on('stream', getChoppedStreamHandler(this, onIntakeError));
// We don't expect the chopper stream to end until the client is ending.
// Make sure to clean up if this does happen unexpectedly.
const fail = () => {
if (this._writableState.ending === false) this.destroy();
};
eos(this._chopper, fail);
this._index = clientsToAutoEnd.length;
clientsToAutoEnd.push(this);
// The 'beforeExit' event is significant in Lambda invocation completion
// handling, so we log it for debugging.
if (isLambdaExecutionEnvironment && this._log.isLevelEnabled('trace')) {
process.prependListener('beforeExit', () => {
this._log.trace('process "beforeExit"');
});
}
if (this._conf.centralConfig) {
this._pollConfig();
}
}