@vtex/diagnostics-nodejs
Version:
Diagnostics library for Node.js applications
132 lines • 5.38 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigurableSampler = void 0;
const api_1 = require("@opentelemetry/api");
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
const metadata_1 = require("./metadata");
class ConfigurableSampler {
constructor(config) {
this.config = config;
}
shouldSample(context, traceId, spanName, spanKind, attributes, links) {
const metadata = (0, metadata_1.newSamplerMetadata)('configurable');
if (this.config.parentBased !== false) {
const parentContext = api_1.trace.getSpanContext(context);
if (parentContext?.traceFlags && (parentContext.traceFlags & 1)) {
return {
decision: sdk_trace_base_1.SamplingDecision.RECORD_AND_SAMPLED,
attributes: metadata
.setDecision(sdk_trace_base_1.SamplingDecision.RECORD_AND_SAMPLED, 'parent_sampled')
.setRate(1.0)
.toAttributes()
};
}
}
if (this.config.rules) {
for (const rule of this.config.rules) {
if (this.ruleMatches(rule, attributes, spanName)) {
const sampleRate = rule.sampleRate ?? 1.0;
const decision = this.sampleByRate(traceId, sampleRate);
return {
decision,
attributes: metadata
.setDecision(decision, 'rule_match')
.setRule(rule.name || 'unnamed')
.setRate(sampleRate)
.addExtra('conditions_count', rule.conditions?.length || 0)
.toAttributes()
};
}
}
}
const defaultRate = this.config.defaultRate ?? 0.05;
const decision = this.sampleByRate(traceId, defaultRate);
return {
decision,
attributes: metadata
.setDecision(decision, 'default_rate')
.setRate(defaultRate)
.addExtra('rules_evaluated', this.config.rules?.length || 0)
.toAttributes()
};
}
updateConfig(newConfig) {
this.config = newConfig;
}
ruleMatches(rule, attributes, spanName) {
if (!rule.conditions || rule.conditions.length === 0) {
return true;
}
return rule.conditions.every((condition) => this.conditionMatches(condition, attributes, spanName));
}
conditionMatches(condition, attributes, spanName) {
let value;
if (condition.attribute === 'span.name' && spanName) {
value = spanName;
}
else {
value = String(attributes[condition.attribute] || '');
}
switch (condition.operator) {
case 'Equals':
return value === condition.value;
case 'NotEquals':
return value !== condition.value;
case 'Contains':
return value.includes(condition.value || '');
case 'StartsWith':
return value.startsWith(condition.value || '');
case 'EndsWith':
return value.endsWith(condition.value || '');
case 'In':
return (condition.values || []).includes(value);
case 'NotIn':
return !(condition.values || []).includes(value);
case 'Regex':
try {
const regex = new RegExp(condition.value || '');
return regex.test(value);
}
catch {
return false;
}
case 'GreaterThan':
return this.numericCompare(value, condition.value, (a, b) => a > b);
case 'LessThan':
return this.numericCompare(value, condition.value, (a, b) => a < b);
case 'GreaterThanEqual':
return this.numericCompare(value, condition.value, (a, b) => a >= b);
case 'LessThanEqual':
return this.numericCompare(value, condition.value, (a, b) => a <= b);
default:
return false;
}
}
numericCompare(value, target, compareFn) {
const numValue = parseFloat(value);
const numTarget = parseFloat(target || '0');
if (isNaN(numValue) || isNaN(numTarget)) {
return false;
}
return compareFn(numValue, numTarget);
}
sampleByRate(traceId, rate) {
if (rate <= 0.0) {
return sdk_trace_base_1.SamplingDecision.NOT_RECORD;
}
if (rate >= 1.0) {
return sdk_trace_base_1.SamplingDecision.RECORD_AND_SAMPLED;
}
const hashHex = traceId.substring(0, 8);
const hashValue = parseInt(hashHex, 16);
const normalizedValue = hashValue / 0xFFFFFFFF;
return normalizedValue < rate
? sdk_trace_base_1.SamplingDecision.RECORD_AND_SAMPLED
: sdk_trace_base_1.SamplingDecision.NOT_RECORD;
}
toString() {
return `ConfigurableSampler(rules=${this.config.rules?.length || 0})`;
}
}
exports.ConfigurableSampler = ConfigurableSampler;
//# sourceMappingURL=configurable.js.map