Skip to content

Commit f73bebb

Browse files
committed
fs: add diagnostics_channel tracing for operations
Each node:fs operation publishes to its own TracingChannel, named fs.<operation>. The sync, callback, and promise forms of an operation share a channel, and the event context carries the form in `api`, the caller's arguments in `args`, and the leading arguments by name. The events are published from JavaScript with the TracingChannel helpers, so all events of a call share one context object, stores bound with bindStore() reach the callback and nested operations, and the error event is always followed by end or asyncEnd. Each traced function starts with a check that calls the function again inside the trace when the channel has subscribers. The whole body then runs inside the start scope, so requests capture the bound stores, and captured function references still publish. Assisted-by: claude:opus-5.5 Signed-off-by: Tim Fish <tim@timfish.uk>
1 parent 3a44541 commit f73bebb

10 files changed

Lines changed: 1330 additions & 12 deletions

‎doc/api/diagnostics_channel.md‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,91 @@ diagnosticsChannel.subscribe('crypto.fips.indicator', (message) => {
16361636
});
16371637
```
16381638

1639+
#### File system
1640+
1641+
<!-- YAML
1642+
added: REPLACEME
1643+
-->
1644+
1645+
> Stability: 1 - Experimental
1646+
1647+
Each `node:fs` operation publishes to its own [`TracingChannel`][] named
1648+
`fs.<operation>`, for example `tracing:fs.stat:start`. The synchronous,
1649+
callback, and promise forms of an operation share the same channel. The events
1650+
follow the [TracingChannel Channels][] rules.
1651+
1652+
* `event` {Object} containing the following properties
1653+
* `api` {string} The form of the function: `'sync'`, `'callback'`, or
1654+
`'promise'`.
1655+
* `args` {Array} The arguments as passed by the caller.
1656+
* The leading arguments of the operation, by name, as listed in the table
1657+
below. For `FileHandle` methods, `fd` is the descriptor of the handle and
1658+
`args` holds the arguments of the method.
1659+
1660+
| Channel | Functions | Named properties |
1661+
| --------------- | ---------------------------------------------------------------- | ------------------------ |
1662+
| `fs.access` | `access` | `path` |
1663+
| `fs.appendFile` | `appendFile` | `path`, `data` |
1664+
| `fs.chmod` | `chmod` | `path`, `mode` |
1665+
| `fs.chown` | `chown` | `path`, `uid`, `gid` |
1666+
| `fs.close` | `close`, `filehandle.close()` | `fd` |
1667+
| `fs.closedir` | `dir.close()`, `dir.closeSync()` | `path` |
1668+
| `fs.copyFile` | `copyFile` | `path`, `dest` |
1669+
| `fs.cp` | `cp` | `path`, `dest` |
1670+
| `fs.exists` | `exists` | `path` |
1671+
| `fs.fchmod` | `fchmod`, `filehandle.chmod()` | `fd`, `mode` |
1672+
| `fs.fchown` | `fchown`, `filehandle.chown()` | `fd`, `uid`, `gid` |
1673+
| `fs.fdatasync` | `fdatasync`, `filehandle.datasync()` | `fd` |
1674+
| `fs.fstat` | `fstat`, `filehandle.stat()` | `fd` |
1675+
| `fs.fsync` | `fsync`, `filehandle.sync()` | `fd` |
1676+
| `fs.ftruncate` | `ftruncate`, `filehandle.truncate()` | `fd` |
1677+
| `fs.futimes` | `futimes`, `filehandle.utimes()` | `fd`, `atime`, `mtime` |
1678+
| `fs.glob` | `glob` | `pattern` |
1679+
| `fs.lchmod` | `lchmod` | `path`, `mode` |
1680+
| `fs.lchown` | `lchown` | `path`, `uid`, `gid` |
1681+
| `fs.link` | `link` | `path`, `dest` |
1682+
| `fs.lstat` | `lstat` | `path` |
1683+
| `fs.lutimes` | `lutimes` | `path`, `atime`, `mtime` |
1684+
| `fs.mkdir` | `mkdir` | `path` |
1685+
| `fs.mkdtemp` | `mkdtemp`, `mkdtempDisposable` | `prefix` |
1686+
| `fs.open` | `open` | `path` |
1687+
| `fs.openAsBlob` | `openAsBlob` | `path` |
1688+
| `fs.opendir` | `opendir` | `path` |
1689+
| `fs.read` | `read`, `filehandle.read()` | `fd` |
1690+
| `fs.readdir` | `readdir` | `path` |
1691+
| `fs.readFile` | `readFile`, `filehandle.readFile()` | `path` |
1692+
| `fs.readlink` | `readlink` | `path` |
1693+
| `fs.readv` | `readv`, `filehandle.readv()` | `fd`, `buffers` |
1694+
| `fs.realpath` | `realpath`, `realpath.native` | `path` |
1695+
| `fs.rename` | `rename` | `path`, `dest` |
1696+
| `fs.rm` | `rm` | `path` |
1697+
| `fs.rmdir` | `rmdir` | `path` |
1698+
| `fs.stat` | `stat` | `path` |
1699+
| `fs.statfs` | `statfs` | `path` |
1700+
| `fs.symlink` | `symlink` | `target`, `path` |
1701+
| `fs.truncate` | `truncate` | `path` |
1702+
| `fs.unlink` | `unlink` | `path` |
1703+
| `fs.utimes` | `utimes` | `path`, `atime`, `mtime` |
1704+
| `fs.write` | `write`, `filehandle.write()` | `fd`, `buffer` |
1705+
| `fs.writeFile` | `writeFile`, `filehandle.writeFile()`, `filehandle.appendFile()` | `path`, `data` |
1706+
| `fs.writev` | `writev`, `filehandle.writev()` | `fd`, `buffers` |
1707+
1708+
A function name such as `stat` means `fs.stat()`, `fs.statSync()`, and
1709+
`fsPromises.stat()`, where these exist. For `fs.readFile`, `fs.writeFile`, and
1710+
`fs.appendFile`, `path` is the value as passed, so it can also be a file
1711+
descriptor or a {FileHandle}. For `fs.write` with a string, `buffer` is the
1712+
string. For callback forms, `result` is the first callback argument after the
1713+
error, so for `fs.read` and `fs.write` it is the number of bytes.
1714+
1715+
An operation that uses other `fs` operations also publishes those, inside its
1716+
own events. For example, `fs.readFileSync()` without an encoding publishes to
1717+
`fs.open`, `fs.read`, and `fs.close`. Streams from `fs.createReadStream()` and
1718+
`fs.createWriteStream()` publish the `fs.open`, `fs.read`, `fs.write`,
1719+
`fs.writev`, and `fs.close` operations they use.
1720+
1721+
`fsPromises.glob()`, `fs.watch()`, `fs.watchFile()`, and `dir.read()` do not
1722+
publish events.
1723+
16391724
#### HTTP
16401725

16411726
> Stability: 1 - Experimental

0 commit comments

Comments
 (0)