Comparing version 4.37.0 to 4.38.0
30
init.js
'use strict' | ||
const tracer = require('.') | ||
const path = require('path') | ||
const Module = require('module') | ||
tracer.init() | ||
let initBailout = false | ||
module.exports = tracer | ||
if (process.env.DD_INJECTION_ENABLED) { | ||
// If we're running via single-step install, and we're not in the app's | ||
// node_modules, then we should not initialize the tracer. This prevents | ||
// single-step-installed tracer from clobbering the manually-installed tracer. | ||
let resolvedInApp | ||
const entrypoint = process.argv[1] | ||
try { | ||
resolvedInApp = Module.createRequire(entrypoint).resolve('dd-trace') | ||
} catch (e) { | ||
// Ignore. If we can't resolve the module, we assume it's not in the app. | ||
} | ||
if (resolvedInApp) { | ||
const ourselves = path.join(__dirname, 'index.js') | ||
if (ourselves !== resolvedInApp) { | ||
initBailout = true | ||
} | ||
} | ||
} | ||
if (!initBailout) { | ||
const tracer = require('.') | ||
tracer.init() | ||
module.exports = tracer | ||
} |
{ | ||
"name": "dd-trace", | ||
"version": "4.37.0", | ||
"version": "4.38.0", | ||
"description": "Datadog APM tracing client for JavaScript", | ||
@@ -77,5 +77,5 @@ "main": "index.js", | ||
"@datadog/native-metrics": "^2.0.0", | ||
"@datadog/pprof": "5.2.0", | ||
"@datadog/pprof": "5.3.0", | ||
"@datadog/sketches-js": "^2.1.0", | ||
"@opentelemetry/api": "^1.0.0", | ||
"@opentelemetry/api": ">=1.0.0 <1.9.0", | ||
"@opentelemetry/core": "^1.14.0", | ||
@@ -82,0 +82,0 @@ "crypto-randomuuid": "^1.0.0", |
@@ -5,31 +5,5 @@ 'use strict' | ||
const log = require('../../log') | ||
const { calculateDDBasePath } = require('../../util') | ||
const telemetryLog = dc.channel('datadog:telemetry:log') | ||
const ddBasePath = calculateDDBasePath(__dirname) | ||
const EOL = '\n' | ||
const STACK_FRAME_LINE_REGEX = /^\s*at\s/gm | ||
function sanitize (logEntry, stack) { | ||
if (!stack) return logEntry | ||
let stackLines = stack.split(EOL) | ||
const firstIndex = stackLines.findIndex(l => l.match(STACK_FRAME_LINE_REGEX)) | ||
const isDDCode = firstIndex > -1 && stackLines[firstIndex].includes(ddBasePath) | ||
stackLines = stackLines | ||
.filter((line, index) => (isDDCode && index < firstIndex) || line.includes(ddBasePath)) | ||
.map(line => line.replace(ddBasePath, '')) | ||
logEntry.stack_trace = stackLines.join(EOL) | ||
if (!isDDCode) { | ||
logEntry.message = 'omitted' | ||
} | ||
return logEntry | ||
} | ||
function getTelemetryLog (data, level) { | ||
@@ -46,14 +20,9 @@ try { | ||
let logEntry = { | ||
const logEntry = { | ||
message, | ||
level | ||
} | ||
if (data.stack) { | ||
logEntry = sanitize(logEntry, data.stack) | ||
if (logEntry.stack_trace === '') { | ||
return | ||
} | ||
logEntry.stack_trace = data.stack | ||
} | ||
return logEntry | ||
@@ -60,0 +29,0 @@ } catch (e) { |
@@ -19,3 +19,3 @@ 'use strict' | ||
const telemetryMetrics = require('./telemetry/metrics') | ||
const { getIsGCPFunction, getIsAzureFunctionConsumptionPlan } = require('./serverless') | ||
const { getIsGCPFunction, getIsAzureFunction } = require('./serverless') | ||
const { ORIGIN_KEY } = require('./constants') | ||
@@ -343,3 +343,3 @@ | ||
this.memcachedCommandEnabled = isTrue(DD_TRACE_MEMCACHED_COMMAND_ENABLED) | ||
this.isAzureFunctionConsumptionPlan = getIsAzureFunctionConsumptionPlan() | ||
this.isAzureFunction = getIsAzureFunction() | ||
this.spanLeakDebug = Number(DD_TRACE_SPAN_LEAK_DEBUG) | ||
@@ -422,4 +422,4 @@ this.installSignature = { | ||
const isGCPFunction = getIsGCPFunction() | ||
const isAzureFunctionConsumptionPlan = getIsAzureFunctionConsumptionPlan() | ||
return inAWSLambda || isGCPFunction || isAzureFunctionConsumptionPlan | ||
const isAzureFunction = getIsAzureFunction() | ||
return inAWSLambda || isGCPFunction || isAzureFunction | ||
} | ||
@@ -555,2 +555,3 @@ | ||
DD_IAST_TELEMETRY_VERBOSITY, | ||
DD_INJECTION_ENABLED, | ||
DD_INSTRUMENTATION_TELEMETRY_ENABLED, | ||
@@ -712,3 +713,10 @@ DD_INSTRUMENTATION_CONFIG_ID, | ||
this._setValue(env, 'telemetry.heartbeatInterval', maybeInt(Math.floor(DD_TELEMETRY_HEARTBEAT_INTERVAL * 1000))) | ||
this._setBoolean(env, 'telemetry.logCollection', coalesce(DD_TELEMETRY_LOG_COLLECTION_ENABLED, DD_IAST_ENABLED)) | ||
const hasTelemetryLogsUsingFeatures = | ||
isTrue(DD_IAST_ENABLED) || | ||
isTrue(DD_PROFILING_ENABLED) || | ||
(typeof DD_INJECTION_ENABLED === 'string' && DD_INJECTION_ENABLED.split(',').includes('profiling')) | ||
? true | ||
: undefined | ||
this._setBoolean(env, 'telemetry.logCollection', coalesce(DD_TELEMETRY_LOG_COLLECTION_ENABLED, | ||
hasTelemetryLogsUsingFeatures)) | ||
this._setBoolean(env, 'telemetry.metrics', DD_TELEMETRY_METRICS_ENABLED) | ||
@@ -794,4 +802,6 @@ this._setBoolean(env, 'traceId128BitGenerationEnabled', DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED) | ||
this._setTags(opts, 'tags', tags) | ||
this._setBoolean(opts, 'telemetry.logCollection', options.iastOptions && | ||
(options.iastOptions === true || options.iastOptions.enabled === true)) | ||
const hasTelemetryLogsUsingFeatures = | ||
(options.iastOptions && (options.iastOptions === true || options.iastOptions?.enabled === true)) || | ||
(options.profiling && options.profiling === true) | ||
this._setBoolean(opts, 'telemetry.logCollection', hasTelemetryLogsUsingFeatures) | ||
this._setBoolean(opts, 'traceId128BitGenerationEnabled', options.traceId128BitGenerationEnabled) | ||
@@ -876,3 +886,3 @@ this._setBoolean(opts, 'traceId128BitLoggingEnabled', options.traceId128BitLoggingEnabled) | ||
process.env.DD_TRACE_STATS_COMPUTATION_ENABLED, | ||
getIsGCPFunction() || getIsAzureFunctionConsumptionPlan() | ||
getIsGCPFunction() || getIsAzureFunction() | ||
) | ||
@@ -879,0 +889,0 @@ } |
@@ -86,9 +86,13 @@ 'use strict' | ||
if (span.type) { | ||
if (span.type && span.meta_struct) { | ||
bytes.buffer[bytes.length++] = 0x8d | ||
} else if (span.type || span.meta_struct) { | ||
bytes.buffer[bytes.length++] = 0x8c | ||
} else { | ||
bytes.buffer[bytes.length++] = 0x8b | ||
} | ||
if (span.type) { | ||
this._encodeString(bytes, 'type') | ||
this._encodeString(bytes, span.type) | ||
} else { | ||
bytes.buffer[bytes.length++] = 0x8b | ||
} | ||
@@ -118,2 +122,6 @@ | ||
this._encodeMap(bytes, span.metrics) | ||
if (span.meta_struct) { | ||
this._encodeString(bytes, 'meta_struct') | ||
this._encodeObject(bytes, span.meta_struct) | ||
} | ||
} | ||
@@ -268,2 +276,41 @@ } | ||
_encodeObject (bytes, value, circularReferencesDetector = new Set()) { | ||
circularReferencesDetector.add(value) | ||
if (Array.isArray(value)) { | ||
return this._encodeObjectAsArray(bytes, value, circularReferencesDetector) | ||
} else if (value !== null && typeof value === 'object') { | ||
return this._encodeObjectAsMap(bytes, value, circularReferencesDetector) | ||
} else if (typeof value === 'string' || typeof value === 'number') { | ||
this._encodeValue(bytes, value) | ||
} | ||
} | ||
_encodeObjectAsMap (bytes, value, circularReferencesDetector) { | ||
const keys = Object.keys(value) | ||
const validKeys = keys.filter(key => | ||
typeof value[key] === 'string' || | ||
typeof value[key] === 'number' || | ||
(value[key] !== null && typeof value[key] === 'object' && !circularReferencesDetector.has(value[key]))) | ||
this._encodeMapPrefix(bytes, validKeys.length) | ||
for (const key of validKeys) { | ||
this._encodeString(bytes, key) | ||
this._encodeObject(bytes, value[key], circularReferencesDetector) | ||
} | ||
} | ||
_encodeObjectAsArray (bytes, value, circularReferencesDetector) { | ||
const validValue = value.filter(item => | ||
typeof item === 'string' || | ||
typeof item === 'number' || | ||
(item !== null && typeof item === 'object' && !circularReferencesDetector.has(item))) | ||
this._encodeArrayPrefix(bytes, validValue) | ||
for (const item of validValue) { | ||
this._encodeObject(bytes, item, circularReferencesDetector) | ||
} | ||
} | ||
_cacheString (value) { | ||
@@ -270,0 +317,0 @@ if (!(value in this._stringMap)) { |
@@ -8,2 +8,3 @@ 'use strict' | ||
const dc = require('dc-polyfill') | ||
const telemetryLog = dc.channel('datadog:telemetry:log') | ||
@@ -19,2 +20,15 @@ const profileSubmittedChannel = dc.channel('datadog:profiling:profile-submitted') | ||
function logError (logger, err) { | ||
if (logger) { | ||
logger.error(err) | ||
} | ||
if (telemetryLog.hasSubscribers) { | ||
telemetryLog.publish({ | ||
message: err.message, | ||
level: 'ERROR', | ||
stack_trace: err.stack | ||
}) | ||
} | ||
} | ||
class Profiler extends EventEmitter { | ||
@@ -33,5 +47,3 @@ constructor () { | ||
return this._start(options).catch((err) => { | ||
if (options.logger) { | ||
options.logger.error(err) | ||
} | ||
logError(options.logger, err) | ||
return false | ||
@@ -41,2 +53,6 @@ }) | ||
_logError (err) { | ||
logError(this._logger, err) | ||
} | ||
async _start (options) { | ||
@@ -68,3 +84,3 @@ if (this._enabled) return true | ||
} catch (err) { | ||
this._logger.error(err) | ||
this._logError(err) | ||
} | ||
@@ -86,3 +102,3 @@ | ||
} catch (e) { | ||
this._logger.error(e) | ||
this._logError(e) | ||
this._stop() | ||
@@ -176,3 +192,3 @@ return false | ||
} catch (err) { | ||
this._logger.error(err) | ||
this._logError(err) | ||
this._stop() | ||
@@ -192,3 +208,3 @@ } | ||
const task = exporter.export({ profiles, start, end, tags }) | ||
.catch(err => this._logger.error(err)) | ||
.catch(err => this._logError(err)) | ||
@@ -195,0 +211,0 @@ tasks.push(task) |
@@ -17,2 +17,3 @@ 'use strict' | ||
const { SSITelemetry } = require('./profiling/ssi-telemetry') | ||
const telemetryLog = require('dc-polyfill').channel('datadog:telemetry:log') | ||
@@ -95,3 +96,3 @@ class LazyModule { | ||
if (config.isGCPFunction || config.isAzureFunctionConsumptionPlan) { | ||
if (config.isGCPFunction || config.isAzureFunction) { | ||
require('./serverless').maybeStartServerlessMiniAgent(config) | ||
@@ -109,2 +110,7 @@ } | ||
log.error(e) | ||
telemetryLog.publish({ | ||
message: e.message, | ||
level: 'ERROR', | ||
stack_trace: e.stack | ||
}) | ||
} | ||
@@ -111,0 +117,0 @@ } else if (ssiTelemetry.enabled()) { |
@@ -56,9 +56,7 @@ 'use strict' | ||
function getIsAzureFunctionConsumptionPlan () { | ||
function getIsAzureFunction () { | ||
const isAzureFunction = | ||
process.env.FUNCTIONS_EXTENSION_VERSION !== undefined && process.env.FUNCTIONS_WORKER_RUNTIME !== undefined | ||
const azureWebsiteSKU = process.env.WEBSITE_SKU | ||
const isConsumptionPlan = azureWebsiteSKU === undefined || azureWebsiteSKU === 'Dynamic' | ||
return isAzureFunction && isConsumptionPlan | ||
return isAzureFunction | ||
} | ||
@@ -69,4 +67,4 @@ | ||
getIsGCPFunction, | ||
getIsAzureFunctionConsumptionPlan, | ||
getIsAzureFunction, | ||
getRustBinaryPath | ||
} |
'use strict' | ||
const log = require('../../log') | ||
const { calculateDDBasePath } = require('../../util') | ||
@@ -32,2 +33,33 @@ const logs = new Map() | ||
const ddBasePath = calculateDDBasePath(__dirname) | ||
const EOL = '\n' | ||
const STACK_FRAME_LINE_REGEX = /^\s*at\s/gm | ||
function sanitize (logEntry) { | ||
const stack = logEntry.stack_trace | ||
if (!stack) return logEntry | ||
let stackLines = stack.split(EOL) | ||
const firstIndex = stackLines.findIndex(l => l.match(STACK_FRAME_LINE_REGEX)) | ||
const isDDCode = firstIndex > -1 && stackLines[firstIndex].includes(ddBasePath) | ||
stackLines = stackLines | ||
.filter((line, index) => (isDDCode && index < firstIndex) || line.includes(ddBasePath)) | ||
.map(line => line.replace(ddBasePath, '')) | ||
logEntry.stack_trace = stackLines.join(EOL) | ||
if (logEntry.stack_trace === '') { | ||
// If entire stack was removed, we'd just have a message saying "omitted" | ||
// in which case we'd rather not log it at all. | ||
return null | ||
} | ||
if (!isDDCode) { | ||
logEntry.message = 'omitted' | ||
} | ||
return logEntry | ||
} | ||
const logCollector = { | ||
@@ -41,5 +73,9 @@ add (logEntry) { | ||
overflowedCount++ | ||
return | ||
return false | ||
} | ||
logEntry = sanitize(logEntry) | ||
if (!logEntry) { | ||
return false | ||
} | ||
const hash = createHash(logEntry) | ||
@@ -56,2 +92,7 @@ if (!logs.has(hash)) { | ||
// Used for testing | ||
hasEntry (logEntry) { | ||
return logs.has(createHash(logEntry)) | ||
}, | ||
drain () { | ||
@@ -58,0 +99,0 @@ if (logs.size === 0) return |
@@ -111,2 +111,9 @@ # `dd-trace`: Node.js APM Tracer Library | ||
Please refer to the [SECURITY.md](https://github.com/DataDog/dd-trace-js/blob/master/SECURITY.md) document if you have found a security issue. | ||
Please refer to the [SECURITY.md](https://github.com/DataDog/dd-trace-js/blob/master/SECURITY.md) document if you have found a security issue. | ||
## Datadog With OpenTelemetery | ||
Please refer to the [Node.js Custom Instrumentation using OpenTelemetry API](https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/nodejs/otel/) document. It includes information on how to use the OpenTelemetry API with dd-trace-js | ||
Note that our internal implementation of the OpenTelemetry API is currently set within the version range `>=1.0.0 <1.9.0`. This range will be updated at a regular cadence therefore, we recommend updating your tracer to the latest release to ensure up to date support. | ||
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
1780845
51536
119
173
+ Added@datadog/pprof@5.3.0(transitive)
+ Added@opentelemetry/api@1.8.0(transitive)
- Removed@datadog/pprof@5.2.0(transitive)
- Removed@opentelemetry/api@1.9.0(transitive)
Updated@datadog/pprof@5.3.0