Skip to content

feat(logging): add hook-based log capture with HTTP forwarding#7674

Open
litianningdatadog wants to merge 2 commits intomasterfrom
tianning.li/log-capture-hook-approach
Open

feat(logging): add hook-based log capture with HTTP forwarding#7674
litianningdatadog wants to merge 2 commits intomasterfrom
tianning.li/log-capture-hook-approach

Conversation

@litianningdatadog
Copy link
Copy Markdown
Contributor

@litianningdatadog litianningdatadog commented Mar 4, 2026

Background:

https://datadoghq.atlassian.net/browse/SVLS-8572

What does this PR do?

Introduces a new log capture feature that forwards log records from Winston, Bunyan, and Pino to a configurable HTTP/HTTPS intake endpoint, without requiring per-instance transport injection.

How it works:

  • Winston and Bunyan: captured via the existing apm:<logger>:log diagnostic channels (already firing for trace injection) inside the generic LogPlugin base class
  • Pino: captured via a new apm:pino:json channel that publishes the complete serialized JSON line from asJsonSym for all Pino versions, bypassing the partial mixin data limitation of ≥5.14. This subscription lives in PinoPlugin (not LogPlugin) to keep the generic base free of pino-specific knowledge
  • A new log-capture/sender module manages a batched NDJSON buffer with a one-shot setTimeout flush (armed only when records are buffered) and configurable max buffer size and HTTP/HTTPS transport

Architecture:

  • LogPlugin._captureEnabled is a protected getter (returns !!config.logCaptureEnabled) that PinoPlugin overrides to return false, suppressing the generic capture path for pino while leaving trace injection intact
  • LogPlugin._configureSender(config) is a protected method that configures the shared sender; it is a no-op when logCaptureEnabled is false — the sender goes dormant naturally once no more records are added
  • PINO_JSON_CHANNEL is defined once in the pino instrumentation (the publisher) and imported by PinoPlugin (the subscriber)

Configuration (env / init options):

DD_LOG_CAPTURE_ENABLED / logCaptureEnabled       (default: true in Lambda Lite, false elsewhere)
DD_LOG_CAPTURE_HOST    / logCaptureHost           (default: localhost)
DD_LOG_CAPTURE_PORT    / logCapturePort           (default: 10517)
DD_LOG_CAPTURE_PATH    / logCapturePath           (default: /logs)
DD_LOG_CAPTURE_PROTOCOL / logCaptureProtocol      (default: http:)
DD_LOG_CAPTURE_MAX_BUFFER_SIZE / logCaptureMaxBufferSize (default: 1000)
DD_LOG_CAPTURE_FLUSH_INTERVAL_MS / logCaptureFlushIntervalMs (default: 5000)
DD_LOG_CAPTURE_TIMEOUT_MS / logCaptureTimeoutMs   (default: 5000)

Motivation

