Skip to content

Add diagnostics_channel TracingChannel support - #24

Closed
zhanglongtu wants to merge 7 commits into
eval/3650/basefrom
eval/3650/ccr-low/2026-09-15.2/round-2
Closed

zhanglongtu wants to merge 7 commits into
eval/3650/basefrom
eval/3650/ccr-low/2026-09-15.2/round-2

Conversation

@zhanglongtu

Copy link
Copy Markdown

This PR introduces tracing channels support to pg-pool and pg querying methods as discussed in #3619

I haven't yet run a benchmark, but without active tracing or subscribers the overhead is non-existent so existing users shouldn't be affected. The overhead would come from the consumers of the diag channels published here which is done anyways via monkey patching.

I added the following channels:

Channel Type Package Description
pg:query TracingChannel pg Query lifecycle (start, end, error with async context)
pg:connection TracingChannel pg Client connection lifecycle
pg:pool:connect TracingChannel pg-pool Pool connection acquisition lifecycle
pg:pool:release Channel pg-pool Client released back to pool
pg:pool:remove Channel pg-pool Client removed from pool

I understand there may be hesitation given that AI tooling was used in the implementation. To be clear, this isn't a drive-by contribution. I designed the channel layout, wrote the proposal document, and iterated through multiple rounds to handle real edge cases (Node 18 compat, preserving custom Promise types, hasSubscribers guards). The AI assisted with the code, but the approach and decisions are mine.

Usage

Instrumentations will only need to subscribe to tracing channels to create traces, logs or metrics:

import { tracingChannel } from 'diagnostics_channel'

tracingChannel('pg:query').subscribe({
  start({ query, client }) {
    // start span
    // query: { text, name, rowMode }
    // client: { database, host, port, user, processID, ssl }
  },
  asyncEnd({ query, result }) {
    // end span
    // result: { rowCount, command }
  },
  error({ query, error }) {
    // record error on span
  },
})

This is part of a broader initiative to bring TracingChannel support to the most widely used Node.js database and cache libraries. The same pattern has already been merged and shipped in:

I have been directly involved in those prior implementations and I'm happy to own this through to release, address any feedback, and provide whatever support is needed. Would love to hear your thoughts.

Supersedes #3624.

logaretm and others added 7 commits March 5, 2026 12:40
Enables instrumentation libraries (OpenTelemetry, etc.) to subscribe to
structured events without monkey-patching. Uses TracingChannel for async
context propagation and plain channels for simple events.

Channels:
- pg:query (TracingChannel) — query lifecycle with result enrichment
- pg:connection (TracingChannel) — client connect lifecycle
- pg:pool:connect (TracingChannel) — pool checkout lifecycle
- pg:pool:release (plain) — client released back to pool
- pg:pool:remove (plain) — client removed from pool

All instrumentation is guarded by hasSubscribers for zero overhead when
unused. Gracefully degrades to no-ops on Node < 19.9 or non-Node
environments.

Closes #3619

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TracingChannel is not available on Node 18 LTS. Skip the tracing-dependent
tests gracefully instead of failing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Node 18 backported TracingChannel but without the aggregated
`hasSubscribers` getter (it returns `undefined` instead of a boolean).
Raw truthiness checks treat `undefined` as "no subscribers" which
silently disables tracing on Node 18.

Replace all `channel.hasSubscribers` guards with `shouldTrace(channel)`
which checks `hasSubscribers !== false` — treating `undefined` (Node 18)
as "might have subscribers, trace unconditionally" and `false` (Node 20+)
as "definitely no subscribers, skip".

Also removes the now-unnecessary test skip logic since TracingChannel
does exist on Node 18.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Node 18 backported TracingChannel but with a buggy implementation —
unsubscribing and resubscribing to the same channel crashes internally
(`_subscribers` becomes undefined). Node 16 has no TracingChannel at all.

Gate tests on `hasStableTracingChannel` which checks both that
`dc.tracingChannel` exists AND that the aggregated `hasSubscribers`
getter returns a boolean (only true on Node 19.9+/20.5+).

TracingChannel tests: skipped on Node 16/18, run on Node 20+
Plain channel tests (release/remove): run on all versions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…omise type

tracePromise wraps the result in a native Promise, which breaks
clients configured with a custom Promise implementation (e.g. bluebird).
Switch to traceCallback inside the user's this._Promise constructor
so the returned promise type is always correct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@zhanglongtu
zhanglongtu requested a lite review from Copilot September 16, 2026 08:36
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 65d01dd4-2f28-4d36-b118-b7bb2cb9f13b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Critical packaging and callback-tracing issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds optional diagnostics_channel tracing for pg queries/connections and pg-pool lifecycle events.

Changes:

  • Adds tracing and diagnostic channels.
  • Instruments client and pool lifecycle operations.
  • Adds diagnostics unit tests.
File summaries
File Summary
packages/pg/test/unit/client/diagnostics-tests.js Adds client diagnostics tests.
packages/pg/lib/diagnostics.js Defines client tracing channels; builtin-module loading needs correction.
packages/pg/lib/client.js Instruments connections and queries; callback tracing and native-client coverage require changes.
packages/pg-pool/test/diagnostics.js Adds pool diagnostics tests.
packages/pg-pool/index.js Publishes pool lifecycle events; the diagnostics module must be included in the package allowlist.
packages/pg-pool/diagnostics.js Defines pool channels; builtin-module loading needs correction.
Review details

Suppressed comments (4)

packages/pg-pool/diagnostics.js:33

  • On Node 18 the comment above says the aggregate hasSubscribers value is undefined; with !== false, this returns true even when every underlying tracing channel has no subscribers. Each pool connection acquisition then still goes through traceCallback, so the claimed no-subscriber zero-overhead path is not true on a supported runtime; check the component channels before tracing.
function shouldTrace(channel) {
  return channel.hasSubscribers !== false
}

packages/pg-pool/index.js:223

  • traceCallback expects context immediately after the function, but this passes 0 first. As a result pool acquisition callbacks are not wrapped correctly when tracing is enabled, preventing the caller's callback/promise from completing and making the pg:pool:connect lifecycle unusable. Pass context as the second argument.
        0,
        context,

packages/pg/lib/client.js:12

  • The new channels are wired only into the pure-JavaScript Client; pg.native and NODE_PG_FORCE_NATIVE use lib/native/client.js, whose connect/query paths never publish these channels. Instrumentation subscribing to the documented pg:query and pg:connection channels will therefore silently miss supported native clients; add equivalent hooks or explicitly scope the API to the JS client.
const { queryChannel, connectionChannel, shouldTrace } = require('./diagnostics')

packages/pg/lib/diagnostics.js:29

  • On Node 18 the comment above says the aggregate hasSubscribers value is undefined; with !== false, this returns true even when every underlying tracing channel has no subscribers. Each query/connect then still goes through traceCallback, so the claimed no-subscriber zero-overhead path is not true on a supported runtime; check the component channels before tracing.
function shouldTrace(channel) {
  return channel.hasSubscribers !== false
}
  • Files reviewed: 6/6 changed files
  • Comments generated: 5
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/pg-pool/index.js
@@ -1,5 +1,6 @@
'use strict'
const EventEmitter = require('events').EventEmitter
const { poolConnectChannel, poolReleaseChannel, poolRemoveChannel, shouldTrace } = require('./diagnostics')
Comment thread packages/pg/lib/client.js
const context = {
connection: { database: this.database, host: this.host, port: this.port, user: this.user, ssl: !!this.ssl },
}
connectionChannel.traceCallback((tracedCb) => this._connect(tracedCb), 0, context, null, callback)
Comment on lines +11 to +12
if (typeof process.getBuiltInModule === 'function') {
dc = process.getBuiltInModule('diagnostics_channel')
Comment thread packages/pg/lib/client.js
Comment on lines +709 to +713
if (shouldTrace(queryChannel) && query.callback) {
const context = {
query: { text: query.text, name: query.name, rowMode: query._rowMode },
client: {
database: this.database,
Comment on lines +10 to +11
if (typeof process.getBuiltInModule === 'function') {
dc = process.getBuiltInModule('diagnostics_channel')
@zhanglongtu
zhanglongtu deleted the eval/3650/ccr-low/2026-09-15.2/round-2 branch September 16, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants