Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#2191): Add support for NODE_DEBUG #2585

Merged
merged 11 commits into from
Jan 7, 2024
19 changes: 4 additions & 15 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const net = require('net')
const http = require('http')
const { pipeline } = require('stream')
const util = require('./core/util')
const { channels } = require('./core/diagnostics')
const timers = require('./timers')
const Request = require('./core/request')
const DispatcherBase = require('./dispatcher-base')
Expand Down Expand Up @@ -108,21 +109,6 @@ const FastBuffer = Buffer[Symbol.species]

const kClosedResolve = Symbol('kClosedResolve')

const channels = {}

try {
const diagnosticsChannel = require('diagnostics_channel')
channels.sendHeaders = diagnosticsChannel.channel('undici:client:sendHeaders')
channels.beforeConnect = diagnosticsChannel.channel('undici:client:beforeConnect')
channels.connectError = diagnosticsChannel.channel('undici:client:connectError')
channels.connected = diagnosticsChannel.channel('undici:client:connected')
} catch {
channels.sendHeaders = { hasSubscribers: false }
channels.beforeConnect = { hasSubscribers: false }
channels.connectError = { hasSubscribers: false }
channels.connected = { hasSubscribers: false }
}

/**
* @type {import('../types/client').default}
*/
Expand Down Expand Up @@ -1191,6 +1177,7 @@ async function connect (client) {
hostname,
protocol,
port,
version: client[kHTTPConnVersion],
servername: client[kServerName],
localAddress: client[kLocalAddress]
},
Expand Down Expand Up @@ -1284,6 +1271,7 @@ async function connect (client) {
hostname,
protocol,
port,
version: client[kHTTPConnVersion],
servername: client[kServerName],
localAddress: client[kLocalAddress]
},
Expand All @@ -1306,6 +1294,7 @@ async function connect (client) {
hostname,
protocol,
port,
version: client[kHTTPConnVersion],
servername: client[kServerName],
localAddress: client[kLocalAddress]
},
Expand Down
186 changes: 186 additions & 0 deletions lib/core/diagnostics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
const diagnosticsChannel = require('diagnostics_channel')
metcoder95 marked this conversation as resolved.
Show resolved Hide resolved

let isClientSet = false
const channels = {
// Client
beforeConnect: diagnosticsChannel.channel('undici:client:beforeConnect'),
connected: diagnosticsChannel.channel('undici:client:connected'),
connectError: diagnosticsChannel.channel('undici:client:connectError'),
sendHeaders: diagnosticsChannel.channel('undici:client:sendHeaders'),
// Request
create: diagnosticsChannel.channel('undici:request:create'),
bodySent: diagnosticsChannel.channel('undici:request:bodySent'),
headers: diagnosticsChannel.channel('undici:request:headers'),
trailers: diagnosticsChannel.channel('undici:request:trailers'),
error: diagnosticsChannel.channel('undici:request:error'),
// WebSocket
open: diagnosticsChannel.channel('undici:websocket:open'),
close: diagnosticsChannel.channel('undici:websocket:close'),
socketError: diagnosticsChannel.channel('undici:websocket:socket_error'),
ping: diagnosticsChannel.channel('undici:websocket:ping'),
pong: diagnosticsChannel.channel('undici:websocket:pong')
}

if (process.env.NODE_DEBUG?.match(/(fetch|undici)/) != null) {
// Track all Client events
diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(evt => {
const {
connectParams: { version, protocol, port, host }
} = evt
console.log(
metcoder95 marked this conversation as resolved.
Show resolved Hide resolved
`HTTP:undici ${process.pid}: connecting to ${host}${
port ? `:${port}` : ''
} using ${protocol}${version}`
)
})

diagnosticsChannel.channel('undici:client:connected').subscribe(evt => {
const {
connectParams: { version, protocol, port, host }
} = evt
console.log(
`HTTP:undici ${process.pid}: connected to ${host}${
port ? `:${port}` : ''
} using ${protocol}${version}`
)
})

diagnosticsChannel.channel('undici:client:connectError').subscribe(evt => {
const {
connectParams: { version, protocol, port, host },
error
} = evt
console.log(
`HTTP:undici ${process.pid}: connection to ${host}${
port ? `:${port}` : ''
} using ${protocol}${version} errored - ${error.message}`
)
})

diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(evt => {
const {
request: { method, path, origin }
} = evt
console.log(
`HTTP:undici ${process.pid}: sending request to ${method} ${origin}/${path}`
)
})

// Track Request events
diagnosticsChannel.channel('undici:request:headers').subscribe(evt => {
const {
request: { method, path, origin },
response: { statusCode }
} = evt
console.log(
`HTTP:undici ${process.pid}: received response ${method} ${origin}/${path} - HTTP ${statusCode}`
)
})

diagnosticsChannel.channel('undici:request:trailers').subscribe(evt => {
const {
request: { method, path, origin }
} = evt
console.log(
`HTTP:undici ${process.pid}: trailers received from ${method} ${origin}/${path}`
)
})

diagnosticsChannel.channel('undici:request:error').subscribe(evt => {
const {
request: { method, path, origin },
error
} = evt
console.log(
`HTTP:undici ${process.pid}: request errored ${method} ${origin}/${path} - ${error.message}`
)
})

isClientSet = true
}

if (process.env.NODE_DEBUG?.match(/websocket/) != null) {
if (!isClientSet) {
diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(evt => {
const {
connectParams: { version, protocol, port, host }
} = evt
console.log(
`HTTP:undici ${process.pid}: connecting to ${host}${
port ? `:${port}` : ''
} using ${protocol}${version}`
)
})

diagnosticsChannel.channel('undici:client:connected').subscribe(evt => {
const {
connectParams: { version, protocol, port, host }
} = evt
console.log(
`HTTP:undici ${process.pid}: connected to ${host}${
port ? `:${port}` : ''
} using ${protocol}${version}`
)
})

diagnosticsChannel.channel('undici:client:connectError').subscribe(evt => {
const {
connectParams: { version, protocol, port, host },
error
} = evt
console.log(
`HTTP:undici ${process.pid}: connection to ${host}${
port ? `:${port}` : ''
} using ${protocol}${version} errored - ${error.message}`
)
})

diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(evt => {
const {
request: { method, path, origin }
} = evt
console.log(
`HTTP:undici ${process.pid}: sending request to ${method} ${origin}/${path}`
)
})
}

// Track all WebSocket events
diagnosticsChannel.channel('undici:websocket:open').subscribe(evt => {
const {
address: { address, port },
protocol,
extensions
} = evt
console.log(
`WebSocket:undici ${process.pid}: connection opened ${address}${
port ? `:${port}` : ''
} using ${protocol}-${extensions}`
)
})

diagnosticsChannel.channel('undici:websocket:close').subscribe(evt => {
const { websocket, code, reason } = evt
console.log(
`WebSocket:undici ${process.pid}: closed connection to ${websocket.url} - ${code} ${reason}`
)
})

diagnosticsChannel.channel('undici:websocket:socket_error').subscribe(err => {
console.log(
`WebSocket:undici ${process.pid}: connection errored - ${err.message}`
)
})

diagnosticsChannel.channel('undici:websocket:ping').subscribe(evt => {
console.log(`WebSocket:undici ${process.pid}: ping received`)
})

diagnosticsChannel.channel('undici:websocket:pong').subscribe(evt => {
console.log(`WebSocket:undici ${process.pid}: pong received`)
})
}

module.exports = {
channels
}
18 changes: 1 addition & 17 deletions lib/core/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
const assert = require('assert')
const { kHTTP2BuildRequest, kHTTP2CopyHeaders, kHTTP1BuildRequest } = require('./symbols')
const util = require('./util')
const { channels } = require('./diagnostics.js')
const { headerNameLowerCasedRecord } = require('./constants')

// headerCharRegex have been lifted from
Expand All @@ -25,25 +26,8 @@ const invalidPathRegex = /[^\u0021-\u00ff]/

const kHandler = Symbol('handler')

const channels = {}

let extractBody

try {
const diagnosticsChannel = require('diagnostics_channel')
channels.create = diagnosticsChannel.channel('undici:request:create')
channels.bodySent = diagnosticsChannel.channel('undici:request:bodySent')
channels.headers = diagnosticsChannel.channel('undici:request:headers')
channels.trailers = diagnosticsChannel.channel('undici:request:trailers')
channels.error = diagnosticsChannel.channel('undici:request:error')
} catch {
channels.create = { hasSubscribers: false }
channels.bodySent = { hasSubscribers: false }
channels.headers = { hasSubscribers: false }
channels.trailers = { hasSubscribers: false }
channels.error = { hasSubscribers: false }
}

class Request {
constructor (origin, {
path,
Expand Down
7 changes: 1 addition & 6 deletions lib/websocket/connection.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict'

const diagnosticsChannel = require('diagnostics_channel')
const { uid, states } = require('./constants')
const {
kReadyState,
Expand All @@ -9,18 +8,14 @@ const {
kReceivedClose
} = require('./symbols')
const { fireEvent, failWebsocketConnection } = require('./util')
const { channels } = require('../core/diagnostics')
const { CloseEvent } = require('./events')
const { makeRequest } = require('../fetch/request')
const { fetching } = require('../fetch/index')
const { Headers } = require('../fetch/headers')
const { getGlobalDispatcher } = require('../global')
const { kHeadersList } = require('../core/symbols')

const channels = {}
channels.open = diagnosticsChannel.channel('undici:websocket:open')
channels.close = diagnosticsChannel.channel('undici:websocket:close')
channels.socketError = diagnosticsChannel.channel('undici:websocket:socket_error')

/** @type {import('crypto')} */
let crypto
try {
Expand Down
6 changes: 1 addition & 5 deletions lib/websocket/receiver.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict'

const { Writable } = require('stream')
const diagnosticsChannel = require('diagnostics_channel')
const { parserStates, opcodes, states, emptyBuffer } = require('./constants')
const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols')
const { channels } = require('../core/diagnostics')
const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = require('./util')
const { WebsocketFrameSend } = require('./frame')

Expand All @@ -12,10 +12,6 @@ const { WebsocketFrameSend } = require('./frame')
// Copyright (c) 2013 Arnout Kazemier and contributors
// Copyright (c) 2016 Luigi Pinca and contributors

const channels = {}
channels.ping = diagnosticsChannel.channel('undici:websocket:ping')
channels.pong = diagnosticsChannel.channel('undici:websocket:pong')

class ByteParser extends Writable {
#buffers = []
#byteOffset = 0
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@
"test:node-fetch": "mocha --exit test/node-fetch",
"test:fetch": "npm run build:node && borp --expose-gc --coverage -p \"test/fetch/*.js\" && borp --coverage -p \"test/webidl/*.js\"",
"test:jest": "jest",
"test:tap": "tap test/*.js test/diagnostics-channel/*.js",
"test:node-test": "borp --coverage -p \"test/node-test/*.js\"",
"test:tdd": "tap test/*.js test/diagnostics-channel/*.js -w",
"test:tap": "tap test/*.js",
"test:node-test": "borp --coverage -p \"test/node-test/**/*.js\"",
"test:tdd": "tap test/*.js --coverage -w",
"test:tdd:node-test": "borp -p \"test/node-test/**/*.js\" -w",
Comment on lines +84 to +86
Copy link
Member Author

Choose a reason for hiding this comment

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

Had to split it as for some reason diagnostics tests were migrated but still run under tap, and failed only for this PR 🤔

"test:typescript": "tsd && tsc --skipLibCheck test/imports/undici-import.ts",
"test:websocket": "borp --coverage -p \"test/websocket/*.js\"",
"test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-FileAPI.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ try {
process.exit(0)
}

const { Client } = require('../..')
const { Client } = require('../../..')

test('Diagnostics channel - connect error', (t) => {
const connectError = new Error('custom error')
Expand All @@ -23,7 +23,7 @@ test('Diagnostics channel - connect error', (t) => {
_connector = connector

assert.equal(typeof _connector, 'function')
assert.equal(Object.keys(connectParams).length, 6)
assert.equal(Object.keys(connectParams).length, 7)

const { host, hostname, protocol, port, servername } = connectParams

Expand All @@ -35,7 +35,7 @@ test('Diagnostics channel - connect error', (t) => {
})

diagnosticsChannel.channel('undici:client:connectError').subscribe(({ error, connectParams, connector }) => {
assert.equal(Object.keys(connectParams).length, 6)
assert.equal(Object.keys(connectParams).length, 7)
assert.equal(_connector, connector)

const { host, hostname, protocol, port, servername } = connectParams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ try {
process.exit(0)
}

const { Client } = require('../..')
const { Client } = require('../../..')
const { createServer } = require('http')

test('Diagnostics channel - error', (t) => {
Expand Down