Alternative to the transport-injection approach (PR #7522). By hooking into channels that already fire on every log write, this avoids per-instance injection, WeakSet de-duplication, and the duplicate-injection issues observed with Winston's createLogger.

Additional Notes

Key design decisions:

  • logInjection and logCaptureEnabled are independent — enabling only capture does not inject dd into the actual log output, but dd trace context is always included in the captured JSON sent to the intake
  • Pino ≥5.14: mixinSym (used for trace injection) only provides partial mixin fields. A separate wrapAsJsonForCapture wrapper on asJsonSym captures the complete JSON line post-serialization and publishes to apm:pino:json
  • The sender uses a one-shot setTimeout (re-armed only when records are buffered) rather than setInterval, avoiding idle event-loop wakeups. There is no stop() — when capture is disabled, records simply stop being added and the sender goes dormant
  • flush is registered in beforeExitHandlers once when first configured and never removed, ensuring buffered records are flushed on process exit regardless of runtime config changes
  • NDJSON body trims trailing \n from each record before joining (Pino's asJson appends \n; naïve join would produce double blank lines)
  • HTTP response body is drained via res.resume() to release sockets back to the pool
  • All logCapture* config fields are always forwarded through plugin_manager._getSharedConfig() (no conditional guard)

Performance: Pino overhead is ~200–400 ns/write (no extra serialization). Winston/Bunyan overhead is ~3–25 µs/write dominated by JSON.stringify.

@litianningdatadog litianningdatadog requested review from a team as code owners March 4, 2026 20:59
@litianningdatadog litianningdatadog requested review from BridgeAR and removed request for a team March 4, 2026 20:59
@litianningdatadog litianningdatadog changed the title feat(logging): add hook-based log capture with HTTP forwarding feat(logging, ai): add hook-based log capture with HTTP forwarding Mar 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 4, 2026

Overall package size

Self size: 5.57 MB
Deduped: 6.42 MB
No deduping: 6.42 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | dc-polyfill | 0.1.10 | 26.73 kB | 26.73 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-datadog-prod-us1
Copy link
Copy Markdown

datadog-datadog-prod-us1 Bot commented Mar 4, 2026

Tests

Fix all issues with BitsAI or with Cursor

⚠️ Warnings

🧪 1 Test failed

pg instrumentation with pg >=8.0.3 (8.0.3) "before all" hook in "with pg >=8.0.3 (8.0.3)" from with pg >=8.0.3 (8.0.3)   View in Datadog   (Fix with Cursor)
Timeout of 5000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/runner/work/dd-trace-js/dd-trace-js/packages/datadog-instrumentations/test/pg.spec.js)

Error: Timeout of 5000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/runner/work/dd-trace-js/dd-trace-js/packages/datadog-instrumentations/test/pg.spec.js)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 83.61%
Overall Coverage: 68.18% (+0.10%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 08adc7e | Docs | Datadog PR Page | Give us feedback!

@litianningdatadog litianningdatadog marked this pull request as draft March 4, 2026 21:03
@pr-commenter
Copy link
Copy Markdown

pr-commenter Bot commented Mar 4, 2026

Benchmarks

Benchmark execution time: 2026-04-23 16:07:29

Comparing candidate commit 08adc7e in PR branch tianning.li/log-capture-hook-approach with baseline commit fb34ecc in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1345 metrics, 99 unstable metrics.

@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch from 1d185ce to 7a9d4e8 Compare March 4, 2026 21:29
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 4, 2026

Codecov Report

❌ Patch coverage is 87.06897% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.76%. Comparing base (8539f88) to head (f37288f).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
packages/datadog-plugin-pino/src/index.js 38.09% 13 Missing ⚠️
packages/dd-trace/src/log-capture/sender.js 95.34% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7674      +/-   ##
==========================================
+ Coverage   73.67%   73.76%   +0.09%     
==========================================
  Files         775      776       +1     
  Lines       36215    36326     +111     
==========================================
+ Hits        26680    26796     +116     
+ Misses       9535     9530       -5     
Flag Coverage Δ
aiguard-macos 36.50% <30.76%> (-0.14%) ⬇️
aiguard-ubuntu 36.61% <30.76%> (-0.14%) ⬇️
aiguard-windows 36.41% <30.76%> (-0.14%) ⬇️
apm-capabilities-tracing-macos 48.51% <81.00%> (+0.14%) ⬆️
apm-capabilities-tracing-ubuntu 48.55% <81.00%> (+0.11%) ⬆️
apm-capabilities-tracing-windows 48.34% <81.00%> (+0.18%) ⬆️
apm-integrations-child-process 36.18% <33.84%> (-0.09%) ⬇️
apm-integrations-couchbase-18 35.15% <33.84%> (-0.11%) ⬇️
apm-integrations-couchbase-eol 35.23% <33.84%> (-0.09%) ⬇️
apm-integrations-oracledb 35.19% <33.84%> (-0.11%) ⬇️
appsec-express 52.81% <33.84%> (-0.15%) ⬇️
appsec-fastify 49.23% <29.31%> (-0.22%) ⬇️
appsec-graphql 49.58% <29.31%> (-0.22%) ⬇️
appsec-kafka 42.12% <33.84%> (-0.14%) ⬇️
appsec-ldapjs 41.45% <33.84%> (-0.12%) ⬇️
appsec-lodash 41.48% <33.84%> (-0.12%) ⬇️
appsec-macos 56.72% <33.84%> (-0.17%) ⬇️
appsec-mongodb-core 45.77% <33.84%> (-0.14%) ⬇️
appsec-mongoose 46.65% <33.84%> (-0.14%) ⬇️
appsec-mysql 48.79% <33.84%> (-0.14%) ⬇️
appsec-node-serialize 40.65% <33.84%> (-0.12%) ⬇️
appsec-passport 44.62% <33.84%> (-0.14%) ⬇️
appsec-postgres 48.40% <33.84%> (-0.14%) ⬇️
appsec-sourcing 40.15% <33.84%> (-0.12%) ⬇️
appsec-stripe 42.36% <33.84%> (-0.13%) ⬇️
appsec-template 40.82% <33.84%> (-0.12%) ⬇️
appsec-ubuntu 56.80% <33.84%> (-0.17%) ⬇️
appsec-windows 56.59% <33.84%> (-0.19%) ⬇️
instrumentations-instrumentation-bluebird 29.86% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-body-parser 37.74% <33.84%> (-0.12%) ⬇️
instrumentations-instrumentation-child_process 35.53% <33.84%> (-0.12%) ⬇️
instrumentations-instrumentation-cookie-parser 31.79% <33.84%> (-0.09%) ⬇️
instrumentations-instrumentation-express 32.00% <33.84%> (-0.09%) ⬇️
instrumentations-instrumentation-express-mongo-sanitize 31.91% <33.84%> (-0.09%) ⬇️
instrumentations-instrumentation-express-session 37.37% <33.84%> (-0.12%) ⬇️
instrumentations-instrumentation-fs 29.53% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-generic-pool 30.92% <0.00%> (-0.01%) ⬇️
instrumentations-instrumentation-http 36.97% <33.84%> (-0.12%) ⬇️
instrumentations-instrumentation-knex 29.83% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-mongoose 30.95% <33.84%> (-0.08%) ⬇️
instrumentations-instrumentation-multer 37.51% <33.84%> (-0.12%) ⬇️
instrumentations-instrumentation-mysql2 35.49% <30.76%> (-0.13%) ⬇️
instrumentations-instrumentation-passport 41.23% <33.84%> (-0.13%) ⬇️
instrumentations-instrumentation-passport-http 40.93% <33.84%> (-0.13%) ⬇️
instrumentations-instrumentation-passport-local 41.42% <33.84%> (-0.13%) ⬇️
instrumentations-instrumentation-pg 35.01% <30.76%> (-0.13%) ⬇️
instrumentations-instrumentation-pino 30.35% <46.55%> (?)
instrumentations-instrumentation-promise 29.79% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-promise-js 29.80% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-q 29.83% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-url 29.79% <30.76%> (-0.10%) ⬇️
instrumentations-instrumentation-when 29.81% <30.76%> (-0.10%) ⬇️
llmobs-ai 38.45% <33.84%> (-0.12%) ⬇️
llmobs-anthropic 37.90% <33.84%> (-0.12%) ⬇️
llmobs-bedrock 37.16% <33.84%> (-0.11%) ⬇️
llmobs-google-genai 37.59% <33.84%> (-0.11%) ⬇️
llmobs-langchain 37.15% <33.84%> (+0.02%) ⬆️
llmobs-openai 41.25% <33.84%> (-0.13%) ⬇️
llmobs-vertex-ai 37.76% <33.84%> (-0.12%) ⬇️
platform-core 30.01% <ø> (ø)
platform-esbuild 32.83% <ø> (ø)
platform-instrumentations-misc 40.06% <0.00%> (-0.04%) ⬇️
platform-shimmer 35.73% <ø> (ø)
platform-unit-guardrails 31.38% <ø> (ø)
platform-webpack 20.73% <11.11%> (-0.05%) ⬇️
plugins-azure-durable-functions 25.21% <ø> (ø)
plugins-azure-event-hubs 25.36% <ø> (ø)
plugins-azure-service-bus 24.78% <ø> (ø)
plugins-bullmq 40.77% <33.84%> (-0.14%) ⬇️
plugins-cassandra 35.33% <33.84%> (-0.11%) ⬇️
plugins-cookie 26.33% <ø> (ø)
plugins-cookie-parser 26.14% <ø> (ø)
plugins-crypto 25.66% <ø> (ø)
plugins-dd-trace-api 35.47% <33.84%> (-0.12%) ⬇️
plugins-express-mongo-sanitize 26.28% <ø> (ø)
plugins-express-session 26.10% <ø> (ø)
plugins-fastify 39.35% <29.31%> (-0.19%) ⬇️
plugins-fetch 35.84% <33.84%> (-0.11%) ⬇️
plugins-fs 35.75% <33.84%> (-0.12%) ⬇️
plugins-generic-pool 25.25% <ø> (ø)
plugins-google-cloud-pubsub 43.07% <33.84%> (-0.14%) ⬇️
plugins-grpc 38.10% <33.84%> (-0.12%) ⬇️
plugins-handlebars 26.32% <ø> (ø)
plugins-hapi 37.47% <33.84%> (+0.01%) ⬆️
plugins-hono 37.58% <33.84%> (-0.12%) ⬇️
plugins-ioredis 35.79% <33.84%> (-0.12%) ⬇️
plugins-knex 26.01% <ø> (ø)
plugins-langgraph 35.14% <33.84%> (-0.11%) ⬇️
plugins-ldapjs 23.88% <ø> (ø)
plugins-light-my-request 25.75% <ø> (ø)
plugins-limitd-client 30.07% <30.76%> (-0.10%) ⬇️
plugins-lodash 25.33% <ø> (ø)
plugins-mariadb 36.70% <33.84%> (-0.08%) ⬇️
plugins-memcached 35.44% <33.84%> (-0.12%) ⬇️
plugins-microgateway-core 36.43% <33.84%> (-0.12%) ⬇️
plugins-moleculer 38.12% <33.84%> (-0.12%) ⬇️
plugins-mongodb 36.52% <33.84%> (-0.11%) ⬇️
plugins-mongodb-core 36.25% <33.84%> (-0.14%) ⬇️
plugins-mongoose 36.11% <33.84%> (-0.20%) ⬇️
plugins-multer 26.10% <ø> (ø)
plugins-mysql 36.52% <33.84%> (-0.12%) ⬇️
plugins-mysql2 36.50% <33.84%> (-0.12%) ⬇️
plugins-node-serialize 26.37% <ø> (ø)
plugins-opensearch 35.10% <33.84%> (-0.11%) ⬇️
plugins-passport-http 26.16% <ø> (ø)
plugins-postgres 34.51% <33.84%> (-0.08%) ⬇️
plugins-process 25.66% <ø> (ø)
plugins-pug 26.33% <ø> (ø)
plugins-redis 35.99% <33.84%> (-0.12%) ⬇️
plugins-router 39.98% <33.84%> (-0.13%) ⬇️
plugins-sequelize 25.03% <ø> (ø)
plugins-test-and-upstream-amqp10 35.76% <33.84%> (-0.12%) ⬇️
plugins-test-and-upstream-amqplib 40.92% <33.84%> (-0.14%) ⬇️
plugins-test-and-upstream-apollo 36.61% <33.84%> (-0.11%) ⬇️
plugins-test-and-upstream-avsc 35.61% <33.84%> (-0.12%) ⬇️
plugins-test-and-upstream-bunyan 31.27% <39.24%> (-0.06%) ⬇️
plugins-test-and-upstream-connect 37.93% <33.84%> (-0.12%) ⬇️
plugins-test-and-upstream-graphql 37.29% <33.84%> (-0.12%) ⬇️
plugins-test-and-upstream-koa 37.54% <33.84%> (-0.12%) ⬇️
plugins-test-and-upstream-protobufjs 35.82% <33.84%> (-0.12%) ⬇️
plugins-test-and-upstream-rhea 41.03% <33.84%> (-0.12%) ⬇️
plugins-undici 36.61% <33.84%> (-0.11%) ⬇️
plugins-url 25.66% <ø> (ø)
plugins-valkey 35.47% <33.84%> (+0.01%) ⬆️
plugins-vm 25.66% <ø> (ø)
plugins-winston 31.70% <39.24%> (-0.06%) ⬇️
plugins-ws 39.05% <33.84%> (-0.13%) ⬇️
profiling-macos 38.01% <33.84%> (-0.12%) ⬇️
profiling-ubuntu 38.17% <33.84%> (-0.13%) ⬇️
profiling-windows 39.52% <33.84%> (-0.13%) ⬇️
serverless-azure-functions-client 25.10% <ø> (ø)
serverless-azure-functions-eventhubs 25.10% <ø> (ø)
serverless-azure-functions-servicebus 25.10% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 3 times, most recently from f2cd92c to 2d4a829 Compare March 5, 2026 19:11
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 6 times, most recently from e039ca3 to 945de7f Compare March 12, 2026 20:49
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 3 times, most recently from aa04e8e to 7f7948e Compare March 24, 2026 15:07
@litianningdatadog litianningdatadog marked this pull request as ready for review March 24, 2026 16:29
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 3 times, most recently from ad7ba6c to 8ff09a9 Compare March 30, 2026 15:30
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 2 times, most recently from 9aa259f to 791d03b Compare April 6, 2026 20:40
Comment thread packages/datadog-instrumentations/src/pino.js Outdated
Comment thread docs/API.md Outdated
Comment thread packages/dd-trace/src/plugin_manager.js Outdated
Comment thread packages/dd-trace/src/plugins/plugin.js
Comment thread packages/dd-trace/src/plugins/log_plugin.js Outdated
Comment thread packages/dd-trace/src/log-capture/sender.js
Comment thread packages/dd-trace/src/plugins/log_plugin.js Outdated
Comment thread packages/dd-trace/src/plugins/log_plugin.js Outdated
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch from 791d03b to 23b81c2 Compare April 8, 2026 15:01
@litianningdatadog litianningdatadog changed the title feat(logging, ai): add hook-based log capture with HTTP forwarding feat(logging): add hook-based log capture with HTTP forwarding Apr 8, 2026
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 7 times, most recently from 640df93 to 039cfd0 Compare April 9, 2026 18:29
Copy link
Copy Markdown
Member

@rochdev rochdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last small thing and then I think this should be good to go! I would like to see an integration test for this as well with a mock mini agent, but that can be added as a follow up PR.

Comment thread packages/dd-trace/src/log-capture/sender.js Outdated
Comment thread packages/dd-trace/src/log-capture/sender.js Outdated
Comment thread packages/datadog-plugin-pino/src/index.js Outdated
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch from b923d1a to f34da68 Compare April 14, 2026 14:42
const { storage } = require('../../../datadog-core')

describe('Subscription', () => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is only needed because Subscription was used directly. Instead, this.addSub() should be used.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acked

Comment thread packages/dd-trace/src/plugins/plugin.js Outdated
}

module.exports = Plugin
module.exports.Subscription = Subscription
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be needed, all subscriptions should be done through addSub.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acked

try {
// Always include dd trace context in captured records even if logInjection is off.
const msg = this.config.logInjection ? arg.message : messageProxy(arg.message, holder)
require('../log-capture/sender').add(JSON.stringify(msg))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why require here instead of at the top of the file? This could be a hot path and it's better to avoid unnecessary abstractions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acked

Comment on lines +49 to +50
* Override to prevent the generic apm:${id}:log capture path from running for pino.
* Pino capture is handled via the apm:pino:json channel in #jsonCaptureSub.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about cases where json is not used at all? Do we just skip these logs entirely? If we do, then that implementation seems incomplete? And if we don't, then why even bother with log? We could just use json for everything at that point.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. apm:pino:json actually fires for all standard pino output, including pino-pretty, because pino always serializes internally via asJson before writing to any estination. So no logs are silently dropped. The reason we can't use apm:pino:log instead is that for pino ≥5.14 it fires from the mixin hook, which only carries partial data (the mixin fields, not the full log record). apm:pino:json fires from the asJson wrapper and always has the complete record, which is why we use it exclusively for capture.

if (!config.logCaptureEnabled) return

const captureSender = require('../log-capture/sender')
captureSender.configure({
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should happen outside of plugins. Right now the tracer gets these options, passes them to the plugins so that the plugins can then go back to the tracer to configure it. This not only requires unnecessary code but it also technically broken because it means 2 plugins could be configured differently and then the last one wins which is broken.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acked

@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch 4 times, most recently from 4cd1f62 to 4772168 Compare April 15, 2026 17:27
Captures JSON log records from Winston, Bunyan, and Pino via diagnostic
channels and forwards them as NDJSON to a configurable HTTP(S) intake
without requiring transports or stream shims in user code.

Architecture:
- LogPlugin base subscribes to apm:${id}:log for winston/bunyan capture
- PinoPlugin overrides _captureEnabled to suppress the generic path and
  instead subscribes to apm:pino:json for fully-serialized records
- Sender uses a one-shot setTimeout (armed only when records are buffered)
- PINO_JSON_CHANNEL is defined once in the instrumentation and imported
  by PinoPlugin to avoid duplication

Config options (all with DD_ env var equivalents):
- logCaptureEnabled (default: true in Lambda Lite, false elsewhere)
- logCaptureHost / logCapturePort (default: localhost:10517)
- logCapturePath / logCaptureProtocol / logCaptureFlushIntervalMs
- logCaptureMaxBufferSize / logCaptureTimeoutMs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@litianningdatadog litianningdatadog force-pushed the tianning.li/log-capture-hook-approach branch from 4772168 to f37288f Compare April 21, 2026 13:27
Resolves conflicts:
- .github/workflows/platform.yml: accept master's version (PR #8039 moved
  instrumentation jobs into .github/workflows/instrumentation.yml)
- .github/workflows/instrumentation.yml: re-add instrumentation-pino job
  at the new location
- regenerate packages/dd-trace/src/config/generated-config-types.d.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants