dd-trace
Version:
Datadog APM tracing client for JavaScript
1,128 lines (1,052 loc) • 69.7 kB
JavaScript
'use strict'
const fs = require('fs')
const os = require('os')
const uuid = require('crypto-randomuuid') // we need to keep the old uuid dep because of cypress
const { URL } = require('url')
const log = require('./log')
const pkg = require('./pkg')
const coalesce = require('koalas')
const tagger = require('./tagger')
const set = require('../../datadog-core/src/utils/src/set')
const { isTrue, isFalse, normalizeProfilingEnabledValue } = require('./util')
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
const { getGitMetadataFromGitProperties, removeUserSensitiveInfo } = require('./git_properties')
const { updateConfig } = require('./telemetry')
const telemetryMetrics = require('./telemetry/metrics')
const { isInServerlessEnvironment, getIsGCPFunction, getIsAzureFunction } = require('./serverless')
const {
ORIGIN_KEY, GRPC_CLIENT_ERROR_STATUSES, GRPC_SERVER_ERROR_STATUSES
} = require('./constants')
const { appendRules } = require('./payload-tagging/config')
const { getEnvironmentVariable, getEnvironmentVariables } = require('./config-helper')
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
const changeTracker = {}
const telemetryCounters = {
'otel.env.hiding': {},
'otel.env.invalid': {}
}
function getCounter (event, ddVar, otelVar) {
const counters = telemetryCounters[event]
const tags = []
const ddVarPrefix = 'config_datadog:'
const otelVarPrefix = 'config_opentelemetry:'
if (ddVar) {
ddVar = ddVarPrefix + ddVar.toLowerCase()
tags.push(ddVar)
}
if (otelVar) {
otelVar = otelVarPrefix + otelVar.toLowerCase()
tags.push(otelVar)
}
if (!(otelVar in counters)) counters[otelVar] = {}
const counter = tracerMetrics.count(event, tags)
counters[otelVar][ddVar] = counter
return counter
}
const otelDdEnvMapping = {
OTEL_LOG_LEVEL: 'DD_TRACE_LOG_LEVEL',
OTEL_PROPAGATORS: 'DD_TRACE_PROPAGATION_STYLE',
OTEL_SERVICE_NAME: 'DD_SERVICE',
OTEL_TRACES_SAMPLER: 'DD_TRACE_SAMPLE_RATE',
OTEL_TRACES_SAMPLER_ARG: 'DD_TRACE_SAMPLE_RATE',
OTEL_TRACES_EXPORTER: 'DD_TRACE_ENABLED',
OTEL_METRICS_EXPORTER: 'DD_RUNTIME_METRICS_ENABLED',
OTEL_RESOURCE_ATTRIBUTES: 'DD_TAGS',
OTEL_SDK_DISABLED: 'DD_TRACE_OTEL_ENABLED',
OTEL_LOGS_EXPORTER: undefined
}
const VALID_PROPAGATION_STYLES = new Set(['datadog', 'tracecontext', 'b3', 'b3 single header', 'none'])
const VALID_PROPAGATION_BEHAVIOR_EXTRACT = new Set(['continue', 'restart', 'ignore'])
const VALID_LOG_LEVELS = new Set(['debug', 'info', 'warn', 'error'])
function getFromOtelSamplerMap (otelTracesSampler, otelTracesSamplerArg) {
const OTEL_TRACES_SAMPLER_MAPPING = {
always_on: '1.0',
always_off: '0.0',
traceidratio: otelTracesSamplerArg,
parentbased_always_on: '1.0',
parentbased_always_off: '0.0',
parentbased_traceidratio: otelTracesSamplerArg
}
return OTEL_TRACES_SAMPLER_MAPPING[otelTracesSampler]
}
function validateOtelPropagators (propagators) {
if (!getEnvironmentVariable('PROPAGATION_STYLE_EXTRACT') &&
!getEnvironmentVariable('PROPAGATION_STYLE_INJECT') &&
!getEnvironmentVariable('DD_TRACE_PROPAGATION_STYLE') &&
getEnvironmentVariable('OTEL_PROPAGATORS')) {
for (const style in propagators) {
if (!VALID_PROPAGATION_STYLES.has(style)) {
log.warn('unexpected value for OTEL_PROPAGATORS environment variable')
getCounter('otel.env.invalid', 'DD_TRACE_PROPAGATION_STYLE', 'OTEL_PROPAGATORS').inc()
}
}
}
}
function validateEnvVarType (envVar) {
const value = getEnvironmentVariable(envVar)
switch (envVar) {
case 'OTEL_LOG_LEVEL':
return VALID_LOG_LEVELS.has(value)
case 'OTEL_PROPAGATORS':
case 'OTEL_RESOURCE_ATTRIBUTES':
case 'OTEL_SERVICE_NAME':
return typeof value === 'string'
case 'OTEL_TRACES_SAMPLER':
return getFromOtelSamplerMap(value, getEnvironmentVariable('OTEL_TRACES_SAMPLER_ARG')) !== undefined
case 'OTEL_TRACES_SAMPLER_ARG':
return !Number.isNaN(Number.parseFloat(value))
case 'OTEL_SDK_DISABLED':
return value.toLowerCase() === 'true' || value.toLowerCase() === 'false'
case 'OTEL_TRACES_EXPORTER':
case 'OTEL_METRICS_EXPORTER':
case 'OTEL_LOGS_EXPORTER':
return value.toLowerCase() === 'none'
default:
return false
}
}
function checkIfBothOtelAndDdEnvVarSet () {
for (const [otelEnvVar, ddEnvVar] of Object.entries(otelDdEnvMapping)) {
if (ddEnvVar && getEnvironmentVariable(ddEnvVar) && getEnvironmentVariable(otelEnvVar)) {
log.warn('both %s and %s environment variables are set', ddEnvVar, otelEnvVar)
getCounter('otel.env.hiding', ddEnvVar, otelEnvVar).inc()
}
if (getEnvironmentVariable(otelEnvVar) && !validateEnvVarType(otelEnvVar)) {
log.warn('unexpected value for %s environment variable', otelEnvVar)
getCounter('otel.env.invalid', ddEnvVar, otelEnvVar).inc()
}
}
}
// eslint-disable-next-line @stylistic/max-len
const qsRegex = String.raw`(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\s|%20)*(?:=|%3D)[^&]+|(?:"|%22)(?:\s|%20)*(?::|%3A)(?:\s|%20)*(?:"|%22)(?:%2[^2]|%[^2]|[^"%])+(?:"|%22))|bearer(?:\s|%20)+[a-z0-9\._\-]+|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\w=-]|%3D)+\.ey[I-L](?:[\w=-]|%3D)+(?:\.(?:[\w.+\/=-]|%3D|%2F|%2B)+)?|[\-]{5}BEGIN(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY[\-]{5}[^\-]+[\-]{5}END(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY|ssh-rsa(?:\s|%20)*(?:[a-z0-9\/\.+]|%2F|%5C|%2B){100,}`
// eslint-disable-next-line @stylistic/max-len
const defaultWafObfuscatorKeyRegex = String.raw`(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\.net[_-]sessionid|sid|jwt`
// eslint-disable-next-line @stylistic/max-len
const defaultWafObfuscatorValueRegex = String.raw`(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\.net(?:[_-]|-)sessionid|sid|jwt)(?:\s*=([^;&]+)|"\s*:\s*("[^"]+"|\d+))|bearer\s+([a-z0-9\._\-]+)|token\s*:\s*([a-z0-9]{13})|gh[opsu]_([0-9a-zA-Z]{36})|ey[I-L][\w=-]+\.(ey[I-L][\w=-]+(?:\.[\w.+\/=-]+)?)|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY[\-]{5}([^\-]+)[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*([a-z0-9\/\.+]{100,})`
const runtimeId = uuid()
function maybeFile (filepath) {
if (!filepath) return
try {
return fs.readFileSync(filepath, 'utf8')
} catch (e) {
log.error('Error reading file %s', filepath, e)
}
}
function maybeJsonFile (filepath) {
const file = maybeFile(filepath)
if (!file) return
try {
return JSON.parse(file)
} catch (e) {
log.error('Error parsing JSON file %s', filepath, e)
}
}
function safeJsonParse (input) {
try {
return JSON.parse(input)
} catch {}
}
const namingVersions = new Set(['v0', 'v1'])
const defaultNamingVersion = 'v0'
function validateNamingVersion (versionString) {
if (!versionString) {
return defaultNamingVersion
}
if (!namingVersions.has(versionString)) {
log.warn('Unexpected input for config.spanAttributeSchema, picked default', defaultNamingVersion)
return defaultNamingVersion
}
return versionString
}
/**
* Given a string of comma-separated paths, return the array of paths.
* If a blank path is provided a null is returned to signal that the feature is disabled.
* An empty array means the feature is enabled but that no rules need to be applied.
*
* @param {string | string[]} input
*/
function splitJSONPathRules (input) {
if (!input) return
if (Array.isArray(input)) return input
if (input === 'all') return []
return input.split(',')
}
// Shallow clone with property name remapping
function remapify (input, mappings) {
if (!input) return
const output = {}
for (const [key, value] of Object.entries(input)) {
output[key in mappings ? mappings[key] : key] = value
}
return output
}
function propagationStyle (key, option) {
// Extract by key if in object-form value
if (option !== null && typeof option === 'object' && !Array.isArray(option)) {
option = option[key]
}
// Should be an array at this point
if (Array.isArray(option)) return option.map(v => v.toLowerCase())
// If it's not an array but not undefined there's something wrong with the input
if (option !== undefined) {
log.warn('Unexpected input for config.tracePropagationStyle')
}
// Otherwise, fallback to env var parsing
const envKey = `DD_TRACE_PROPAGATION_STYLE_${key.toUpperCase()}`
const envVar = coalesce(getEnvironmentVariable(envKey),
getEnvironmentVariable('DD_TRACE_PROPAGATION_STYLE'), getEnvironmentVariable('OTEL_PROPAGATORS'))
if (envVar !== undefined) {
return envVar.split(',')
.filter(v => v !== '')
.map(v => v.trim().toLowerCase())
}
}
function reformatSpanSamplingRules (rules) {
if (!rules) return rules
return rules.map(rule => {
return remapify(rule, {
sample_rate: 'sampleRate',
max_per_second: 'maxPerSecond'
})
})
}
const sourcesOrder = [
{ containerProperty: '_remote', origin: 'remote_config', unprocessedProperty: '_remoteUnprocessed' },
{ containerProperty: '_options', origin: 'code', unprocessedProperty: '_optsUnprocessed' },
{ containerProperty: '_fleetStableConfig', origin: 'fleet_stable_config' },
{ containerProperty: '_env', origin: 'env_var', unprocessedProperty: '_envUnprocessed' },
{ containerProperty: '_localStableConfig', origin: 'local_stable_config' },
{ containerProperty: '_calculated', origin: 'calculated' },
{ containerProperty: '_defaults', origin: 'default' }
]
class Config {
/**
* parsed DD_TAGS, usable as a standalone tag set across products
* @type {Record<string, string> | undefined}
*/
#parsedDdTags = {}
constructor (options = {}) {
if (!isInServerlessEnvironment()) {
// Bail out early if we're in a serverless environment, stable config isn't supported
const StableConfig = require('./config_stable')
this.stableConfig = new StableConfig()
}
options = {
...options,
appsec: options.appsec == null ? options.experimental?.appsec : options.appsec,
iast: options.iast == null ? options.experimental?.iast : options.iast
}
// Configure the logger first so it can be used to warn about other configs
const logConfig = log.getConfig()
this.debug = log.isEnabled(
this.stableConfig?.fleetEntries?.DD_TRACE_DEBUG,
this.stableConfig?.localEntries?.DD_TRACE_DEBUG
)
this.logger = coalesce(options.logger, logConfig.logger)
this.logLevel = log.getLogLevel(
options.logLevel,
this.stableConfig?.fleetEntries?.DD_TRACE_LOG_LEVEL,
this.stableConfig?.localEntries?.DD_TRACE_LOG_LEVEL
)
log.use(this.logger)
log.toggle(this.debug, this.logLevel)
// Process stable config warnings, if any
for (const warning of this.stableConfig?.warnings ?? []) {
log.warn(warning)
}
checkIfBothOtelAndDdEnvVarSet()
const DD_API_KEY = getEnvironmentVariable('DD_API_KEY')
if (getEnvironmentVariable('DD_TRACE_PROPAGATION_STYLE') && (
getEnvironmentVariable('DD_TRACE_PROPAGATION_STYLE_INJECT') ||
getEnvironmentVariable('DD_TRACE_PROPAGATION_STYLE_EXTRACT')
)) {
log.warn(
// eslint-disable-next-line @stylistic/max-len
'Use either the DD_TRACE_PROPAGATION_STYLE environment variable or separate DD_TRACE_PROPAGATION_STYLE_INJECT and DD_TRACE_PROPAGATION_STYLE_EXTRACT environment variables'
)
}
const PROPAGATION_STYLE_INJECT = propagationStyle(
'inject',
options.tracePropagationStyle
)
validateOtelPropagators(PROPAGATION_STYLE_INJECT)
if (typeof options.appsec === 'boolean') {
options.appsec = {
enabled: options.appsec
}
}
if (typeof options.runtimeMetrics === 'boolean') {
options.runtimeMetrics = {
enabled: options.runtimeMetrics
}
}
const DD_INSTRUMENTATION_INSTALL_ID = coalesce(
getEnvironmentVariable('DD_INSTRUMENTATION_INSTALL_ID'),
null
)
const DD_INSTRUMENTATION_INSTALL_TIME = coalesce(
getEnvironmentVariable('DD_INSTRUMENTATION_INSTALL_TIME'),
null
)
const DD_INSTRUMENTATION_INSTALL_TYPE = coalesce(
getEnvironmentVariable('DD_INSTRUMENTATION_INSTALL_TYPE'),
null
)
const DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING = splitJSONPathRules(
coalesce(
getEnvironmentVariable('DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING'),
options.cloudPayloadTagging?.request,
''
))
const DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING = splitJSONPathRules(
coalesce(
getEnvironmentVariable('DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING'),
options.cloudPayloadTagging?.response,
''
))
const DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH = coalesce(
getEnvironmentVariable('DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH'),
options.cloudPayloadTagging?.maxDepth,
10
)
// TODO: refactor
this.apiKey = DD_API_KEY
// sent in telemetry event app-started
this.installSignature = {
id: DD_INSTRUMENTATION_INSTALL_ID,
time: DD_INSTRUMENTATION_INSTALL_TIME,
type: DD_INSTRUMENTATION_INSTALL_TYPE
}
this.cloudPayloadTagging = {
requestsEnabled: !!DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING,
responsesEnabled: !!DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING,
maxDepth: DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH,
rules: appendRules(
DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING, DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING
)
}
this._applyDefaults()
this._applyLocalStableConfig()
this._applyEnvironment()
this._applyFleetStableConfig()
this._applyOptions(options)
this._applyCalculated()
this._applyRemote({})
this._merge()
tagger.add(this.tags, {
service: this.service,
env: this.env,
version: this.version,
'runtime-id': runtimeId
})
if (this.isCiVisibility) {
tagger.add(this.tags, {
[ORIGIN_KEY]: 'ciapp-test'
})
}
if (this.gitMetadataEnabled) {
this.repositoryUrl = removeUserSensitiveInfo(
coalesce(
getEnvironmentVariable('DD_GIT_REPOSITORY_URL'),
this.tags[GIT_REPOSITORY_URL]
)
)
this.commitSHA = coalesce(
getEnvironmentVariable('DD_GIT_COMMIT_SHA'),
this.tags[GIT_COMMIT_SHA]
)
if (!this.repositoryUrl || !this.commitSHA) {
const DD_GIT_PROPERTIES_FILE = coalesce(
getEnvironmentVariable('DD_GIT_PROPERTIES_FILE'),
`${process.cwd()}/git.properties`
)
let gitPropertiesString
try {
gitPropertiesString = fs.readFileSync(DD_GIT_PROPERTIES_FILE, 'utf8')
} catch (e) {
// Only log error if the user has set a git.properties path
if (getEnvironmentVariable('DD_GIT_PROPERTIES_FILE')) {
log.error('Error reading DD_GIT_PROPERTIES_FILE: %s', DD_GIT_PROPERTIES_FILE, e)
}
}
if (gitPropertiesString) {
const { commitSHA, repositoryUrl } = getGitMetadataFromGitProperties(gitPropertiesString)
this.commitSHA = this.commitSHA || commitSHA
this.repositoryUrl = this.repositoryUrl || repositoryUrl
}
}
}
}
get parsedDdTags () {
return this.#parsedDdTags
}
// Supports only a subset of options for now.
configure (options, remote) {
if (remote) {
this._applyRemote(options)
} else {
this._applyOptions(options)
}
// TODO: test
this._applyCalculated()
this._merge()
}
_getDefaultPropagationStyle (options) {
// TODO: Remove the experimental env vars as a major?
const DD_TRACE_B3_ENABLED = coalesce(
options.experimental && options.experimental.b3,
getEnvironmentVariable('DD_TRACE_EXPERIMENTAL_B3_ENABLED'),
false
)
const defaultPropagationStyle = ['datadog', 'tracecontext']
if (isTrue(DD_TRACE_B3_ENABLED)) {
defaultPropagationStyle.push('b3', 'b3 single header')
}
return defaultPropagationStyle
}
_isInServerlessEnvironment () {
return isInServerlessEnvironment()
}
// for _merge to work, every config value must have a default value
_applyDefaults () {
const {
AWS_LAMBDA_FUNCTION_NAME,
FUNCTION_NAME,
K_SERVICE,
WEBSITE_SITE_NAME
} = getEnvironmentVariables()
const service = AWS_LAMBDA_FUNCTION_NAME ||
FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
K_SERVICE || // Google Cloud Function Name set by newer runtimes
WEBSITE_SITE_NAME || // set by Azure Functions
pkg.name ||
'node'
const defaults = setHiddenProperty(this, '_defaults', {})
defaults.apmTracingEnabled = true
defaults['appsec.apiSecurity.enabled'] = true
defaults['appsec.apiSecurity.sampleDelay'] = 30
defaults['appsec.apiSecurity.endpointCollectionEnabled'] = true
defaults['appsec.apiSecurity.endpointCollectionMessageLimit'] = 300
defaults['appsec.blockedTemplateGraphql'] = undefined
defaults['appsec.blockedTemplateHtml'] = undefined
defaults['appsec.blockedTemplateJson'] = undefined
defaults['appsec.enabled'] = undefined
defaults['appsec.eventTracking.mode'] = 'identification'
defaults['appsec.extendedHeadersCollection.enabled'] = false
defaults['appsec.extendedHeadersCollection.redaction'] = true
defaults['appsec.extendedHeadersCollection.maxHeaders'] = 50
defaults['appsec.obfuscatorKeyRegex'] = defaultWafObfuscatorKeyRegex
defaults['appsec.obfuscatorValueRegex'] = defaultWafObfuscatorValueRegex
defaults['appsec.rasp.enabled'] = true
defaults['appsec.rasp.bodyCollection'] = false
defaults['appsec.rateLimit'] = 100
defaults['appsec.rules'] = undefined
defaults['appsec.sca.enabled'] = null
defaults['appsec.stackTrace.enabled'] = true
defaults['appsec.stackTrace.maxDepth'] = 32
defaults['appsec.stackTrace.maxStackTraces'] = 2
defaults['appsec.wafTimeout'] = 5e3 // µs
defaults.baggageMaxBytes = 8192
defaults.baggageMaxItems = 64
defaults.baggageTagKeys = 'user.id,session.id,account.id'
defaults.ciVisibilityTestSessionName = ''
defaults.clientIpEnabled = false
defaults.clientIpHeader = null
defaults['crashtracking.enabled'] = true
defaults['codeOriginForSpans.enabled'] = true
defaults['codeOriginForSpans.experimental.exit_spans.enabled'] = false
defaults.dbmPropagationMode = 'disabled'
defaults['dogstatsd.hostname'] = '127.0.0.1'
defaults['dogstatsd.port'] = '8125'
defaults.dsmEnabled = false
defaults['dynamicInstrumentation.enabled'] = false
defaults['dynamicInstrumentation.probeFile'] = undefined
defaults['dynamicInstrumentation.redactedIdentifiers'] = []
defaults['dynamicInstrumentation.redactionExcludedIdentifiers'] = []
defaults['dynamicInstrumentation.uploadIntervalSeconds'] = 1
defaults.env = undefined
defaults['experimental.enableGetRumData'] = false
defaults['experimental.exporter'] = undefined
defaults.flushInterval = 2000
defaults.flushMinSpans = 1000
defaults.gitMetadataEnabled = true
defaults.graphqlErrorExtensions = []
defaults['grpc.client.error.statuses'] = GRPC_CLIENT_ERROR_STATUSES
defaults['grpc.server.error.statuses'] = GRPC_SERVER_ERROR_STATUSES
defaults.headerTags = []
defaults['heapSnapshot.count'] = 0
defaults['heapSnapshot.destination'] = ''
defaults['heapSnapshot.interval'] = 3600
defaults.hostname = '127.0.0.1'
defaults['iast.dbRowsToTaint'] = 1
defaults['iast.deduplicationEnabled'] = true
defaults['iast.enabled'] = false
defaults['iast.maxConcurrentRequests'] = 2
defaults['iast.maxContextOperations'] = 2
defaults['iast.redactionEnabled'] = true
defaults['iast.redactionNamePattern'] = null
defaults['iast.redactionValuePattern'] = null
defaults['iast.requestSampling'] = 30
defaults['iast.securityControlsConfiguration'] = null
defaults['iast.telemetryVerbosity'] = 'INFORMATION'
defaults['iast.stackTrace.enabled'] = true
defaults.injectionEnabled = []
defaults.instrumentationSource = 'manual'
defaults.injectForce = null
defaults.isAzureFunction = false
defaults.isCiVisibility = false
defaults.isEarlyFlakeDetectionEnabled = false
defaults.isFlakyTestRetriesEnabled = false
defaults.flakyTestRetriesCount = 5
defaults.isGCPFunction = false
defaults.isGitUploadEnabled = false
defaults.isIntelligentTestRunnerEnabled = false
defaults.isManualApiEnabled = false
defaults['langchain.spanCharLimit'] = 128
defaults['langchain.spanPromptCompletionSampleRate'] = 1
defaults['llmobs.agentlessEnabled'] = undefined
defaults['llmobs.enabled'] = false
defaults['llmobs.mlApp'] = undefined
defaults.ciVisibilityTestSessionName = ''
defaults.ciVisAgentlessLogSubmissionEnabled = false
defaults.legacyBaggageEnabled = true
defaults.isTestDynamicInstrumentationEnabled = false
defaults.isServiceUserProvided = false
defaults.testManagementAttemptToFixRetries = 20
defaults.isTestManagementEnabled = false
defaults.isImpactedTestsEnabled = false
defaults.logInjection = true
defaults.lookup = undefined
defaults.inferredProxyServicesEnabled = false
defaults.memcachedCommandEnabled = false
defaults.middlewareTracingEnabled = true
defaults.openAiLogsEnabled = false
defaults['openai.spanCharLimit'] = 128
defaults.peerServiceMapping = {}
defaults.plugins = true
defaults.port = '8126'
defaults['profiling.enabled'] = undefined
defaults['profiling.exporters'] = 'agent'
defaults['profiling.sourceMap'] = true
defaults['profiling.longLivedThreshold'] = undefined
defaults.protocolVersion = '0.4'
defaults.queryStringObfuscation = qsRegex
defaults['remoteConfig.enabled'] = true
defaults['remoteConfig.pollInterval'] = 5 // seconds
defaults.reportHostname = false
defaults['runtimeMetrics.enabled'] = false
defaults['runtimeMetrics.eventLoop'] = true
defaults['runtimeMetrics.gc'] = true
defaults.runtimeMetricsRuntimeId = false
defaults.sampleRate = undefined
defaults['sampler.rateLimit'] = 100
defaults['sampler.rules'] = []
defaults['sampler.spanSamplingRules'] = []
defaults.scope = undefined
defaults.service = service
defaults.serviceMapping = {}
defaults.site = 'datadoghq.com'
defaults.spanAttributeSchema = 'v0'
defaults.spanComputePeerService = false
defaults.spanLeakDebug = 0
defaults.spanRemoveIntegrationFromService = false
defaults.startupLogs = false
defaults['stats.enabled'] = false
defaults.tags = {}
defaults.tagsHeaderMaxLength = 512
defaults['telemetry.debug'] = false
defaults['telemetry.dependencyCollection'] = true
defaults['telemetry.enabled'] = true
defaults['telemetry.heartbeatInterval'] = 60_000
defaults['telemetry.logCollection'] = true
defaults['telemetry.metrics'] = true
defaults.traceEnabled = true
defaults.traceId128BitGenerationEnabled = true
defaults.traceId128BitLoggingEnabled = true
defaults.tracePropagationExtractFirst = false
defaults.tracePropagationBehaviorExtract = 'continue'
defaults['tracePropagationStyle.inject'] = ['datadog', 'tracecontext', 'baggage']
defaults['tracePropagationStyle.extract'] = ['datadog', 'tracecontext', 'baggage']
defaults['tracePropagationStyle.otelPropagators'] = false
defaults.traceWebsocketMessagesEnabled = true
defaults.traceWebsocketMessagesInheritSampling = true
defaults.traceWebsocketMessagesSeparateTraces = true
defaults.tracing = true
defaults.url = undefined
defaults.version = pkg.version
defaults.instrumentation_config_id = undefined
defaults['vertexai.spanCharLimit'] = 128
defaults['vertexai.spanPromptCompletionSampleRate'] = 1
defaults['trace.aws.addSpanPointers'] = true
defaults['trace.dynamoDb.tablePrimaryKeys'] = undefined
defaults['trace.nativeSpanEvents'] = false
}
_applyLocalStableConfig () {
const obj = setHiddenProperty(this, '_localStableConfig', {})
this._applyStableConfig(this.stableConfig?.localEntries ?? {}, obj)
}
_applyFleetStableConfig () {
const obj = setHiddenProperty(this, '_fleetStableConfig', {})
this._applyStableConfig(this.stableConfig?.fleetEntries ?? {}, obj)
}
_applyStableConfig (config, obj) {
const {
DD_APPSEC_ENABLED,
DD_APPSEC_SCA_ENABLED,
DD_DATA_STREAMS_ENABLED,
DD_DYNAMIC_INSTRUMENTATION_ENABLED,
DD_ENV,
DD_IAST_ENABLED,
DD_LOGS_INJECTION,
DD_PROFILING_ENABLED,
DD_RUNTIME_METRICS_ENABLED,
DD_SERVICE,
DD_VERSION
} = config
this._setBoolean(obj, 'appsec.enabled', DD_APPSEC_ENABLED)
this._setBoolean(obj, 'appsec.sca.enabled', DD_APPSEC_SCA_ENABLED)
this._setBoolean(obj, 'dsmEnabled', DD_DATA_STREAMS_ENABLED)
this._setBoolean(obj, 'dynamicInstrumentation.enabled', DD_DYNAMIC_INSTRUMENTATION_ENABLED)
this._setString(obj, 'env', DD_ENV)
this._setBoolean(obj, 'iast.enabled', DD_IAST_ENABLED)
this._setBoolean(obj, 'logInjection', DD_LOGS_INJECTION)
const profilingEnabled = normalizeProfilingEnabledValue(DD_PROFILING_ENABLED)
this._setString(obj, 'profiling.enabled', profilingEnabled)
this._setBoolean(obj, 'runtimeMetrics.enabled', DD_RUNTIME_METRICS_ENABLED)
this._setString(obj, 'service', DD_SERVICE)
this._setString(obj, 'version', DD_VERSION)
}
_applyEnvironment () {
const {
AWS_LAMBDA_FUNCTION_NAME,
DD_AGENT_HOST,
DD_API_SECURITY_ENABLED,
DD_API_SECURITY_SAMPLE_DELAY,
DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED,
DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT,
DD_APM_TRACING_ENABLED,
DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE,
DD_APPSEC_COLLECT_ALL_HEADERS,
DD_APPSEC_ENABLED,
DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
DD_APPSEC_HEADER_COLLECTION_REDACTION_ENABLED,
DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
DD_APPSEC_MAX_COLLECTED_HEADERS,
DD_APPSEC_MAX_STACK_TRACES,
DD_APPSEC_MAX_STACK_TRACE_DEPTH,
DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
DD_APPSEC_RULES,
DD_APPSEC_SCA_ENABLED,
DD_APPSEC_STACK_TRACE_ENABLED,
DD_APPSEC_RASP_ENABLED,
DD_APPSEC_RASP_COLLECT_REQUEST_BODY,
DD_APPSEC_TRACE_RATE_LIMIT,
DD_APPSEC_WAF_TIMEOUT,
DD_CRASHTRACKING_ENABLED,
DD_CODE_ORIGIN_FOR_SPANS_ENABLED,
DD_CODE_ORIGIN_FOR_SPANS_EXPERIMENTAL_EXIT_SPANS_ENABLED,
DD_DATA_STREAMS_ENABLED,
DD_DBM_PROPAGATION_MODE,
DD_DOGSTATSD_HOST,
DD_DOGSTATSD_PORT,
DD_DYNAMIC_INSTRUMENTATION_ENABLED,
DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE,
DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS,
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS,
DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS,
DD_ENV,
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
DD_PROFILING_ENABLED,
DD_GRPC_CLIENT_ERROR_STATUSES,
DD_GRPC_SERVER_ERROR_STATUSES,
JEST_WORKER_ID,
DD_HEAP_SNAPSHOT_COUNT,
DD_HEAP_SNAPSHOT_DESTINATION,
DD_HEAP_SNAPSHOT_INTERVAL,
DD_IAST_DB_ROWS_TO_TAINT,
DD_IAST_DEDUPLICATION_ENABLED,
DD_IAST_ENABLED,
DD_IAST_MAX_CONCURRENT_REQUESTS,
DD_IAST_MAX_CONTEXT_OPERATIONS,
DD_IAST_REDACTION_ENABLED,
DD_IAST_REDACTION_NAME_PATTERN,
DD_IAST_REDACTION_VALUE_PATTERN,
DD_IAST_REQUEST_SAMPLING,
DD_IAST_SECURITY_CONTROLS_CONFIGURATION,
DD_IAST_TELEMETRY_VERBOSITY,
DD_IAST_STACK_TRACE_ENABLED,
DD_INJECTION_ENABLED,
DD_INJECT_FORCE,
DD_INSTRUMENTATION_TELEMETRY_ENABLED,
DD_INSTRUMENTATION_CONFIG_ID,
DD_LOGS_INJECTION,
DD_LANGCHAIN_SPAN_CHAR_LIMIT,
DD_LANGCHAIN_SPAN_PROMPT_COMPLETION_SAMPLE_RATE,
DD_LLMOBS_AGENTLESS_ENABLED,
DD_LLMOBS_ENABLED,
DD_LLMOBS_ML_APP,
DD_OPENAI_LOGS_ENABLED,
DD_OPENAI_SPAN_CHAR_LIMIT,
DD_PROFILING_EXPORTERS,
DD_PROFILING_SOURCE_MAP,
DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD,
DD_REMOTE_CONFIGURATION_ENABLED,
DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS,
DD_RUNTIME_METRICS_ENABLED,
DD_RUNTIME_METRICS_EVENT_LOOP_ENABLED,
DD_RUNTIME_METRICS_GC_ENABLED,
DD_SERVICE,
DD_SERVICE_MAPPING,
DD_SITE,
DD_SPAN_SAMPLING_RULES,
DD_SPAN_SAMPLING_RULES_FILE,
DD_TAGS,
DD_TELEMETRY_DEBUG,
DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED,
DD_TELEMETRY_HEARTBEAT_INTERVAL,
DD_TELEMETRY_LOG_COLLECTION_ENABLED,
DD_TELEMETRY_METRICS_ENABLED,
DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED,
DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED,
DD_TRACE_AGENT_PORT,
DD_TRACE_AGENT_PROTOCOL_VERSION,
DD_TRACE_AWS_ADD_SPAN_POINTERS,
DD_TRACE_BAGGAGE_MAX_BYTES,
DD_TRACE_BAGGAGE_MAX_ITEMS,
DD_TRACE_BAGGAGE_TAG_KEYS,
DD_TRACE_CLIENT_IP_ENABLED,
DD_TRACE_CLIENT_IP_HEADER,
DD_TRACE_DYNAMODB_TABLE_PRIMARY_KEYS,
DD_TRACE_ENABLED,
DD_TRACE_EXPERIMENTAL_EXPORTER,
DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED,
DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED,
DD_TRACE_GIT_METADATA_ENABLED,
DD_TRACE_GLOBAL_TAGS,
DD_TRACE_GRAPHQL_ERROR_EXTENSIONS,
DD_TRACE_HEADER_TAGS,
DD_TRACE_LEGACY_BAGGAGE_ENABLED,
DD_TRACE_MEMCACHED_COMMAND_ENABLED,
DD_TRACE_MIDDLEWARE_TRACING_ENABLED,
DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
DD_TRACE_PARTIAL_FLUSH_MIN_SPANS,
DD_TRACE_PEER_SERVICE_MAPPING,
DD_TRACE_PROPAGATION_EXTRACT_FIRST,
DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT,
DD_TRACE_PROPAGATION_STYLE,
DD_TRACE_PROPAGATION_STYLE_INJECT,
DD_TRACE_PROPAGATION_STYLE_EXTRACT,
DD_TRACE_RATE_LIMIT,
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED,
DD_TRACE_REPORT_HOSTNAME,
DD_TRACE_SAMPLE_RATE,
DD_TRACE_SAMPLING_RULES,
DD_TRACE_SCOPE,
DD_TRACE_SPAN_ATTRIBUTE_SCHEMA,
DD_TRACE_SPAN_LEAK_DEBUG,
DD_TRACE_STARTUP_LOGS,
DD_TRACE_TAGS,
DD_TRACE_WEBSOCKET_MESSAGES_ENABLED,
DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING,
DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACES,
DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
DD_TRACING_ENABLED,
DD_VERSION,
DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE,
DD_VERTEXAI_SPAN_CHAR_LIMIT,
DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED,
DD_TRACE_NATIVE_SPAN_EVENTS,
OTEL_METRICS_EXPORTER,
OTEL_PROPAGATORS,
OTEL_RESOURCE_ATTRIBUTES,
OTEL_SERVICE_NAME,
OTEL_TRACES_SAMPLER,
OTEL_TRACES_SAMPLER_ARG
} = getEnvironmentVariables()
const tags = {}
const env = setHiddenProperty(this, '_env', {})
setHiddenProperty(this, '_envUnprocessed', {})
tagger.add(this.#parsedDdTags, parseSpaceSeparatedTags(DD_TAGS))
tagger.add(tags, parseSpaceSeparatedTags(handleOtel(OTEL_RESOURCE_ATTRIBUTES)))
tagger.add(tags, this.#parsedDdTags)
tagger.add(tags, DD_TRACE_TAGS)
tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
this._setBoolean(env, 'apmTracingEnabled', coalesce(
DD_APM_TRACING_ENABLED,
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED && isFalse(DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED)
))
this._setBoolean(env, 'appsec.apiSecurity.enabled', DD_API_SECURITY_ENABLED && isTrue(DD_API_SECURITY_ENABLED))
env['appsec.apiSecurity.sampleDelay'] = maybeFloat(DD_API_SECURITY_SAMPLE_DELAY)
this._setBoolean(env, 'appsec.apiSecurity.endpointCollectionEnabled',
DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED)
env['appsec.apiSecurity.endpointCollectionMessageLimit'] =
maybeInt(DD_API_SECURITY_ENDPOINT_COLLECTION_MESSAGE_LIMIT)
env['appsec.blockedTemplateGraphql'] = maybeFile(DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON)
env['appsec.blockedTemplateHtml'] = maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML)
this._envUnprocessed['appsec.blockedTemplateHtml'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML
env['appsec.blockedTemplateJson'] = maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
this._envUnprocessed['appsec.blockedTemplateJson'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON
this._setBoolean(env, 'appsec.enabled', DD_APPSEC_ENABLED)
this._setString(env, 'appsec.eventTracking.mode', DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE)
this._setBoolean(env, 'appsec.extendedHeadersCollection.enabled', DD_APPSEC_COLLECT_ALL_HEADERS)
this._setBoolean(
env,
'appsec.extendedHeadersCollection.redaction',
DD_APPSEC_HEADER_COLLECTION_REDACTION_ENABLED
)
env['appsec.extendedHeadersCollection.maxHeaders'] = maybeInt(DD_APPSEC_MAX_COLLECTED_HEADERS)
this._envUnprocessed['appsec.extendedHeadersCollection.maxHeaders'] = DD_APPSEC_MAX_COLLECTED_HEADERS
this._setString(env, 'appsec.obfuscatorKeyRegex', DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP)
this._setString(env, 'appsec.obfuscatorValueRegex', DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP)
this._setBoolean(env, 'appsec.rasp.enabled', DD_APPSEC_RASP_ENABLED)
this._setBoolean(env, 'appsec.rasp.bodyCollection', DD_APPSEC_RASP_COLLECT_REQUEST_BODY)
env['appsec.rateLimit'] = maybeInt(DD_APPSEC_TRACE_RATE_LIMIT)
this._envUnprocessed['appsec.rateLimit'] = DD_APPSEC_TRACE_RATE_LIMIT
this._setString(env, 'appsec.rules', DD_APPSEC_RULES)
// DD_APPSEC_SCA_ENABLED is never used locally, but only sent to the backend
this._setBoolean(env, 'appsec.sca.enabled', DD_APPSEC_SCA_ENABLED)
this._setBoolean(env, 'appsec.stackTrace.enabled', DD_APPSEC_STACK_TRACE_ENABLED)
env['appsec.stackTrace.maxDepth'] = maybeInt(DD_APPSEC_MAX_STACK_TRACE_DEPTH)
this._envUnprocessed['appsec.stackTrace.maxDepth'] = DD_APPSEC_MAX_STACK_TRACE_DEPTH
env['appsec.stackTrace.maxStackTraces'] = maybeInt(DD_APPSEC_MAX_STACK_TRACES)
this._envUnprocessed['appsec.stackTrace.maxStackTraces'] = DD_APPSEC_MAX_STACK_TRACES
env['appsec.wafTimeout'] = maybeInt(DD_APPSEC_WAF_TIMEOUT)
this._envUnprocessed['appsec.wafTimeout'] = DD_APPSEC_WAF_TIMEOUT
env.baggageMaxBytes = DD_TRACE_BAGGAGE_MAX_BYTES
env.baggageMaxItems = DD_TRACE_BAGGAGE_MAX_ITEMS
env.baggageTagKeys = DD_TRACE_BAGGAGE_TAG_KEYS
this._setBoolean(env, 'clientIpEnabled', DD_TRACE_CLIENT_IP_ENABLED)
this._setString(env, 'clientIpHeader', DD_TRACE_CLIENT_IP_HEADER?.toLowerCase())
this._setBoolean(env, 'crashtracking.enabled', coalesce(
DD_CRASHTRACKING_ENABLED,
!this._isInServerlessEnvironment()
))
this._setBoolean(env, 'codeOriginForSpans.enabled', DD_CODE_ORIGIN_FOR_SPANS_ENABLED)
this._setBoolean(
env,
'codeOriginForSpans.experimental.exit_spans.enabled',
DD_CODE_ORIGIN_FOR_SPANS_EXPERIMENTAL_EXIT_SPANS_ENABLED
)
this._setString(env, 'dbmPropagationMode', DD_DBM_PROPAGATION_MODE)
this._setString(env, 'dogstatsd.hostname', DD_DOGSTATSD_HOST)
this._setString(env, 'dogstatsd.port', DD_DOGSTATSD_PORT)
this._setBoolean(env, 'dsmEnabled', DD_DATA_STREAMS_ENABLED)
this._setBoolean(env, 'dynamicInstrumentation.enabled', DD_DYNAMIC_INSTRUMENTATION_ENABLED)
this._setString(env, 'dynamicInstrumentation.probeFile', DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE)
this._setArray(env, 'dynamicInstrumentation.redactedIdentifiers', DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS)
this._setArray(
env,
'dynamicInstrumentation.redactionExcludedIdentifiers',
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS
)
env['dynamicInstrumentation.uploadIntervalSeconds'] = maybeFloat(DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS)
this._envUnprocessed['dynamicInstrumentation.uploadInterval'] = DD_DYNAMIC_INSTRUMENTATION_UPLOAD_INTERVAL_SECONDS
this._setString(env, 'env', DD_ENV || tags.env)
this._setBoolean(env, 'traceEnabled', DD_TRACE_ENABLED)
this._setBoolean(env, 'experimental.enableGetRumData', DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED)
this._setString(env, 'experimental.exporter', DD_TRACE_EXPERIMENTAL_EXPORTER)
if (AWS_LAMBDA_FUNCTION_NAME) env.flushInterval = 0
env.flushMinSpans = maybeInt(DD_TRACE_PARTIAL_FLUSH_MIN_SPANS)
this._envUnprocessed.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
this._setBoolean(env, 'gitMetadataEnabled', DD_TRACE_GIT_METADATA_ENABLED)
this._setIntegerRangeSet(env, 'grpc.client.error.statuses', DD_GRPC_CLIENT_ERROR_STATUSES)
this._setIntegerRangeSet(env, 'grpc.server.error.statuses', DD_GRPC_SERVER_ERROR_STATUSES)
this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
env['heapSnapshot.count'] = maybeInt(DD_HEAP_SNAPSHOT_COUNT)
this._setString(env, 'heapSnapshot.destination', DD_HEAP_SNAPSHOT_DESTINATION)
env['heapSnapshot.interval'] = maybeInt(DD_HEAP_SNAPSHOT_INTERVAL)
this._setString(env, 'hostname', DD_AGENT_HOST)
env['iast.dbRowsToTaint'] = maybeInt(DD_IAST_DB_ROWS_TO_TAINT)
this._setBoolean(env, 'iast.deduplicationEnabled', DD_IAST_DEDUPLICATION_ENABLED)
this._setBoolean(env, 'iast.enabled', DD_IAST_ENABLED)
env['iast.maxConcurrentRequests'] = maybeInt(DD_IAST_MAX_CONCURRENT_REQUESTS)
this._envUnprocessed['iast.maxConcurrentRequests'] = DD_IAST_MAX_CONCURRENT_REQUESTS
env['iast.maxContextOperations'] = maybeInt(DD_IAST_MAX_CONTEXT_OPERATIONS)
this._envUnprocessed['iast.maxContextOperations'] = DD_IAST_MAX_CONTEXT_OPERATIONS
this._setBoolean(env, 'iast.redactionEnabled', DD_IAST_REDACTION_ENABLED && !isFalse(DD_IAST_REDACTION_ENABLED))
this._setString(env, 'iast.redactionNamePattern', DD_IAST_REDACTION_NAME_PATTERN)
this._setString(env, 'iast.redactionValuePattern', DD_IAST_REDACTION_VALUE_PATTERN)
const iastRequestSampling = maybeInt(DD_IAST_REQUEST_SAMPLING)
if (iastRequestSampling > -1 && iastRequestSampling < 101) {
env['iast.requestSampling'] = iastRequestSampling
}
this._envUnprocessed['iast.requestSampling'] = DD_IAST_REQUEST_SAMPLING
this._setString(env, 'iast.securityControlsConfiguration', DD_IAST_SECURITY_CONTROLS_CONFIGURATION)
this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
this._setBoolean(env, 'iast.stackTrace.enabled', DD_IAST_STACK_TRACE_ENABLED)
this._setArray(env, 'injectionEnabled', DD_INJECTION_ENABLED)
this._setString(env, 'instrumentationSource', DD_INJECTION_ENABLED ? 'ssi' : 'manual')
this._setBoolean(env, 'injectForce', DD_INJECT_FORCE)
this._setBoolean(env, 'isAzureFunction', getIsAzureFunction())
this._setBoolean(env, 'isGCPFunction', getIsGCPFunction())
env['langchain.spanCharLimit'] = maybeInt(DD_LANGCHAIN_SPAN_CHAR_LIMIT)
env['langchain.spanPromptCompletionSampleRate'] = maybeFloat(DD_LANGCHAIN_SPAN_PROMPT_COMPLETION_SAMPLE_RATE)
this._setBoolean(env, 'legacyBaggageEnabled', DD_TRACE_LEGACY_BAGGAGE_ENABLED)
this._setBoolean(env, 'llmobs.agentlessEnabled', DD_LLMOBS_AGENTLESS_ENABLED)
this._setBoolean(env, 'llmobs.enabled', DD_LLMOBS_ENABLED)
this._setString(env, 'llmobs.mlApp', DD_LLMOBS_ML_APP)
this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
// Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
this._setBoolean(env, 'memcachedCommandEnabled', DD_TRACE_MEMCACHED_COMMAND_ENABLED)
this._setBoolean(env, 'middlewareTracingEnabled', DD_TRACE_MIDDLEWARE_TRACING_ENABLED)
this._setBoolean(env, 'openAiLogsEnabled', DD_OPENAI_LOGS_ENABLED)
env['openai.spanCharLimit'] = maybeInt(DD_OPENAI_SPAN_CHAR_LIMIT)
this._envUnprocessed.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
if (DD_TRACE_PEER_SERVICE_MAPPING) {
env.peerServiceMapping = Object.fromEntries(
DD_TRACE_PEER_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
)
this._envUnprocessed.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
}
this._setString(env, 'port', DD_TRACE_AGENT_PORT)
const profilingEnabled = normalizeProfilingEnabledValue(
coalesce(
DD_PROFILING_ENABLED,
this._isInServerlessEnvironment() ? 'false' : undefined
)
)
this._setString(env, 'profiling.enabled', profilingEnabled)
this._setString(env, 'profiling.exporters', DD_PROFILING_EXPORTERS)
this._setBoolean(env, 'profiling.sourceMap', DD_PROFILING_SOURCE_MAP && !isFalse(DD_PROFILING_SOURCE_MAP))
if (DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD) {
// This is only used in testing to not have to wait 30s
env['profiling.longLivedThreshold'] = Number(DD_INTERNAL_PROFILING_LONG_LIVED_THRESHOLD)
}
this._setString(env, 'protocolVersion', DD_TRACE_AGENT_PROTOCOL_VERSION)
this._setString(env, 'queryStringObfuscation', DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP)
this._setBoolean(env, 'remoteConfig.enabled', coalesce(
DD_REMOTE_CONFIGURATION_ENABLED,
!this._isInServerlessEnvironment()
))
env['remoteConfig.pollInterval'] = maybeFloat(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS)
this._envUnprocessed['remoteConfig.pollInterval'] = DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS
this._setBoolean(env, 'reportHostname', DD_TRACE_REPORT_HOSTNAME)
// only used to explicitly set runtimeMetrics to false
const otelSetRuntimeMetrics = String(OTEL_METRICS_EXPORTER).toLowerCase() === 'none'
? false
: undefined
this._setBoolean(env, 'runtimeMetrics.enabled', DD_RUNTIME_METRICS_ENABLED ||
otelSetRuntimeMetrics)
this._setBoolean(env, 'runtimeMetrics.eventLoop', DD_RUNTIME_METRICS_EVENT_LOOP_ENABLED)
this._setBoolean(env, 'runtimeMetrics.gc', DD_RUNTIME_METRICS_GC_ENABLED)
this._setBoolean(env, 'runtimeMetricsRuntimeId', DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED)
this._setArray(env, 'sampler.spanSamplingRules', reformatSpanSamplingRules(coalesce(
maybeJsonFile(DD_SPAN_SAMPLING_RULES_FILE),
safeJsonParse(DD_SPAN_SAMPLING_RULES)
)))
this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE ||
getFromOtelSamplerMap(OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG))
env['sampler.rateLimit'] = DD_TRACE_RATE_LIMIT
this._setSamplingRule(env, 'sampler.rules', safeJsonParse(DD_TRACE_SAMPLING_RULES))
this._envUnprocessed['sampler.rules'] = DD_TRACE_SAMPLING_RULES
this._setString(env, 'scope', DD_TRACE_SCOPE)
this._setString(env, 'service', DD_SERVICE || tags.service || OTEL_SERVICE_NAME)
if (DD_SERVICE_MAPPING) {
env.serviceMapping = Object.fromEntries(
DD_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
)
}
this._setString(env, 'site', DD_SITE)
if (DD_TRACE_SPAN_ATTRIBUTE_SCHEMA) {
this._setString(env, 'spanAttributeSchema', validateNamingVersion(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA))
this._envUnprocessed.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
}
// 0: disabled, 1: logging, 2: garbage collection + logging
env.spanLeakDebug = maybeInt(DD_TRACE_SPAN_LEAK_DEBUG)
this._setBoolean(env, 'spanRemoveIntegrationFromService', DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED)
this._setBoolean(env, 'startupLogs', DD_TRACE_STARTUP_LOGS)
this._setTags(env, 'tags', tags)
env.tagsHeaderMaxLength = DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH
this._setBoolean(env, 'telemetry.enabled', coalesce(
DD_INSTRUMENTATION_TELEMETRY_ENABLED,
!(this._isInServerlessEnvironment() || JEST_WORKER_ID)
))
this._setString(env, 'instrumentation_config_id', DD_INSTRUMENTATION_CONFIG_ID)
this._setBoolean(env, 'telemetry.debug', DD_TELEMETRY_DEBUG)
this._setBoolean(env, 'telemetry.dependencyCollection', DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED)
env['telemetry.heartbeatInterval'] = maybeInt(Math.floor(DD_TELEMETRY_HEARTBEAT_INTERVAL * 1000))
this._envUnprocessed['telemetry.heartbeatInterval'] = DD_TELEMETRY_HEARTBEAT_INTERVAL * 1000
this._setBoolean(env, 'telemetry.logCollection', DD_TELEMETRY_LOG_COLLECTION_ENABLED)
this._setBoolean(env, 'telemetry.metrics', DD_TELEMETRY_METRICS_ENABLED)
this._setBoolean(env, 'traceId128BitGenerationEnabled', DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
this._setBoolean(env, 'traceId128BitLoggingEnabled', DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
this._setBoolean(env, 'tracePropagationExtractFirst', DD_TRACE_PROPAGATION_EXTRACT_FIRST)
const stringPropagationBehaviorExtract = String(DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT)
env.tracePropagationBehaviorExtract =
VALID_PROPAGATION_BEHAVIOR_EXTRACT.has(stringPropagationBehaviorExtract)
? stringPropagationBehaviorExtract
: 'continue'
this._setBoolean(env, 'tracePropagationStyle.otelPropagators',
DD_TRACE_PROPAGATION_STYLE ||
DD_TRACE_PROPAGATION_STYLE_INJECT ||
DD_TRACE_PROPAGATION_STYLE_EXTRACT
? false
: !!OTEL_PROPAGATORS)
this._setBoolean(env, 'traceWebsocketMessagesEnabled', DD_TRACE_WEBSOCKET_MESSAGES_ENABLED)
this._setBoolean(env, 'traceWebsocketMessagesInheritSampling', DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING)
this._setBoolean(env, 'traceWebsocketMessagesSeparateTraces', DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACES)
this._setBoolean(env, 'tracing', DD_TRACING_ENABLED)
this._setString(env, 'version', DD_VERSION || tags.version)
this._setBoolean(env, 'inferredProxyServicesEnabled', DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED)
this._setBoolean(env, 'trace.aws.addSpanPointers', DD_TRACE_AWS_ADD_SPAN_POINTERS)
this._setString(env, 'trace.dynamoDb.tablePrimaryKeys', DD_TRACE_DYNAMODB_TABLE_PRIMARY_KEYS)
this._setArray(env, 'graphqlErrorExtensions', DD_TRACE_GRAPHQL_ERROR_EXTENSIONS)
this._setBoolean(env, 'trace.nativeSpanEvents', DD_TRACE_NATIVE_SPAN_EVENTS)
env['vertexai.spanPromptCompletionSampleRate'] = maybeFloat(DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE)
env['vertexai.spanCharLimit'] = maybeInt(DD_VERTEXAI_SPAN_CHAR_LIMIT)
}
_applyOptions (options) {
const opts = setHiddenProperty(this, '_options', this._options || {})
const tags = {}
setHiddenProperty(this, '_optsUnprocessed', {})
options = setHiddenProperty(this, '_optionsArg', { ingestion: {}, ...options, ...opts })
tagger.add(tags, options.tags)
this._setBoolean(opts, 'apmTracingEnabled', coalesce(
options.apmTracingEnabled,
options.experimental?.appsec?.standalone && !options.experimental.appsec.standalone.enabled
))
this._setBoolean(opts, 'appsec.apiSecurity.enabled', options.appsec?.apiSecurity?.enabled)
this._setBoolean(opts, 'appsec.apiSecurity.endpointCollectionEnabled',
options.appsec?.apiSecurity?.endpointCollectionEnabled)
opts['appsec.apiSecurity.endpointCollectionMessageLimit'] =
maybeInt(options.appsec?.apiSecurity?.endpointCollectionMessageLimit)
opts['appsec.blockedTemplateGraphql'] = maybeFile(options.appsec?.blockedTemplateGraphql)
opts['appsec.blockedTemplateHtml'] = maybeFile(options.appsec?.blockedTemplateHtml)
this._optsUnprocessed['appsec.blockedTemplateHtml'] = options.appsec?.blockedTemplateHtml
opts['appsec.blockedTemplateJson'] = maybeFile(options.appsec?.blockedTemplateJson)
this._optsUnprocessed['appsec.blockedTemplateJson'] = options.appsec?.blockedTemplateJson
this._setBoolean(opts, 'appsec.enabled', options.appsec?.enabled)
this._setString(opts, 'appsec.eventTracking.mode', options.appsec?.eventTracking?.mode)
this._setBoolean(
opts,
'appsec.extendedHeadersCollection.enabled',
options.appsec?.extendedHeadersCollection?.enabled
)
this._setBoolean(
opts,
'appsec.extendedHeadersCollection.redaction',
options.appsec?.extendedHeadersCollection?.redaction
)
opts['appsec.extendedHeadersCollection.maxHeaders'] = options.appsec?.extendedHeadersCollection?.maxHeaders
this._setString(opts, 'appsec.obfuscatorKeyRegex', options.appsec?.obfuscatorKeyRegex)
this._setString(opts, 'appsec.obfuscatorValueRegex', options.appsec?.obfuscatorValueRegex)
this._setBoolean(opts, 'appsec.rasp.enabled', options.appsec?.rasp?.enabled)
this._setBoolean(opts, 'appsec.rasp.bodyCollection', options.appsec?.rasp?.bodyCollection)
opts['appsec.rateLimit'] = maybeInt(options.appsec?.rateLimit)
this._optsUnprocessed['appsec.rateLimit'] = options.appsec?.rateLimit
this._setString(opts, 'appsec.rules', options.appsec?.rules)
this._setBoolean(opts, 'appsec.stackTrace.enabled', options.appsec?.stackTrace?.enabled)
opts['appsec.stackTrace.maxDepth'] = maybeInt(options.appsec?.stackTrace?.maxDepth)
this._optsUnprocessed['appsec.stackTrace.maxDepth'] = options.appsec?.stackTrace?.maxDepth
opts['appsec.stackTrace.maxStackTraces'] = maybeInt(options.appsec?.stackTrace?.maxStackTraces)
this._optsUnprocessed['appsec.stackTrace.maxStackTraces'] = options.appsec?.stackTrace?.maxStackTraces
opts['appsec.wafTimeout'] = maybeInt(options.appsec?.wafTimeout)
this._optsUnprocessed['appsec.wafTimeout'] = options.appsec?.wafTimeout
this._setBoolean(opts, 'clientIpEnabled', options.clientIpEnabled)
this._setString(opts, 'clientIpHeader', options.clientIpHeader?.toLowerCase())
opts.baggageMaxBytes = options.baggageMaxBytes
opts.baggageMaxItems = options.baggageMaxItems
opts.baggageTagKeys = options.baggageTagKeys
t