Comparing version 5.30.0 to 5.31.0
{ | ||
"name": "dd-trace", | ||
"version": "5.30.0", | ||
"version": "5.31.0", | ||
"description": "Datadog APM tracing client for JavaScript", | ||
@@ -85,3 +85,3 @@ "main": "index.js", | ||
"@datadog/libdatadog": "^0.3.0", | ||
"@datadog/native-appsec": "8.3.0", | ||
"@datadog/native-appsec": "8.4.0", | ||
"@datadog/native-iast-rewriter": "2.6.1", | ||
@@ -149,3 +149,3 @@ "@datadog/native-iast-taint-tracking": "3.2.0", | ||
"mkdirp": "^3.0.1", | ||
"mocha": "^9", | ||
"mocha": "^10", | ||
"msgpack-lite": "^0.1.26", | ||
@@ -152,0 +152,0 @@ "multer": "^1.4.5-lts.1", |
@@ -24,4 +24,12 @@ 'use strict' | ||
getStore () { | ||
const handle = this._storage.getStore() | ||
// TODO: Refactor the Scope class to use a span-only store and remove this. | ||
getHandle () { | ||
return this._storage.getStore() | ||
} | ||
getStore (handle) { | ||
if (!handle) { | ||
handle = this._storage.getStore() | ||
} | ||
return stores.get(handle) | ||
@@ -54,2 +62,3 @@ } | ||
storage.exit = legacyStorage.exit.bind(legacyStorage) | ||
storage.getHandle = legacyStorage.getHandle.bind(legacyStorage) | ||
storage.getStore = legacyStorage.getStore.bind(legacyStorage) | ||
@@ -56,0 +65,0 @@ storage.run = legacyStorage.run.bind(legacyStorage) |
@@ -43,3 +43,3 @@ 'use strict' | ||
file: 'lib/commands/command.js', | ||
versions: ['4', '5'] | ||
versions: ['4', '5', '6'] | ||
}, | ||
@@ -46,0 +46,0 @@ commandFactory => { |
@@ -12,2 +12,3 @@ 'use strict' | ||
const Scheduler = require('./scheduler') | ||
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../../plugins/util/tags') | ||
@@ -37,2 +38,10 @@ const clientId = uuid() | ||
const tags = config.repositoryUrl | ||
? { | ||
...config.tags, | ||
[GIT_REPOSITORY_URL]: config.repositoryUrl, | ||
[GIT_COMMIT_SHA]: config.commitSHA | ||
} | ||
: config.tags | ||
this._handlers = new Map() | ||
@@ -72,3 +81,4 @@ const appliedConfigs = this.appliedConfigs = new Map() | ||
app_version: config.version, | ||
extra_services: [] | ||
extra_services: [], | ||
tags: Object.entries(tags).map((pair) => pair.join(':')) | ||
}, | ||
@@ -75,0 +85,0 @@ capabilities: DEFAULT_CAPABILITY // updated by `updateCapabilities()` |
@@ -12,3 +12,4 @@ 'use strict' | ||
repositoryUrl: parentConfig.repositoryUrl, | ||
parentThreadId | ||
parentThreadId, | ||
maxTotalPayloadSize: 5 * 1024 * 1024 // 5MB | ||
} | ||
@@ -15,0 +16,0 @@ |
@@ -132,5 +132,4 @@ 'use strict' | ||
// TODO: Process template (DEBUG-2628) | ||
send(probe.template, logger, dd, snapshot, (err) => { | ||
if (err) log.error('Debugger error', err) | ||
else ackEmitting(probe) | ||
send(probe.template, logger, dd, snapshot, () => { | ||
ackEmitting(probe) | ||
}) | ||
@@ -145,2 +144,4 @@ } | ||
async function getDD (callFrameId) { | ||
// TODO: Consider if an `objectGroup` should be used, so it can be explicitly released using | ||
// `Runtime.releaseObjectGroup` | ||
const { result } = await session.post('Debugger.evaluateOnCallFrame', { | ||
@@ -147,0 +148,0 @@ callFrameId, |
@@ -7,8 +7,11 @@ 'use strict' | ||
const config = require('./config') | ||
const JSONBuffer = require('./json-buffer') | ||
const request = require('../../exporters/common/request') | ||
const { GIT_COMMIT_SHA, GIT_REPOSITORY_URL } = require('../../plugins/util/tags') | ||
const log = require('../../log') | ||
const { version } = require('../../../../../package.json') | ||
module.exports = send | ||
const MAX_PAYLOAD_SIZE = 1024 * 1024 // 1MB | ||
const MAX_LOG_PAYLOAD_SIZE = 1024 * 1024 // 1MB | ||
@@ -20,2 +23,6 @@ const ddsource = 'dd_debugger' | ||
const ddtags = [ | ||
['env', process.env.DD_ENV], | ||
['version', process.env.DD_VERSION], | ||
['debugger_version', version], | ||
['host_name', hostname], | ||
[GIT_COMMIT_SHA, config.commitSHA], | ||
@@ -27,10 +34,6 @@ [GIT_REPOSITORY_URL, config.repositoryUrl] | ||
let callbacks = [] | ||
const jsonBuffer = new JSONBuffer({ size: config.maxTotalPayloadSize, timeout: 1000, onFlush }) | ||
function send (message, logger, dd, snapshot, cb) { | ||
const opts = { | ||
method: 'POST', | ||
url: config.url, | ||
path, | ||
headers: { 'Content-Type': 'application/json; charset=utf-8' } | ||
} | ||
const payload = { | ||
@@ -47,4 +50,5 @@ ddsource, | ||
let json = JSON.stringify(payload) | ||
let size = Buffer.byteLength(json) | ||
if (Buffer.byteLength(json) > MAX_PAYLOAD_SIZE) { | ||
if (size > MAX_LOG_PAYLOAD_SIZE) { | ||
// TODO: This is a very crude way to handle large payloads. Proper pruning will be implemented later (DEBUG-2624) | ||
@@ -57,5 +61,24 @@ const line = Object.values(payload['debugger.snapshot'].captures.lines)[0] | ||
json = JSON.stringify(payload) | ||
size = Buffer.byteLength(json) | ||
} | ||
request(json, opts, cb) | ||
jsonBuffer.write(json, size) | ||
callbacks.push(cb) | ||
} | ||
function onFlush (payload) { | ||
const opts = { | ||
method: 'POST', | ||
url: config.url, | ||
path, | ||
headers: { 'Content-Type': 'application/json; charset=utf-8' } | ||
} | ||
const _callbacks = callbacks | ||
callbacks = [] | ||
request(payload, opts, (err) => { | ||
if (err) log.error('Could not send debugger payload', err) | ||
else _callbacks.forEach(cb => cb()) | ||
}) | ||
} |
@@ -5,2 +5,3 @@ 'use strict' | ||
const config = require('./config') | ||
const JSONBuffer = require('./json-buffer') | ||
const request = require('../../exporters/common/request') | ||
@@ -29,2 +30,4 @@ const FormData = require('../../exporters/common/form-data') | ||
const jsonBuffer = new JSONBuffer({ size: config.maxTotalPayloadSize, timeout: 1000, onFlush }) | ||
const STATUSES = { | ||
@@ -76,2 +79,6 @@ RECEIVED: 'RECEIVED', | ||
function send (payload) { | ||
jsonBuffer.write(JSON.stringify(payload)) | ||
} | ||
function onFlush (payload) { | ||
const form = new FormData() | ||
@@ -81,3 +88,3 @@ | ||
'event', | ||
JSON.stringify(payload), | ||
payload, | ||
{ filename: 'event.json', contentType: 'application/json; charset=utf-8' } | ||
@@ -94,3 +101,3 @@ ) | ||
request(form, options, (err) => { | ||
if (err) log.error('[debugger:devtools_client] Error sending debugger payload', err) | ||
if (err) log.error('[debugger:devtools_client] Error sending probe payload', err) | ||
}) | ||
@@ -97,0 +104,0 @@ } |
'use strict' | ||
const { SPAN_KIND, OUTPUT_VALUE } = require('./constants/tags') | ||
const { SPAN_KIND, OUTPUT_VALUE, INPUT_VALUE } = require('./constants/tags') | ||
@@ -9,3 +9,3 @@ const { | ||
} = require('./util') | ||
const { isTrue } = require('../util') | ||
const { isTrue, isError } = require('../util') | ||
@@ -138,25 +138,59 @@ const { storage } = require('./storage') | ||
const span = llmobs._tracer.scope().active() | ||
const fnArgs = arguments | ||
const result = llmobs._activate(span, { kind, options: llmobsOptions }, () => { | ||
if (!['llm', 'embedding'].includes(kind)) { | ||
llmobs.annotate(span, { inputData: getFunctionArguments(fn, arguments) }) | ||
} | ||
const lastArgId = fnArgs.length - 1 | ||
const cb = fnArgs[lastArgId] | ||
const hasCallback = typeof cb === 'function' | ||
return fn.apply(this, arguments) | ||
}) | ||
if (hasCallback) { | ||
const scopeBoundCb = llmobs._bind(cb) | ||
fnArgs[lastArgId] = function () { | ||
// it is standard practice to follow the callback signature (err, result) | ||
// however, we try to parse the arguments to determine if the first argument is an error | ||
// if it is not, and is not undefined, we will use that for the output value | ||
const maybeError = arguments[0] | ||
const maybeResult = arguments[1] | ||
if (result && typeof result.then === 'function') { | ||
return result.then(value => { | ||
if (value && !['llm', 'retrieval'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[OUTPUT_VALUE]) { | ||
llmobs.annotate(span, { outputData: value }) | ||
} | ||
return value | ||
}) | ||
llmobs._autoAnnotate( | ||
span, | ||
kind, | ||
getFunctionArguments(fn, fnArgs), | ||
isError(maybeError) || maybeError == null ? maybeResult : maybeError | ||
) | ||
return scopeBoundCb.apply(this, arguments) | ||
} | ||
} | ||
if (result && !['llm', 'retrieval'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[OUTPUT_VALUE]) { | ||
llmobs.annotate(span, { outputData: result }) | ||
try { | ||
const result = llmobs._activate(span, { kind, options: llmobsOptions }, () => fn.apply(this, fnArgs)) | ||
if (result && typeof result.then === 'function') { | ||
return result.then( | ||
value => { | ||
if (!hasCallback) { | ||
llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), value) | ||
} | ||
return value | ||
}, | ||
err => { | ||
llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs)) | ||
throw err | ||
} | ||
) | ||
} | ||
// it is possible to return a value and have a callback | ||
// however, since the span finishes when the callback is called, it is possible that | ||
// the callback is called before the function returns (although unlikely) | ||
// we do not want to throw for "annotating a finished span" in this case | ||
if (!hasCallback) { | ||
llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs), result) | ||
} | ||
return result | ||
} catch (e) { | ||
llmobs._autoAnnotate(span, kind, getFunctionArguments(fn, fnArgs)) | ||
throw e | ||
} | ||
return result | ||
} | ||
@@ -338,2 +372,15 @@ | ||
_autoAnnotate (span, kind, input, output) { | ||
const annotations = {} | ||
if (input && !['llm', 'embedding'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[INPUT_VALUE]) { | ||
annotations.inputData = input | ||
} | ||
if (output && !['llm', 'retrieval'].includes(kind) && !LLMObsTagger.tagMap.get(span)?.[OUTPUT_VALUE]) { | ||
annotations.outputData = output | ||
} | ||
this.annotate(span, annotations) | ||
} | ||
_active () { | ||
@@ -344,11 +391,12 @@ const store = storage.getStore() | ||
_activate (span, { kind, options } = {}, fn) { | ||
_activate (span, options, fn) { | ||
const parent = this._active() | ||
if (this.enabled) storage.enterWith({ span }) | ||
this._tagger.registerLLMObsSpan(span, { | ||
...options, | ||
parent, | ||
kind | ||
}) | ||
if (options) { | ||
this._tagger.registerLLMObsSpan(span, { | ||
...options, | ||
parent | ||
}) | ||
} | ||
@@ -362,2 +410,18 @@ try { | ||
// bind function to active LLMObs span | ||
_bind (fn) { | ||
if (typeof fn !== 'function') return fn | ||
const llmobs = this | ||
const activeSpan = llmobs._active() | ||
const bound = function () { | ||
return llmobs._activate(activeSpan, null, () => { | ||
return fn.apply(this, arguments) | ||
}) | ||
} | ||
return bound | ||
} | ||
_extractOptions (options) { | ||
@@ -364,0 +428,0 @@ const { |
@@ -66,11 +66,10 @@ 'use strict' | ||
const fn = logRecord.stack.split('\n')[1].replace(/^\s+at ([^\s]+) .+/, '$1') | ||
const params = args.map(a => { | ||
return a && a.hasOwnProperty('toString') && typeof a.toString === 'function' | ||
? a.toString() | ||
: inspect(a, { depth: 3, breakLength: Infinity, compact: true }) | ||
}).join(', ') | ||
const formatted = logRecord.stack.replace('Error: ', `Trace: ${fn}(${params})`) | ||
const stack = logRecord.stack.split('\n') | ||
const fn = stack[1].replace(/^\s+at ([^\s]+) .+/, '$1') | ||
const options = { depth: 2, breakLength: Infinity, compact: true, maxArrayLength: Infinity } | ||
const params = args.map(a => inspect(a, options)).join(', ') | ||
traceChannel.publish(Log.parse(formatted)) | ||
stack[0] = `Trace: ${fn}(${params})` | ||
traceChannel.publish(Log.parse(stack.join('\n'))) | ||
} | ||
@@ -77,0 +76,0 @@ return this |
@@ -13,3 +13,3 @@ 'use strict' | ||
class Tracer { | ||
class NoopProxy { | ||
constructor () { | ||
@@ -95,2 +95,2 @@ this._tracer = noop | ||
module.exports = Tracer | ||
module.exports = NoopProxy |
@@ -9,3 +9,3 @@ 'use strict' | ||
constructor (tracer, parent) { | ||
this._store = storage.getStore() | ||
this._store = storage.getHandle() | ||
this._noopTracer = tracer | ||
@@ -12,0 +12,0 @@ this._noopContext = this._createContext(parent) |
'use strict' | ||
const util = require('util') | ||
const { AUTO_KEEP } = require('../../../../ext/priority') | ||
@@ -34,2 +35,13 @@ | ||
[util.inspect.custom] () { | ||
return { | ||
...this, | ||
_trace: { | ||
...this._trace, | ||
started: '[Array]', | ||
finished: '[Array]' | ||
} | ||
} | ||
} | ||
toTraceId (get128bitId = false) { | ||
@@ -36,0 +48,0 @@ if (get128bitId) { |
@@ -17,2 +17,3 @@ 'use strict' | ||
const spanleak = require('../spanleak') | ||
const util = require('util') | ||
@@ -68,3 +69,3 @@ const tracerMetrics = telemetryMetrics.manager.namespace('tracers') | ||
this._prioritySampler = prioritySampler | ||
this._store = storage.getStore() | ||
this._store = storage.getHandle() | ||
this._duration = undefined | ||
@@ -110,2 +111,11 @@ | ||
[util.inspect.custom] () { | ||
return { | ||
...this, | ||
_parentTracer: `[${this._parentTracer.constructor.name}]`, | ||
_prioritySampler: `[${this._prioritySampler.constructor.name}]`, | ||
_processor: `[${this._processor.constructor.name}]` | ||
} | ||
} | ||
toString () { | ||
@@ -112,0 +122,0 @@ const spanContext = this.context() |
@@ -123,9 +123,11 @@ 'use strict' | ||
const context = this._getContext(span) | ||
const root = context._trace.started[0] | ||
if (!root) return // noop span | ||
context._sampling.priority = samplingPriority | ||
context._sampling.mechanism = mechanism | ||
const root = context._trace.started[0] | ||
log.trace(span, samplingPriority, mechanism) | ||
log.trace(span, samplingPriority, mechanism) | ||
this._addDecisionMaker(root) | ||
@@ -132,0 +134,0 @@ } |
@@ -20,3 +20,3 @@ 'use strict' | ||
const oldStore = storage.getStore() | ||
const newStore = span ? span._store : oldStore | ||
const newStore = span ? storage.getStore(span._store) : oldStore | ||
@@ -23,0 +23,0 @@ storage.enterWith({ ...newStore, span }) |
@@ -310,2 +310,4 @@ 'use strict' | ||
logger.trace(changes) | ||
const application = createAppObject(config) | ||
@@ -312,0 +314,0 @@ const host = createHostObject() |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
2344233
663
66917
15
116
207
5
+ Added@datadog/native-appsec@8.4.0(transitive)
- Removed@datadog/native-appsec@8.3.0(transitive)
Updated@datadog/native-appsec@8.4.0