diff --git a/.github/workflows/apm-integrations.yml b/.github/workflows/apm-integrations.yml index ddc030076a7..3ccd9007692 100644 --- a/.github/workflows/apm-integrations.yml +++ b/.github/workflows/apm-integrations.yml @@ -307,7 +307,7 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: ./.github/actions/testagent/start - - uses: ./.github/actions/node/active-lts # TODO: change this to latest once we figure out the `fresh` bug + - uses: ./.github/actions/node/latest - uses: ./.github/actions/install - run: yarn test:plugins:ci diff --git a/.github/workflows/appsec.yml b/.github/workflows/appsec.yml index 7f3f46def9e..f8c43cad391 100644 --- a/.github/workflows/appsec.yml +++ b/.github/workflows/appsec.yml @@ -127,7 +127,7 @@ jobs: - uses: ./.github/actions/node/oldest-maintenance-lts - uses: ./.github/actions/install - run: yarn test:appsec:plugins:ci - - uses: ./.github/actions/node/active-lts # TODO: change this to latest once we figure out the `fresh` bug + - uses: ./.github/actions/node/latest - run: yarn test:appsec:plugins:ci - uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index 148d24bbe50..40c5d7dc55b 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -73,7 +73,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Check code meets quality and security standards id: datadog-static-analysis - uses: DataDog/datadog-static-analyzer-github-action@v1 + uses: DataDog/datadog-static-analyzer-github-action@2707598b1182dce1d1792186477b5b4132338e1c # v1.2.3 with: dd_api_key: ${{ secrets.DD_API_KEY }} dd_app_key: ${{ secrets.DD_APP_KEY }} diff --git a/package.json b/package.json index b51ff3e9545..a88bb651254 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dd-trace", - "version": "5.63.0", + "version": "5.63.1", "description": "Datadog APM tracing client for JavaScript", "main": "index.js", "typings": "index.d.ts", diff --git a/packages/datadog-instrumentations/src/moleculer/client.js b/packages/datadog-instrumentations/src/moleculer/client.js index 11c5a921f95..eb0c0d72fc8 100644 --- a/packages/datadog-instrumentations/src/moleculer/client.js +++ b/packages/datadog-instrumentations/src/moleculer/client.js @@ -21,19 +21,18 @@ function wrapCall (call) { ctx.promiseCtx = promise.ctx ctx.broker = broker - return promise + promise .then( result => { finishChannel.publish(ctx) - return result }, error => { ctx.error = error errorChannel.publish(ctx) finishChannel.publish(ctx) - throw error } ) + return promise }) } } diff --git a/packages/datadog-plugin-express/test/index.spec.js b/packages/datadog-plugin-express/test/index.spec.js index d50b7dfda4b..08ef867303d 100644 --- a/packages/datadog-plugin-express/test/index.spec.js +++ b/packages/datadog-plugin-express/test/index.spec.js @@ -1,5 +1,6 @@ 'use strict' +const { NODE_MAJOR } = require('../../../version') const { AsyncLocalStorage } = require('async_hooks') const axios = require('axios') const semver = require('semver') @@ -17,6 +18,12 @@ describe('Plugin', () => { describe('express', () => { withVersions('express', 'express', version => { + // Express.js 4.10.5 and below have a Node.js incompatibility in the `fresh` package RE res._headers missing + if (semver.intersects(version, '<=4.10.5') && NODE_MAJOR >= 24) { + describe.skip(`refusing to run tests as express@${version} is incompatible with Node.js ${NODE_MAJOR}`) + return + } + beforeEach(() => { tracer = require('../../dd-trace') }) diff --git a/packages/datadog-plugin-moleculer/test/index.spec.js b/packages/datadog-plugin-moleculer/test/index.spec.js index 67e267d4952..197f2c17df2 100644 --- a/packages/datadog-plugin-moleculer/test/index.spec.js +++ b/packages/datadog-plugin-moleculer/test/index.spec.js @@ -1,11 +1,13 @@ 'use strict' const { expect } = require('chai') +const assert = require('node:assert') const getPort = require('get-port') const os = require('node:os') const { withNamingSchema, withPeerService, withVersions } = require('../../dd-trace/test/setup/mocha') const agent = require('../../dd-trace/test/plugins/agent') const { expectedSchema, rawExpectedSchema } = require('./naming') +const { assertObjectContains } = require('../../../integration-tests/helpers') const sort = trace => trace.sort((a, b) => Number(a.start - b.start)) @@ -30,10 +32,10 @@ describe('Plugin', () => { broker.createService({ name: 'math', actions: { - add (ctx) { + async add (ctx) { const numerify = this.actions.numerify - return numerify(ctx.params.a) + numerify(ctx.params.b) + return await numerify(ctx.params.a) + await numerify(ctx.params.b) }, numerify (ctx) { @@ -42,6 +44,15 @@ describe('Plugin', () => { } }) + broker.createService({ + name: 'error', + actions: { + async error (ctx) { + throw new Error('Invalid number') + } + } + }) + return broker.start() } @@ -159,25 +170,61 @@ describe('Plugin', () => { 'out.host' ) - it('should do automatic instrumentation', done => { + it('should do automatic instrumentation', async () => { + const result = await broker.call('math.add', { a: 5, b: 3 }) + assert.strictEqual(result, 8) + agent.assertSomeTraces(traces => { - const spans = sort(traces[0]) + const span = traces[0][0] + + assertObjectContains(span, { + name: expectedSchema.client.opName, + service: expectedSchema.client.serviceName, + resource: 'math.add', + meta: { + 'span.kind': 'client', + 'out.host': hostname, + 'moleculer.context.action': 'math.add', + 'moleculer.context.node_id': `server-${process.pid}`, + 'moleculer.context.service': 'math', + 'moleculer.namespace': 'multi', + 'moleculer.node_id': `server-${process.pid}`, + }, + metrics: { + 'network.destination.port': port + } + }) + + assert.strictEqual(typeof span.meta['moleculer.context.request_id'], 'string') + }) + }) - expect(spans[0]).to.have.property('name', expectedSchema.client.opName) - expect(spans[0]).to.have.property('service', expectedSchema.client.serviceName) - expect(spans[0]).to.have.property('resource', 'math.add') - expect(spans[0].meta).to.have.property('span.kind', 'client') - expect(spans[0].meta).to.have.property('out.host', hostname) - expect(spans[0].meta).to.have.property('moleculer.context.action', 'math.add') - expect(spans[0].meta).to.have.property('moleculer.context.node_id', `server-${process.pid}`) - expect(spans[0].meta).to.have.property('moleculer.context.request_id') - expect(spans[0].meta).to.have.property('moleculer.context.service', 'math') - expect(spans[0].meta).to.have.property('moleculer.namespace', 'multi') - expect(spans[0].meta).to.have.property('moleculer.node_id', `server-${process.pid}`) - expect(spans[0].metrics).to.have.property('network.destination.port', port) - }).then(done, done) + it('should handle error cases', async () => { + await assert.rejects(broker.call('error.error'), { message: 'Invalid number' }) - broker.call('math.add', { a: 5, b: 3 }).catch(done) + agent.assertSomeTraces(traces => { + const span = traces[0][0] + + assertObjectContains(span, { + name: expectedSchema.client.opName, + service: expectedSchema.client.serviceName, + resource: 'error.error', + meta: { + 'span.kind': 'client', + 'out.host': hostname, + 'moleculer.context.action': 'error.error', + 'moleculer.context.node_id': `server-${process.pid}`, + 'moleculer.context.service': 'error', + 'moleculer.namespace': 'multi', + 'moleculer.node_id': `server-${process.pid}`, + }, + metrics: { + 'network.destination.port': port + } + }) + + assert.strictEqual(typeof span.meta['moleculer.context.request_id'], 'string') + }) }) withNamingSchema( @@ -331,6 +378,47 @@ describe('Plugin', () => { expect(spanId.toString()).to.equal(parentId.toString()) }) }) + describe('meta propagation', () => { + before(() => agent.load('moleculer', { + meta: true + })) + + before(async () => { + const { ServiceBroker } = require(`../../../versions/moleculer@${version}`).get() + broker = new ServiceBroker({ + nodeID: `server-${process.pid}`, + logger: false + }) + + broker.createService({ + name: 'test', + actions: { + async first (ctx) { + await ctx.call('test.second', null, { + meta: { + a: 'John' + } + }) + return ctx.meta.a + }, + second (ctx) { + ctx.meta.a = 'Doe' + } + } + }) + + return broker.start() + }) + + after(() => broker.stop()) + + after(() => agent.close({ ritmReset: false })) + + it('should propagate meta from child to parent', async () => { + const result = await broker.call('test.first') + assert.strictEqual(result, 'Doe') + }) + }) }) }) }) diff --git a/packages/dd-trace/src/llmobs/writers/base.js b/packages/dd-trace/src/llmobs/writers/base.js index 8895bd81130..8f4e84b6e61 100644 --- a/packages/dd-trace/src/llmobs/writers/base.js +++ b/packages/dd-trace/src/llmobs/writers/base.js @@ -120,7 +120,11 @@ class BaseLLMObsWriter { } const { hostname, port } = this._config - const base = this._config.url || new URL(format({ + + const overrideOriginEnv = getEnvironmentVariable('_DD_LLMOBS_OVERRIDE_ORIGIN') + const overrideOriginUrl = overrideOriginEnv && new URL(overrideOriginEnv) + + const base = overrideOriginUrl ?? this._config.url ?? new URL(format({ protocol: 'http:', hostname, port diff --git a/packages/dd-trace/src/opentracing/propagation/text_map.js b/packages/dd-trace/src/opentracing/propagation/text_map.js index 06a56371997..3d7668dfcd3 100644 --- a/packages/dd-trace/src/opentracing/propagation/text_map.js +++ b/packages/dd-trace/src/opentracing/propagation/text_map.js @@ -148,13 +148,13 @@ class TextMapPropagator { // Check for item count limit exceeded if (itemCounter > this._config.baggageMaxItems) { - tracerMetrics.count('context_header_style.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc() + tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc() break } // Check for byte count limit exceeded if (byteCounter > this._config.baggageMaxBytes) { - tracerMetrics.count('context_header_style.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc() + tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc() break } diff --git a/packages/dd-trace/src/supported-configurations.json b/packages/dd-trace/src/supported-configurations.json index e9ba71e91ce..9a43e8fb436 100644 --- a/packages/dd-trace/src/supported-configurations.json +++ b/packages/dd-trace/src/supported-configurations.json @@ -118,6 +118,7 @@ "DD_PLAYWRIGHT_WORKER": ["A"], "DD_PROFILING_CODEHOTSPOTS_ENABLED": ["A"], "DD_PROFILING_CPU_ENABLED": ["A"], + "DD_PROFILING_DEBUG_SOURCE_MAPS": ["A"], "DD_PROFILING_DEBUG_UPLOAD_COMPRESSION": ["A"], "DD_PROFILING_ENABLED": ["A"], "DD_PROFILING_ENDPOINT_COLLECTION_ENABLED": ["A"], @@ -127,10 +128,13 @@ "DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED": ["A"], "DD_PROFILING_EXPORTERS": ["A"], "DD_PROFILING_HEAP_ENABLED": ["A"], + "DD_PROFILING_HEAP_SAMPLING_INTERVAL": ["A"], + "DD_PROFILING_PPROF_PREFIX": ["A"], "DD_PROFILING_PROFILERS": ["A"], "DD_PROFILING_SOURCE_MAP": ["A"], "DD_PROFILING_TIMELINE_ENABLED": ["A"], "DD_PROFILING_UPLOAD_PERIOD": ["A"], + "DD_PROFILING_UPLOAD_TIMEOUT": ["A"], "DD_PROFILING_V8_PROFILER_BUG_WORKAROUND": ["A"], "DD_PROFILING_WALLTIME_ENABLED": ["A"], "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": ["A"], diff --git a/packages/dd-trace/test/appsec/iast/analyzers/code-injection-analyzer.express.plugin.spec.js b/packages/dd-trace/test/appsec/iast/analyzers/code-injection-analyzer.express.plugin.spec.js index d700042e245..7fc736bb286 100644 --- a/packages/dd-trace/test/appsec/iast/analyzers/code-injection-analyzer.express.plugin.spec.js +++ b/packages/dd-trace/test/appsec/iast/analyzers/code-injection-analyzer.express.plugin.spec.js @@ -1,5 +1,7 @@ 'use strict' +const { NODE_MAJOR } = require('../../../../../../version') +const semver = require('semver') const { prepareTestServerForIastInExpress } = require('../utils') const axios = require('axios') const path = require('path') @@ -14,6 +16,11 @@ const { withVersions } = require('../../../setup/mocha') describe('Code injection vulnerability', () => { withVersions('express', 'express', version => { + if (semver.intersects(version, '<=4.10.5') && NODE_MAJOR >= 24) { + describe.skip(`refusing to run tests as express@${version} is incompatible with Node.js ${NODE_MAJOR}`) + return + } + describe('Eval', () => { let i = 0 let evalFunctionsPath diff --git a/packages/dd-trace/test/appsec/iast/taint-tracking/sources/taint-tracking.express.plugin.spec.js b/packages/dd-trace/test/appsec/iast/taint-tracking/sources/taint-tracking.express.plugin.spec.js index e53231d6469..b00bdaa9ef2 100644 --- a/packages/dd-trace/test/appsec/iast/taint-tracking/sources/taint-tracking.express.plugin.spec.js +++ b/packages/dd-trace/test/appsec/iast/taint-tracking/sources/taint-tracking.express.plugin.spec.js @@ -1,5 +1,6 @@ 'use strict' +const { NODE_MAJOR } = require('../../../../../../../version') const axios = require('axios') const semver = require('semver') const agent = require('../../../../plugins/agent') @@ -19,6 +20,11 @@ describe('URI sourcing with express', () => { let appListener withVersions('express', 'express', version => { + if (semver.intersects(version, '<=4.10.5') && NODE_MAJOR >= 24) { + describe.skip(`refusing to run tests as express@${version} is incompatible with Node.js ${NODE_MAJOR}`) + return + } + before(() => { return agent.load(['http', 'express'], { client: false }) }) @@ -78,6 +84,11 @@ describe('Path params sourcing with express', () => { let appListener withVersions('express', 'express', version => { + if (semver.intersects(version, '<=4.10.5') && NODE_MAJOR >= 24) { + describe.skip(`refusing to run tests as express@${version} is incompatible with Node.js ${NODE_MAJOR}`) + return + } + const checkParamIsTaintedAndNext = (req, res, next, param, name) => { const store = storage('legacy').getStore() const iastContext = iastContextFunctions.getIastContext(store) diff --git a/packages/dd-trace/test/appsec/index.express.plugin.spec.js b/packages/dd-trace/test/appsec/index.express.plugin.spec.js index 335f5b95114..a851709d564 100644 --- a/packages/dd-trace/test/appsec/index.express.plugin.spec.js +++ b/packages/dd-trace/test/appsec/index.express.plugin.spec.js @@ -1,5 +1,7 @@ 'use strict' +const { NODE_MAJOR } = require('../../../../version') +const semver = require('semver') const Axios = require('axios') const { assert } = require('chai') const path = require('path') @@ -11,6 +13,11 @@ const { json } = require('../../src/appsec/blocked_templates') const { withVersions } = require('../setup/mocha') withVersions('express', 'express', version => { + if (semver.intersects(version, '<=4.10.5') && NODE_MAJOR >= 24) { + describe.skip(`refusing to run tests as express@${version} is incompatible with Node.js ${NODE_MAJOR}`) + return + } + describe('Suspicious request blocking - path parameters', () => { let server, paramCallbackSpy, axios diff --git a/packages/dd-trace/test/appsec/rasp/lfi.express.plugin.spec.js b/packages/dd-trace/test/appsec/rasp/lfi.express.plugin.spec.js index 5309e37eeff..a65d6c8bcc7 100644 --- a/packages/dd-trace/test/appsec/rasp/lfi.express.plugin.spec.js +++ b/packages/dd-trace/test/appsec/rasp/lfi.express.plugin.spec.js @@ -1,5 +1,7 @@ 'use strict' +const { NODE_MAJOR } = require('../../../../../version') +const semver = require('semver') const Axios = require('axios') const os = require('os') const fs = require('fs') @@ -31,6 +33,11 @@ describe('RASP - lfi', () => { } withVersions('express', 'express', expressVersion => { + if (semver.intersects(expressVersion, '<=4.10.5') && NODE_MAJOR >= 24) { + describe.skip(`refusing to run tests as express@${expressVersion} is incompatible with Node.js ${NODE_MAJOR}`) + return + } + withVersions('express', 'ejs', ejsVersion => { let app, server diff --git a/packages/dd-trace/test/llmobs/writers/base.spec.js b/packages/dd-trace/test/llmobs/writers/base.spec.js index 624eedeab0a..cf8d9a10e32 100644 --- a/packages/dd-trace/test/llmobs/writers/base.spec.js +++ b/packages/dd-trace/test/llmobs/writers/base.spec.js @@ -1,6 +1,7 @@ 'use strict' const { expect } = require('chai') const proxyquire = require('proxyquire') +const { useEnv } = require('../../../../../integration-tests/helpers') describe('BaseLLMObsWriter', () => { let BaseLLMObsWriter @@ -60,6 +61,19 @@ describe('BaseLLMObsWriter', () => { expect(writer.url).to.equal('http://localhost:8126/evp_proxy/v2/endpoint') }) + describe('with override origin', () => { + useEnv({ + _DD_LLMOBS_OVERRIDE_ORIGIN: 'http://override-origin:12345' + }) + + it('constructs a writer with the correct url', () => { + writer = new BaseLLMObsWriter(options) + writer.setAgentless(false) + + expect(writer.url).to.equal('http://override-origin:12345/evp_proxy/v2/endpoint') + }) + }) + describe('with config url', () => { beforeEach(() => { options.config.url = new URL('http://test-agent:12345') diff --git a/packages/dd-trace/test/opentracing/propagation/text_map.spec.js b/packages/dd-trace/test/opentracing/propagation/text_map.spec.js index 52157fef95c..ad39f9435aa 100644 --- a/packages/dd-trace/test/opentracing/propagation/text_map.spec.js +++ b/packages/dd-trace/test/opentracing/propagation/text_map.spec.js @@ -23,6 +23,7 @@ describe('TextMapPropagator', () => { let baggageItems let config let log + let telemetryMetrics const createContext = (params = {}) => { const trace = { started: [], finished: [], tags: {} } @@ -45,8 +46,18 @@ describe('TextMapPropagator', () => { log = { debug: sinon.spy() } + telemetryMetrics = { + manager: { + namespace: sinon.stub().returns({ + count: sinon.stub().returns({ + inc: sinon.spy() + }) + }) + } + } TextMapPropagator = proxyquire('../src/opentracing/propagation/text_map', { - '../../log': log + '../../log': log, + '../../telemetry/metrics': telemetryMetrics }) config = new Config({ tagsHeaderMaxLength: 512 }) propagator = new TextMapPropagator(config) @@ -388,6 +399,68 @@ describe('TextMapPropagator', () => { injectCh.unsubscribe(onSpanInject) } }) + + describe('baggage telemetry metrics', () => { + let tracerMetrics + + beforeEach(() => { + // Get the mocked tracer metrics instance + tracerMetrics = telemetryMetrics.manager.namespace('tracers') + }) + + it('should track baggage injection metric when baggage is successfully injected', () => { + const carrier = {} + setBaggageItem('test-key', 'test-value') + + propagator.inject(undefined, carrier) + + expect(tracerMetrics.count).to.have.been.calledWith('context_header_style.injected', ['header_style:baggage']) + expect(tracerMetrics.count().inc).to.have.been.called + expect(carrier.baggage).to.equal('test-key=test-value') + }) + + it('should track truncation metric when baggage item count exceeds limit', () => { + const carrier = {} + const originalMaxItems = config.baggageMaxItems + config.baggageMaxItems = 2 + + // Add 3 items to exceed the limit + setBaggageItem('key1', 'value1') + setBaggageItem('key2', 'value2') + setBaggageItem('key3', 'value3') + + propagator.inject(undefined, carrier) + + expect(tracerMetrics.count).to.have.been.calledWith( + 'context_header.truncated', + ['truncation_reason:baggage_item_count_exceeded'] + ) + expect(tracerMetrics.count().inc).to.have.been.called + + // Restore original config + config.baggageMaxItems = originalMaxItems + }) + + it('should track truncation metric when baggage byte count exceeds limit', () => { + const carrier = {} + const originalMaxBytes = config.baggageMaxBytes + config.baggageMaxBytes = 50 + + // Add a large value to exceed byte limit + setBaggageItem('small-key', 'a'.repeat(100)) + + propagator.inject(undefined, carrier) + + expect(tracerMetrics.count).to.have.been.calledWith( + 'context_header.truncated', + ['truncation_reason:baggage_byte_count_exceeded'] + ) + expect(tracerMetrics.count().inc).to.have.been.called + + // Restore original config + config.baggageMaxBytes = originalMaxBytes + }) + }) }) describe('extract', () => { @@ -855,6 +928,45 @@ describe('TextMapPropagator', () => { } }) + describe('baggage telemetry metrics', () => { + let tracerMetrics + + beforeEach(() => { + // Get the mocked tracer metrics instance + tracerMetrics = telemetryMetrics.manager.namespace('tracers') + // Reset baggage between tests + removeAllBaggageItems() + }) + + it('should track baggage extraction metric when baggage is successfully extracted', () => { + const carrier = { + 'x-datadog-trace-id': '123', + 'x-datadog-parent-id': '456', + baggage: 'test-key=test-value' + } + + propagator.extract(carrier) + + expect(tracerMetrics.count).to.have.been.calledWith('context_header_style.extracted', ['header_style:baggage']) + expect(tracerMetrics.count().inc).to.have.been.called + expect(getBaggageItem('test-key')).to.equal('test-value') + }) + + it('should track malformed metric when baggage has empty key', () => { + const carrier = { + 'x-datadog-trace-id': '123', + 'x-datadog-parent-id': '456', + baggage: '=value-without-key' + } + + propagator.extract(carrier) + + expect(tracerMetrics.count).to.have.been.calledWith('context_header_style.malformed', ['header_style:baggage']) + expect(tracerMetrics.count().inc).to.have.been.called + expect(getAllBaggageItems()).to.deep.equal({}) + }) + }) + it('should create span links when traces have inconsistent traceids', () => { // Add a traceparent header and it will prioritize it const traceId = '1111aaaa2222bbbb3333cccc4444dddd' diff --git a/packages/dd-trace/test/plugins/versions/package.json b/packages/dd-trace/test/plugins/versions/package.json index 8fbcb7373bd..4e03b9131b7 100644 --- a/packages/dd-trace/test/plugins/versions/package.json +++ b/packages/dd-trace/test/plugins/versions/package.json @@ -4,12 +4,12 @@ "license": "BSD-3-Clause", "private": true, "dependencies": { - "@ai-sdk/openai": "2.0.1", + "@ai-sdk/openai": "2.0.15", "@apollo/gateway": "2.11.2", "@apollo/server": "5.0.0", "@apollo/subgraph": "2.11.2", "@aws-sdk/client-bedrock-runtime": "3.864.0", - "@aws-sdk/client-dynamodb": "3.864.0", + "@aws-sdk/client-dynamodb": "3.868.0", "@aws-sdk/client-kinesis": "3.864.0", "@aws-sdk/client-lambda": "3.865.0", "@aws-sdk/client-s3": "3.864.0", @@ -33,7 +33,7 @@ "@grpc/proto-loader": "0.8.0", "@hapi/boom": "10.0.1", "@hapi/hapi": "21.4.3", - "@hono/node-server": "1.18.2", + "@hono/node-server": "1.19.0", "@jest/core": "30.0.5", "@jest/globals": "30.0.5", "@jest/reporters": "30.0.5", @@ -42,7 +42,7 @@ "@koa/router": "14.0.0", "@langchain/anthropic": "0.3.26", "@langchain/cohere": "0.3.4", - "@langchain/core": "0.3.70", + "@langchain/core": "0.3.71", "@langchain/google-genai": "0.2.16", "@langchain/openai": "0.6.7", "@node-redis/client": "1.0.6", @@ -60,7 +60,7 @@ "@vitest/coverage-v8": "3.2.4", "@vitest/runner": "3.2.4", "aerospike": "6.3.0", - "ai": "5.0.2", + "ai": "5.0.15", "amqp10": "3.6.0", "amqplib": "0.10.8", "apollo-server-core": "3.13.0", @@ -99,7 +99,7 @@ "graphql-yoga": "5.15.1", "handlebars": "4.7.8", "hapi": "18.1.0", - "hono": "4.9.1", + "hono": "4.9.2", "ioredis": "5.7.0", "iovalkey": "0.3.3", "jest": "30.0.5", @@ -159,7 +159,7 @@ "pnpm": "10.14.0", "promise": "8.3.0", "promise-js": "0.0.7", - "protobufjs": "7.5.3", + "protobufjs": "7.5.4", "pug": "3.0.3", "q": "2.0.3", "react": "19.1.1", @@ -176,13 +176,13 @@ "sqlite3": "5.1.7", "tedious": "19.0.0", "typescript": "5.9.2", - "undici": "7.13.0", + "undici": "7.14.0", "vitest": "3.2.4", "when": "3.7.8", "winston": "3.17.0", "workerpool": "9.3.3", "ws": "8.18.3", "yarn": "1.22.22", - "zod": "4.0.14" + "zod": "4.0.17" } } diff --git a/packages/dd-trace/test/profiling/config.spec.js b/packages/dd-trace/test/profiling/config.spec.js index ba1a48f1b8f..25f6cdc42bb 100644 --- a/packages/dd-trace/test/profiling/config.spec.js +++ b/packages/dd-trace/test/profiling/config.spec.js @@ -176,6 +176,30 @@ describe('config', () => { expect(config.profilers[0]).to.be.an.instanceOf(SpaceProfiler) }) + it('should be able to read some env vars', () => { + const oldenv = process.env + process.env = { + DD_PROFILING_DEBUG_SOURCE_MAPS: '1', + DD_PROFILING_HEAP_SAMPLING_INTERVAL: '1000', + DD_PROFILING_PPROF_PREFIX: 'test-prefix', + DD_PROFILING_UPLOAD_TIMEOUT: '10000', + DD_PROFILING_TIMELINE_ENABLED: '0' + } + + const options = { + logger: nullLogger + } + + const config = new Config(options) + expect(config.debugSourceMaps).to.be.true + expect(config.heapSamplingInterval).to.equal(1000) + expect(config.pprofPrefix).to.equal('test-prefix') + expect(config.uploadTimeout).to.equal(10000) + expect(config.timelineEnabled).to.be.false + + process.env = oldenv + }) + it('should deduplicate profilers', () => { process.env = { DD_PROFILING_PROFILERS: 'wall,wall', diff --git a/yarn.lock b/yarn.lock index 82483ccdf23..7c08d8e19e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -117,9 +117,9 @@ integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== "@babel/helpers@^7.27.6": - version "7.28.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.2.tgz#80f0918fecbfebea9af856c419763230040ee850" - integrity sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw== + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.3.tgz#b83156c0a2232c133d1b535dd5d3452119c7e441" + integrity sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw== dependencies: "@babel/template" "^7.27.2" "@babel/types" "^7.28.2" @@ -819,9 +819,9 @@ undici-types "~6.20.0" "@types/node@^18.19.106": - version "18.19.122" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.122.tgz#e7358f8df7cc3f14e860198e1ca4dc2ed9a7de06" - integrity sha512-yzegtT82dwTNEe/9y+CM8cgb42WrUfMMCg2QqSddzO1J6uPmBD7qKCZ7dOHZP2Yrpm/kb0eqdNMn2MUyEiqBmA== + version "18.19.123" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.123.tgz#08a3e4f5e0c73b8840c677b7635ce59d5dc1f76d" + integrity sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg== dependencies: undici-types "~5.26.4" @@ -1870,9 +1870,9 @@ eslint-module-utils@^2.12.1: debug "^3.2.7" eslint-plugin-cypress@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-5.1.0.tgz#348c63f2afb2b336ab2063bf27347c1219be64b6" - integrity sha512-tdLXm4aq9vX2hTtKJTUFD3gdNseMKqsf8+P6hI4TtOPdz1LU4xvTpQBd1++qPAsPZP2lyYh71B5mvzu2lBr4Ow== + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-5.1.1.tgz#186dd252b4520ce81f59a7d7213050e5f748fa9f" + integrity sha512-LxTmZf1LLh9EklZBVvKNEZj71X9tCJnlYDviAJGsOgEVc6jz+tBODSpm02CS/9eJOfRqGsmVyvIw7LHXQ13RaA== dependencies: globals "^16.2.0" @@ -3823,9 +3823,9 @@ propagate@^2.0.0: integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== protobufjs@^7.5.3: - version "7.5.3" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.3.tgz#13f95a9e3c84669995ec3652db2ac2fb00b89363" - integrity sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw== + version "7.5.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" + integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -4350,9 +4350,9 @@ source-map@^0.6.0, source-map@^0.6.1: integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== spawn-wrap@^2.0.0: version "2.0.0"