dd-trace
Version:
Datadog APM tracing client for JavaScript
1,077 lines (1,007 loc) • 66.8 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 get = require('../../datadog-core/src/utils/src/get')
const has = require('../../datadog-core/src/utils/src/has')
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 tracerMetrics = telemetryMetrics.manager.namespace('tracers')
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 (!process.env.PROPAGATION_STYLE_EXTRACT &&
!process.env.PROPAGATION_STYLE_INJECT &&
!process.env.DD_TRACE_PROPAGATION_STYLE &&
process.env.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 = process.env[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, process.env.OTEL_TRACES_SAMPLER_ARG) !== undefined
case 'OTEL_TRACES_SAMPLER_ARG':
return !isNaN(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 && process.env[ddEnvVar] && process.env[otelEnvVar]) {
log.warn(`both ${ddEnvVar} and ${otelEnvVar} environment variables are set`)
getCounter('otel.env.hiding', ddEnvVar, otelEnvVar).inc()
}
if (process.env[otelEnvVar] && !validateEnvVarType(otelEnvVar)) {
log.warn(`unexpected value for ${otelEnvVar} environment variable`)
getCounter('otel.env.invalid', ddEnvVar, otelEnvVar).inc()
}
}
}
const fromEntries = Object.fromEntries || (entries =>
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
// eslint-disable-next-line @stylistic/js/max-len
const qsRegex = '(?: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/js/max-len
const defaultWafObfuscatorKeyRegex = '(?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/js/max-len
const defaultWafObfuscatorValueRegex = '(?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*"[^"]+")|bearer\\s+[a-z0-9\\._\\-]+|token:[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)
return undefined
}
}
function safeJsonParse (input) {
try {
return JSON.parse(input)
} catch (err) {
return undefined
}
}
const namingVersions = ['v0', 'v1']
const defaultNamingVersion = 'v0'
function validateNamingVersion (versionString) {
if (!versionString) {
return defaultNamingVersion
}
if (!namingVersions.includes(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} input
* @returns {[string]|null}
*/
function splitJSONPathRules (input) {
if (!input) return null
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(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE, process.env.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'
})
})
}
class Config {
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.appsec : options.experimental?.appsec,
iast: options.iast != null ? options.iast : options.experimental?.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 = coalesce(
process.env.DATADOG_API_KEY,
process.env.DD_API_KEY
)
if (process.env.DD_TRACE_PROPAGATION_STYLE && (
process.env.DD_TRACE_PROPAGATION_STYLE_INJECT ||
process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT
)) {
log.warn(
'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,
this._getDefaultPropagationStyle(options)
)
validateOtelPropagators(PROPAGATION_STYLE_INJECT)
if (typeof options.appsec === 'boolean') {
options.appsec = {
enabled: options.appsec
}
} else if (options.appsec == null) {
options.appsec = {}
}
const DD_INSTRUMENTATION_INSTALL_ID = coalesce(
process.env.DD_INSTRUMENTATION_INSTALL_ID,
null
)
const DD_INSTRUMENTATION_INSTALL_TIME = coalesce(
process.env.DD_INSTRUMENTATION_INSTALL_TIME,
null
)
const DD_INSTRUMENTATION_INSTALL_TYPE = coalesce(
process.env.DD_INSTRUMENTATION_INSTALL_TYPE,
null
)
const DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING = splitJSONPathRules(
coalesce(
process.env.DD_TRACE_CLOUD_REQUEST_PAYLOAD_TAGGING,
options.cloudPayloadTagging?.request,
''
))
const DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING = splitJSONPathRules(
coalesce(
process.env.DD_TRACE_CLOUD_RESPONSE_PAYLOAD_TAGGING,
options.cloudPayloadTagging?.response,
''
))
const DD_TRACE_CLOUD_PAYLOAD_TAGGING_MAX_DEPTH = coalesce(
process.env.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(
process.env.DD_GIT_REPOSITORY_URL,
this.tags[GIT_REPOSITORY_URL]
)
)
this.commitSHA = coalesce(
process.env.DD_GIT_COMMIT_SHA,
this.tags[GIT_COMMIT_SHA]
)
if (!this.repositoryUrl || !this.commitSHA) {
const DD_GIT_PROPERTIES_FILE = coalesce(
process.env.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 (process.env.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
}
}
}
}
// 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,
process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
false
)
const defaultPropagationStyle = ['datadog', 'tracecontext']
if (isTrue(DD_TRACE_B3_ENABLED)) {
defaultPropagationStyle.push('b3')
defaultPropagationStyle.push('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
} = process.env
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', {})
this._setBoolean(defaults, 'apmTracingEnabled', true)
this._setValue(defaults, 'appsec.apiSecurity.enabled', true)
this._setValue(defaults, 'appsec.apiSecurity.sampleDelay', 30)
this._setValue(defaults, 'appsec.blockedTemplateGraphql', undefined)
this._setValue(defaults, 'appsec.blockedTemplateHtml', undefined)
this._setValue(defaults, 'appsec.blockedTemplateJson', undefined)
this._setValue(defaults, 'appsec.enabled', undefined)
this._setValue(defaults, 'appsec.eventTracking.mode', 'identification')
this._setValue(defaults, 'appsec.obfuscatorKeyRegex', defaultWafObfuscatorKeyRegex)
this._setValue(defaults, 'appsec.obfuscatorValueRegex', defaultWafObfuscatorValueRegex)
this._setValue(defaults, 'appsec.rasp.enabled', true)
this._setValue(defaults, 'appsec.rateLimit', 100)
this._setValue(defaults, 'appsec.rules', undefined)
this._setValue(defaults, 'appsec.sca.enabled', null)
this._setValue(defaults, 'appsec.stackTrace.enabled', true)
this._setValue(defaults, 'appsec.stackTrace.maxDepth', 32)
this._setValue(defaults, 'appsec.stackTrace.maxStackTraces', 2)
this._setValue(defaults, 'appsec.wafTimeout', 5e3) // µs
this._setValue(defaults, 'baggageMaxBytes', 8192)
this._setValue(defaults, 'baggageMaxItems', 64)
this._setValue(defaults, 'ciVisibilityTestSessionName', '')
this._setValue(defaults, 'clientIpEnabled', false)
this._setValue(defaults, 'clientIpHeader', null)
this._setValue(defaults, 'crashtracking.enabled', true)
this._setValue(defaults, 'codeOriginForSpans.enabled', false)
this._setValue(defaults, 'dbmPropagationMode', 'disabled')
this._setValue(defaults, 'dogstatsd.hostname', '127.0.0.1')
this._setValue(defaults, 'dogstatsd.port', '8125')
this._setValue(defaults, 'dsmEnabled', false)
this._setValue(defaults, 'dynamicInstrumentation.enabled', false)
this._setValue(defaults, 'dynamicInstrumentation.redactedIdentifiers', [])
this._setValue(defaults, 'dynamicInstrumentation.redactionExcludedIdentifiers', [])
this._setValue(defaults, 'env', undefined)
this._setValue(defaults, 'experimental.enableGetRumData', false)
this._setValue(defaults, 'experimental.exporter', undefined)
this._setValue(defaults, 'experimental.runtimeId', false)
this._setValue(defaults, 'flushInterval', 2000)
this._setValue(defaults, 'flushMinSpans', 1000)
this._setValue(defaults, 'gitMetadataEnabled', true)
this._setValue(defaults, 'graphqlErrorExtensions', [])
this._setValue(defaults, 'grpc.client.error.statuses', GRPC_CLIENT_ERROR_STATUSES)
this._setValue(defaults, 'grpc.server.error.statuses', GRPC_SERVER_ERROR_STATUSES)
this._setValue(defaults, 'headerTags', [])
this._setValue(defaults, 'hostname', '127.0.0.1')
this._setValue(defaults, 'iast.cookieFilterPattern', '.{32,}')
this._setValue(defaults, 'iast.dbRowsToTaint', 1)
this._setValue(defaults, 'iast.deduplicationEnabled', true)
this._setValue(defaults, 'iast.enabled', false)
this._setValue(defaults, 'iast.maxConcurrentRequests', 2)
this._setValue(defaults, 'iast.maxContextOperations', 2)
this._setValue(defaults, 'iast.redactionEnabled', true)
this._setValue(defaults, 'iast.redactionNamePattern', null)
this._setValue(defaults, 'iast.redactionValuePattern', null)
this._setValue(defaults, 'iast.requestSampling', 30)
this._setValue(defaults, 'iast.securityControlsConfiguration', null)
this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION')
this._setValue(defaults, 'iast.stackTrace.enabled', true)
this._setValue(defaults, 'injectionEnabled', [])
this._setValue(defaults, 'isAzureFunction', false)
this._setValue(defaults, 'isCiVisibility', false)
this._setValue(defaults, 'isEarlyFlakeDetectionEnabled', false)
this._setValue(defaults, 'isFlakyTestRetriesEnabled', false)
this._setValue(defaults, 'flakyTestRetriesCount', 5)
this._setValue(defaults, 'isGCPFunction', false)
this._setValue(defaults, 'isGitUploadEnabled', false)
this._setValue(defaults, 'isIntelligentTestRunnerEnabled', false)
this._setValue(defaults, 'isManualApiEnabled', false)
this._setValue(defaults, 'langchain.spanCharLimit', 128)
this._setValue(defaults, 'langchain.spanPromptCompletionSampleRate', 1.0)
this._setValue(defaults, 'llmobs.agentlessEnabled', false)
this._setValue(defaults, 'llmobs.enabled', false)
this._setValue(defaults, 'llmobs.mlApp', undefined)
this._setValue(defaults, 'ciVisibilityTestSessionName', '')
this._setValue(defaults, 'ciVisAgentlessLogSubmissionEnabled', false)
this._setValue(defaults, 'legacyBaggageEnabled', true)
this._setValue(defaults, 'isTestDynamicInstrumentationEnabled', false)
this._setValue(defaults, 'isServiceUserProvided', false)
this._setValue(defaults, 'testManagementAttemptToFixRetries', 20)
this._setValue(defaults, 'isTestManagementEnabled', false)
this._setValue(defaults, 'logInjection', false)
this._setValue(defaults, 'lookup', undefined)
this._setValue(defaults, 'inferredProxyServicesEnabled', false)
this._setValue(defaults, 'memcachedCommandEnabled', false)
this._setValue(defaults, 'middlewareTracingEnabled', true)
this._setValue(defaults, 'openAiLogsEnabled', false)
this._setValue(defaults, 'openai.spanCharLimit', 128)
this._setValue(defaults, 'peerServiceMapping', {})
this._setValue(defaults, 'plugins', true)
this._setValue(defaults, 'port', '8126')
this._setValue(defaults, 'profiling.enabled', undefined)
this._setValue(defaults, 'profiling.exporters', 'agent')
this._setValue(defaults, 'profiling.sourceMap', true)
this._setValue(defaults, 'profiling.longLivedThreshold', undefined)
this._setValue(defaults, 'protocolVersion', '0.4')
this._setValue(defaults, 'queryStringObfuscation', qsRegex)
this._setValue(defaults, 'remoteConfig.enabled', true)
this._setValue(defaults, 'remoteConfig.pollInterval', 5) // seconds
this._setValue(defaults, 'reportHostname', false)
this._setValue(defaults, 'runtimeMetrics', false)
this._setValue(defaults, 'sampleRate', undefined)
this._setValue(defaults, 'sampler.rateLimit', 100)
this._setValue(defaults, 'sampler.rules', [])
this._setValue(defaults, 'sampler.spanSamplingRules', [])
this._setValue(defaults, 'scope', undefined)
this._setValue(defaults, 'service', service)
this._setValue(defaults, 'serviceMapping', {})
this._setValue(defaults, 'site', 'datadoghq.com')
this._setValue(defaults, 'spanAttributeSchema', 'v0')
this._setValue(defaults, 'spanComputePeerService', false)
this._setValue(defaults, 'spanLeakDebug', 0)
this._setValue(defaults, 'spanRemoveIntegrationFromService', false)
this._setValue(defaults, 'startupLogs', false)
this._setValue(defaults, 'stats.enabled', false)
this._setValue(defaults, 'tags', {})
this._setValue(defaults, 'tagsHeaderMaxLength', 512)
this._setValue(defaults, 'telemetry.debug', false)
this._setValue(defaults, 'telemetry.dependencyCollection', true)
this._setValue(defaults, 'telemetry.enabled', true)
this._setValue(defaults, 'telemetry.heartbeatInterval', 60000)
this._setValue(defaults, 'telemetry.logCollection', true)
this._setValue(defaults, 'telemetry.metrics', true)
this._setValue(defaults, 'traceEnabled', true)
this._setValue(defaults, 'traceId128BitGenerationEnabled', true)
this._setValue(defaults, 'traceId128BitLoggingEnabled', true)
this._setValue(defaults, 'tracePropagationExtractFirst', false)
this._setValue(defaults, 'tracePropagationBehaviorExtract', 'continue')
this._setValue(defaults, 'tracePropagationStyle.inject', ['datadog', 'tracecontext', 'baggage'])
this._setValue(defaults, 'tracePropagationStyle.extract', ['datadog', 'tracecontext', 'baggage'])
this._setValue(defaults, 'tracePropagationStyle.otelPropagators', false)
this._setValue(defaults, 'tracing', true)
this._setValue(defaults, 'url', undefined)
this._setValue(defaults, 'version', pkg.version)
this._setValue(defaults, 'instrumentation_config_id', undefined)
this._setValue(defaults, 'aws.dynamoDb.tablePrimaryKeys', undefined)
this._setValue(defaults, 'vertexai.spanCharLimit', 128)
this._setValue(defaults, 'vertexai.spanPromptCompletionSampleRate', 1.0)
this._setValue(defaults, 'trace.aws.addSpanPointers', true)
this._setValue(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', 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_APM_TRACING_ENABLED,
DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE,
DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
DD_APPSEC_ENABLED,
DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
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_TRACE_RATE_LIMIT,
DD_APPSEC_WAF_TIMEOUT,
DD_CRASHTRACKING_ENABLED,
DD_CODE_ORIGIN_FOR_SPANS_ENABLED,
DD_DATA_STREAMS_ENABLED,
DD_DBM_PROPAGATION_MODE,
DD_DOGSTATSD_HOSTNAME,
DD_DOGSTATSD_HOST,
DD_DOGSTATSD_PORT,
DD_DYNAMIC_INSTRUMENTATION_ENABLED,
DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS,
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS,
DD_ENV,
DD_EXPERIMENTAL_API_SECURITY_ENABLED,
DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
DD_EXPERIMENTAL_PROFILING_ENABLED,
DD_GRPC_CLIENT_ERROR_STATUSES,
DD_GRPC_SERVER_ERROR_STATUSES,
JEST_WORKER_ID,
DD_IAST_COOKIE_FILTER_PATTERN,
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_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_ENABLED,
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_SERVICE,
DD_SERVICE_MAPPING,
DD_SERVICE_NAME,
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_HOSTNAME,
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_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_TRACE_EXPERIMENTAL_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_TELEMETRY_ENABLED,
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
} = process.env
const tags = {}
const env = setHiddenProperty(this, '_env', {})
setHiddenProperty(this, '_envUnprocessed', {})
tagger.add(tags, parseSpaceSeparatedTags(handleOtel(OTEL_RESOURCE_ATTRIBUTES)))
tagger.add(tags, parseSpaceSeparatedTags(DD_TAGS))
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', coalesce(
DD_API_SECURITY_ENABLED && isTrue(DD_API_SECURITY_ENABLED),
DD_EXPERIMENTAL_API_SECURITY_ENABLED && isTrue(DD_EXPERIMENTAL_API_SECURITY_ENABLED)
))
this._setValue(env, 'appsec.apiSecurity.sampleDelay', maybeFloat(DD_API_SECURITY_SAMPLE_DELAY))
this._setValue(env, 'appsec.blockedTemplateGraphql', maybeFile(DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON))
this._setValue(env, 'appsec.blockedTemplateHtml', maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML))
this._envUnprocessed['appsec.blockedTemplateHtml'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML
this._setValue(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', coalesce(
DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE,
DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING // TODO: remove in next major
))
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._setValue(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)
this._setValue(env, 'appsec.stackTrace.maxDepth', maybeInt(DD_APPSEC_MAX_STACK_TRACE_DEPTH))
this._envUnprocessed['appsec.stackTrace.maxDepth'] = DD_APPSEC_MAX_STACK_TRACE_DEPTH
this._setValue(env, 'appsec.stackTrace.maxStackTraces', maybeInt(DD_APPSEC_MAX_STACK_TRACES))
this._envUnprocessed['appsec.stackTrace.maxStackTraces'] = DD_APPSEC_MAX_STACK_TRACES
this._setValue(env, 'appsec.wafTimeout', maybeInt(DD_APPSEC_WAF_TIMEOUT))
this._envUnprocessed['appsec.wafTimeout'] = DD_APPSEC_WAF_TIMEOUT
this._setValue(env, 'baggageMaxBytes', DD_TRACE_BAGGAGE_MAX_BYTES)
this._setValue(env, 'baggageMaxItems', DD_TRACE_BAGGAGE_MAX_ITEMS)
this._setBoolean(env, 'clientIpEnabled', DD_TRACE_CLIENT_IP_ENABLED)
this._setString(env, 'clientIpHeader', DD_TRACE_CLIENT_IP_HEADER)
this._setBoolean(env, 'crashtracking.enabled', coalesce(
DD_CRASHTRACKING_ENABLED,
!this._isInServerlessEnvironment()
))
this._setBoolean(env, 'codeOriginForSpans.enabled', DD_CODE_ORIGIN_FOR_SPANS_ENABLED)
this._setString(env, 'dbmPropagationMode', DD_DBM_PROPAGATION_MODE)
this._setString(env, 'dogstatsd.hostname', DD_DOGSTATSD_HOST || DD_DOGSTATSD_HOSTNAME)
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._setArray(env, 'dynamicInstrumentation.redactedIdentifiers', DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS)
this._setArray(
env,
'dynamicInstrumentation.redactionExcludedIdentifiers',
DD_DYNAMIC_INSTRUMENTATION_REDACTION_EXCLUDED_IDENTIFIERS
)
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)
this._setBoolean(env, 'experimental.runtimeId', DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED)
if (AWS_LAMBDA_FUNCTION_NAME) this._setValue(env, 'flushInterval', 0)
this._setValue(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)
this._setString(env, 'hostname', coalesce(DD_AGENT_HOST, DD_TRACE_AGENT_HOSTNAME))
this._setString(env, 'iast.cookieFilterPattern', DD_IAST_COOKIE_FILTER_PATTERN)
this._setValue(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)
this._setValue(env, 'iast.maxConcurrentRequests', maybeInt(DD_IAST_MAX_CONCURRENT_REQUESTS))
this._envUnprocessed['iast.maxConcurrentRequests'] = DD_IAST_MAX_CONCURRENT_REQUESTS
this._setValue(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) {
this._setValue(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._setBoolean(env, 'isAzureFunction', getIsAzureFunction())
this._setBoolean(env, 'isGCPFunction', getIsGCPFunction())
this._setValue(env, 'langchain.spanCharLimit', maybeInt(DD_LANGCHAIN_SPAN_CHAR_LIMIT))
this._setValue(
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)
this._setValue(env, 'openai.spanCharLimit', maybeInt(DD_OPENAI_SPAN_CHAR_LIMIT))
this._envUnprocessed.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
if (DD_TRACE_PEER_SERVICE_MAPPING) {
this._setValue(env, 'peerServiceMapping', 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_EXPERIMENTAL_PROFILING_ENABLED,
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
this._setValue(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()
))
this._setValue(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', DD_RUNTIME_METRICS_ENABLED ||
otelSetRuntimeMetrics)
this._setArray(env, 'sampler.spanSamplingRules', reformatSpanSamplingRules(coalesce(
safeJsonParse(maybeFile(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))
this._setValue(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 || DD_SERVICE_NAME || tags.service || OTEL_SERVICE_NAME)
if (DD_SERVICE_MAPPING) {
this._setValue(env, 'serviceMapping', fromEntries(
process.env.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
this._setValue(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)
this._setValue(env, 'tagsHeaderMaxLength', DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
this._setBoolean(env, 'telemetry.enabled', coalesce(
DD_TRACE_TELEMETRY_ENABLED, // for backward compatibility
DD_INSTRUMENTATION_TELEMETRY_ENABLED, // to comply with instrumentation telemetry specs
!(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)
this._setValue(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)
this._setValue(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, '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)
this._setValue(
env,
'vertexai.spanPromptCompletionSampleRate',
maybeFloat(DD_VERTEXAI_SPAN_PROMPT_COMPLETION_SAMPLE_RATE)
)
this._setValue(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', Object.assign({ 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._setValue(opts, 'appsec.blockedTemplateGraphql', maybeFile(options.appsec.blockedTemplateGraphql))
this._setValue(opts, 'appsec.blockedTemplateHtml', maybeFile(options.appsec.blockedTemplateHtml))
this._optsUnprocessed['appsec.blockedTemplateHtml'] = options.appsec.blockedTemplateHtml
this._setValue(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._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._setValue(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)
this._setValue(opts, 'appsec.stackTrace.maxDepth', maybeInt(options.appsec.stackTrace?.maxDepth))
this._optsUnprocessed['appsec.stackTrace.maxDepth'] = options.appsec.stackTrace?.maxDepth
this._setValue(opts, 'appsec.stackTrace.maxStackTraces', maybeInt(options.appsec.stackTrace?.maxStackTraces))
this._optsUnprocessed['appsec.stackTrace.maxStackTraces'] = options.appsec.stackTrace?.maxStackTraces
this._setValue(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)
this._setValue(opts, 'baggageMaxBytes', options.baggageMaxBytes)
this._setValue(opts, 'baggageMaxItems', options.baggageMaxItems)
this._setBoolean(opts, 'codeOriginForSpans.enabled', options.codeOriginForSpans?.enabled)
this._setString(opts, 'dbmPropagationMode', options.dbmPropagationMode)
if (options.dogstatsd) {
this._setString(opts, 'dogstatsd.hostname', options.dogstatsd.hostname)
this._setString(opts, 'dogstatsd.port', options.dogstatsd.port)
}
this._setBoolean(opts, 'dsmEnabled', options.dsmEnabled)
this._setBoolean(opts, 'dynamicInstrumentation.enabled', options.dynamicInstrumentation?.enabled)
this._setArray(
opts,
'dynamicInstrumentation.redactedIdentifiers',
options.dynamicInstrumentation?.redactedIdentifiers
)
this._setArray(
opts,
'dynamicInstrumentation.redactionExcludedIdentifiers',
options.dynamicInstrumentation?.redactionExcludedIdentifiers
)
this._setString(opts, 'env', options.env || tags.env)
this._setBoolean(opts, 'experimental.enableGetRumData', options.experimental?.enableGetRumData)
this._setString(opts, 'experimental.exporter', options.experimental?.exporter)
this._setBoolean(opts, 'experimental.runtimeId', options.experimental?.runtimeId)
this._setValue(opts, 'flushInterval', maybeInt(options.flushInterval))
this._optsUnprocessed.flushInterval = options.flushInterval
this._setValue(opts, 'flushMinSpans', maybeInt(options.flushMinSpans))
this._optsUnprocessed.flushMinSpans = options.flushMinSpans
this._setArray(opts, 'headerTags', options.headerTags)
this._setString(opts, 'hostname', options.hostname)
this._setString(opts, 'iast.cookieFilterPattern', options.iast?.cookieFilterPattern)
this._setValue(opts, 'iast.dbRowsToTaint', maybeInt(options.iast?.dbRowsToTaint))
this._setBoolean(opts, 'iast.deduplicationEnabled', options.iast && options.iast.deduplicationEnabled)
this._setBoolean(opts, 'iast.enabled',
options.iast && (options.iast === true || options.iast.enabled === true))
this._setValue(opts, 'iast.maxConcurrentRequests',
maybeInt(options.iast?.maxConcurrentRequests))
this._optsUnprocessed['iast.maxConcurrentRequests'] = options.iast?.maxConcurrentRequests
this._setValue(opts, 'iast.maxContextOperations', maybeInt(options.iast?.maxContextOperations))
this._optsUnprocessed['iast.maxContextOperations'] = options.iast?.maxContextOperations
this._setBoolean(opts, 'iast.redactionEnabled', options.iast?.redactionEnabled)
this._setString(opts, 'iast.redactionNamePattern', options.iast?.redactionN