UNPKG

enhanced-adot-node-autoinstrumentation

Version:

This package provides Amazon Web Services distribution of the OpenTelemetry Node Instrumentation, which allows for auto-instrumentation of NodeJS applications.

142 lines 7.62 kB
"use strict"; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports._AwsXRayRemoteSampler = exports.AwsXRayRemoteSampler = void 0; const api_1 = require("@opentelemetry/api"); const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base"); const aws_xray_sampling_client_1 = require("./aws-xray-sampling-client"); const fallback_sampler_1 = require("./fallback-sampler"); const rule_cache_1 = require("./rule-cache"); const sampling_rule_applier_1 = require("./sampling-rule-applier"); // 5 minute default sampling rules polling interval const DEFAULT_RULES_POLLING_INTERVAL_SECONDS = 5 * 60; // Default endpoint for awsproxy : https://aws-otel.github.io/docs/getting-started/remote-sampling#enable-awsproxy-extension const DEFAULT_AWS_PROXY_ENDPOINT = 'http://localhost:2000'; // Wrapper class to ensure that all XRay Sampler Functionality in _AwsXRayRemoteSampler // uses ParentBased logic to respect the parent span's sampling decision class AwsXRayRemoteSampler { constructor(samplerConfig) { this._root = new sdk_trace_base_1.ParentBasedSampler({ root: new _AwsXRayRemoteSampler(samplerConfig) }); } shouldSample(context, traceId, spanName, spanKind, attributes, links) { return this._root.shouldSample(context, traceId, spanName, spanKind, attributes, links); } toString() { return `AwsXRayRemoteSampler{root=${this._root.toString()}`; } } exports.AwsXRayRemoteSampler = AwsXRayRemoteSampler; // _AwsXRayRemoteSampler contains all core XRay Sampler Functionality, // however it is NOT Parent-based (e.g. Sample logic runs for each span) // Not intended for external use, use Parent-based `AwsXRayRemoteSampler` instead. class _AwsXRayRemoteSampler { constructor(samplerConfig) { this.samplerDiag = api_1.diag; if (samplerConfig.pollingInterval == null || samplerConfig.pollingInterval < 10) { this.samplerDiag.warn(`'pollingInterval' is undefined or too small. Defaulting to ${DEFAULT_RULES_POLLING_INTERVAL_SECONDS} seconds`); this.rulePollingIntervalMillis = DEFAULT_RULES_POLLING_INTERVAL_SECONDS * 1000; } else { this.rulePollingIntervalMillis = samplerConfig.pollingInterval * 1000; } this.rulePollingJitterMillis = Math.random() * 5 * 1000; this.targetPollingInterval = this.getDefaultTargetPollingInterval(); this.targetPollingJitterMillis = (Math.random() / 10) * 1000; this.awsProxyEndpoint = samplerConfig.endpoint ? samplerConfig.endpoint : DEFAULT_AWS_PROXY_ENDPOINT; this.fallbackSampler = new fallback_sampler_1.FallbackSampler(); this.clientId = _AwsXRayRemoteSampler.generateClientId(); this.ruleCache = new rule_cache_1.RuleCache(samplerConfig.resource); this.samplingClient = new aws_xray_sampling_client_1.AwsXraySamplingClient(this.awsProxyEndpoint, this.samplerDiag); // Start the Sampling Rules poller this.startSamplingRulesPoller(); // Start the Sampling Targets poller where the first poll occurs after the default interval this.startSamplingTargetsPoller(); } getDefaultTargetPollingInterval() { return rule_cache_1.DEFAULT_TARGET_POLLING_INTERVAL_SECONDS; } shouldSample(context, traceId, spanName, spanKind, attributes, links) { if (this.ruleCache.isExpired()) { this.samplerDiag.debug('Rule cache is expired, so using fallback sampling strategy'); return this.fallbackSampler.shouldSample(context, traceId, spanName, spanKind, attributes, links); } const matchedRule = this.ruleCache.getMatchedRule(attributes); if (matchedRule) { return matchedRule.shouldSample(context, traceId, spanName, spanKind, attributes, links); } this.samplerDiag.debug('Using fallback sampler as no rule match was found. This is likely due to a bug, since default rule should always match'); return this.fallbackSampler.shouldSample(context, traceId, spanName, spanKind, attributes, links); } toString() { return `_AwsXRayRemoteSampler{awsProxyEndpoint=${this.awsProxyEndpoint}, rulePollingIntervalMillis=${this.rulePollingIntervalMillis.toString()}}`; } startSamplingRulesPoller() { // Execute first update this.getAndUpdateSamplingRules(); // Update sampling rules every 5 minutes (or user-defined polling interval) this.rulePoller = setInterval(() => this.getAndUpdateSamplingRules(), this.rulePollingIntervalMillis + this.rulePollingJitterMillis); this.rulePoller.unref(); } startSamplingTargetsPoller() { // Update sampling targets every targetPollingInterval (usually 10 seconds) this.targetPoller = setInterval(() => this.getAndUpdateSamplingTargets(), this.targetPollingInterval * 1000 + this.targetPollingJitterMillis); this.targetPoller.unref(); } getAndUpdateSamplingTargets() { const requestBody = { SamplingStatisticsDocuments: this.ruleCache.createSamplingStatisticsDocuments(this.clientId), }; this.samplingClient.fetchSamplingTargets(requestBody, this.updateSamplingTargets.bind(this)); } getAndUpdateSamplingRules() { this.samplingClient.fetchSamplingRules(this.updateSamplingRules.bind(this)); } updateSamplingRules(responseObject) { let samplingRules = []; samplingRules = []; if (responseObject.SamplingRuleRecords) { responseObject.SamplingRuleRecords.forEach((record) => { if (record.SamplingRule) { samplingRules.push(new sampling_rule_applier_1.SamplingRuleApplier(record.SamplingRule, undefined)); } }); this.ruleCache.updateRules(samplingRules); } else { this.samplerDiag.error('SamplingRuleRecords from GetSamplingRules request is not defined'); } } updateSamplingTargets(responseObject) { try { const targetDocuments = {}; // Create Target-Name-to-Target-Map from sampling targets response responseObject.SamplingTargetDocuments.forEach((newTarget) => { targetDocuments[newTarget.RuleName] = newTarget; }); // Update targets in the cache const [refreshSamplingRules, nextPollingInterval] = this.ruleCache.updateTargets(targetDocuments, responseObject.LastRuleModification); this.targetPollingInterval = nextPollingInterval; clearInterval(this.targetPoller); this.startSamplingTargetsPoller(); if (refreshSamplingRules) { this.samplerDiag.debug('Performing out-of-band sampling rule polling to fetch updated rules.'); clearInterval(this.rulePoller); this.startSamplingRulesPoller(); } } catch (error) { this.samplerDiag.debug('Error occurred when updating Sampling Targets'); } } static generateClientId() { const hexChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; const clientIdArray = []; for (let _ = 0; _ < 24; _ += 1) { clientIdArray.push(hexChars[Math.floor(Math.random() * hexChars.length)]); } return clientIdArray.join(''); } } exports._AwsXRayRemoteSampler = _AwsXRayRemoteSampler; //# sourceMappingURL=aws-xray-remote-sampler.js.map