Skip to content

Integrate rust logging#423

Open
adespawn wants to merge 8 commits into
scylladb:mainfrom
adespawn:logging-tracing
Open

Integrate rust logging#423
adespawn wants to merge 8 commits into
scylladb:mainfrom
adespawn:logging-tracing

Conversation

@adespawn
Copy link
Copy Markdown
Contributor

@adespawn adespawn commented Mar 27, 2026

This PR was created with Claude Opus and reviewed by me.

This PR introduces new API for logging. As discussed in person, we cannot keep the original interface, which we change with this PR.

Add configurable log forwarding from Rust driver to JS

Introduces a logging system that forwards internal driver log events to the
JS Client as 'log' EventEmitter events, with configurable severity
filtering.

Highlights

  • logLevel client option: Controls the minimum severity of forwarded
    events. Set to one of trace, debug, info, warning, error, or
    off (default). Filtering happens on the native side before crossing the
    FFI boundary.
  • types.logLevels enum: Provides type-safe access to log level values
    in both JS and TypeScript.
  • Per-client registration: Each Client registers its own callback on
    connect() and unregisters on shutdown(). Multiple clients can coexist
    with independent log levels.
  • Four separate event arguments: The 'log' event delivers
    (level, target, message, furtherInfo) as separate arguments, matching
    the cassandra-driver event signature.
  • Native implementation: A global tracing subscriber in Rust maintains
    a registry of per-client NAPI callbacks. setupLogging() returns an
    Option<u32> id (or null for off/invalid), used by removeLogging()
    to unregister.

Documentation

  • New standalone Logging page covering levels, event
    arguments, event sources, multi-client behavior, and usage examples.
  • New "Logging" section in the Migration guide
    documenting differences from cassandra-driver: logging off by default,
    verbose replaced by trace+debug, target replaces className,
    cross-client event visibility.

Tests

  • Unit tests for setupLogging/removeLogging: level filtering, all five
    levels delivered, furtherInfo with extra fields, multiple callbacks,
    removal stops delivery.
  • Integration tests for log events during connect(), query execution, and
    DDL operations.
  • API tests asserting logLevels enum values in JS and TypeScript.

Fixes: #16

@adespawn adespawn self-assigned this Mar 27, 2026
@adespawn adespawn force-pushed the logging-tracing branch 4 times, most recently from ab97f6e to 18b85d2 Compare April 3, 2026 09:58
@adespawn adespawn changed the title [LLM draft] Integrate logging Integrate rust logging Apr 3, 2026
@adespawn adespawn marked this pull request as ready for review April 3, 2026 09:59
@adespawn adespawn requested a review from Copilot April 3, 2026 10:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR integrates Rust tracing-based logging into the Node.js driver by forwarding Rust log events across the N-API boundary and exposing a types.logLevels string enum to configure filtering from JavaScript/TypeScript.

Changes:

  • Added a Rust global tracing subscriber layer that forwards events to per-client registered JS callbacks with level filtering.
  • Introduced logLevel client option and types.logLevels enum (JS + TS typings), plus tests covering API surface and behavior.
  • Added end-user documentation and migration guide updates for the new logging system.

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/logging.rs New Rust forwarding layer + per-client callback registry + level filtering.
lib/client.js Registers/unregisters Rust log callback based on options.logLevel.
lib/client-options.js Adds logLevel option default + validation and JSDoc.
lib/types/index.js Adds types.logLevels enum values.
lib/types/index.d.ts Adds logLevels TypeScript enum.
main.d.ts Adds logLevel?: types.logLevels to ClientOptions.
src/tests/logging_tests.rs / src/tests/mod.rs Adds Rust test helpers to emit tracing events for JS tests.
test/unit/logging-tests.js Unit tests for Rust->JS forwarding, multi-callback, and filtering.
test/integration/supported/client-logging-tests.js Integration coverage for real Rust driver log events emitted via Client.
test/unit-not-supported/api-tests.js Ensures types.logLevels exists in the public API surface.
test/typescript/* Type-level coverage for types.logLevels and Client({ logLevel }).
docs/src/logging.md / docs/src/migration_guide.md / docs/src/SUMMARY.md Documentation for logging and migration notes.
Cargo.toml Adds tracing and tracing-subscriber dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/client.js Outdated
Comment thread lib/client.js Outdated
Comment thread src/logging.rs Outdated
Comment thread test/unit/logging-tests.js Outdated
Comment thread test/integration/supported/client-logging-tests.js Outdated
Comment thread test/integration/supported/client-logging-tests.js Outdated
Comment thread test/integration/supported/client-logging-tests.js Outdated
Comment thread docs/src/logging.md
Comment thread docs/src/migration_guide.md Outdated
@adespawn adespawn added this to the 0.5.0 milestone Apr 3, 2026
@adespawn adespawn requested a review from Copilot April 3, 2026 10:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 20 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/utils.js
Comment thread src/logging.rs
Comment thread src/logging.rs
Comment thread docs/src/logging.md
Comment thread docs/src/migration_guide.md
Comment thread test/integration/supported/client-logging-tests.js
Comment thread docs/src/migration_guide.md
@adespawn adespawn requested a review from wprzytula April 3, 2026 10:55
@wprzytula
Copy link
Copy Markdown
Contributor

* New "Logging" section in the [Migration guide](docs/src/migration_guide.md)
  documenting differences from `cassandra-driver`: logging off by default,

I have doubts. You say that you change the default logging level from (?) to "off". Why?
Especially ERROR level, but also WARN level logs are often used as a way to signal user
important situation in the driver. For example, Rust Driver automatically logs warnings
that come from the DB on the WARN level. It is expected that driver's users see them by default.

@adespawn
Copy link
Copy Markdown
Contributor Author

It is expected that driver's users see them by default.

You still need to add some logic to be able to see any logs (client.on("log"...).

Why?

Considering the above, I assumed that users when creating the logic will also set the desired log level.
But on the other hand, this logging should be mostly API compatible, so we could set it to WARN/ ERROR by default, so transitioning users have some default logging...

@wprzytula
Copy link
Copy Markdown
Contributor

It is expected that driver's users see them by default.

You still need to add some logic to be able to see any logs (client.on("log"...).

Why?

Considering the above, I assumed that users when creating the logic will also set the desired log level. But on the other hand, this logging should be mostly API compatible, so we could set it to WARN/ ERROR by default, so transitioning users have some default logging...

Yep. Let's default to WARN.

Comment thread src/logging.rs
Comment thread src/logging.rs Outdated
Comment thread src/logging.rs
Comment thread src/logging.rs
Comment thread src/logging.rs
Comment thread src/logging.rs
Comment on lines +66 to +75
/// Returns `None` for `"off"` or unrecognized strings.
fn parse_level(level: &str) -> Option<Level> {
match level {
"trace" => Some(Level::TRACE),
"debug" => Some(Level::DEBUG),
"info" => Some(Level::INFO),
"warning" => Some(Level::WARN),
"error" => Some(Level::ERROR),
_ => None,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤔 Shouldn't this treat unknown strings as Result::Err, while off as Option::None?

Copy link
Copy Markdown
Contributor Author

@adespawn adespawn Apr 16, 2026

Choose a reason for hiding this comment

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

Comment thread src/logging.rs
Comment thread src/logging.rs Outdated
Comment thread src/logging.rs Outdated
Comment thread src/logging.rs Outdated
Copy link
Copy Markdown
Contributor

@wprzytula wprzytula left a comment

Choose a reason for hiding this comment

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

For now, reviewed up till the second commit, inclusively.

Comment thread src/logging.rs Outdated
Comment thread src/logging.rs
@wprzytula
Copy link
Copy Markdown
Contributor

In-person review:

  • useless last integration test,
  • missing unit test of the visitor,
  • callback per Client is OK,
  • callbacks should be removed in a finalizer, not in shutdown,
  • take a look at CPP-RS's impl of the logger bridge.

Comment thread docs/src/logging.md Outdated
Comment thread docs/src/logging.md Outdated
Comment thread docs/src/migration_guide.md Outdated
@adespawn
Copy link
Copy Markdown
Contributor Author

Rebase (no changes)

@adespawn adespawn force-pushed the logging-tracing branch 2 times, most recently from dc99462 to 50e2b46 Compare April 27, 2026 12:19
@adespawn
Copy link
Copy Markdown
Contributor Author

Rebase (again)

@adespawn
Copy link
Copy Markdown
Contributor Author

callbacks should be removed in a finalizer, not in shutdown,

Looking a bit more at it, I'm not sure it's a good idea: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry#notes_on_cleanup_callbacks

@adespawn adespawn force-pushed the logging-tracing branch 2 times, most recently from 0060f73 to 0d05018 Compare April 29, 2026 09:15
@adespawn
Copy link
Copy Markdown
Contributor Author

Partial changes

useless last integration test

Done

@adespawn adespawn force-pushed the logging-tracing branch 3 times, most recently from aa81fa5 to 463df12 Compare April 30, 2026 14:29
@adespawn
Copy link
Copy Markdown
Contributor Author

callbacks should be removed in a finalizer, not in shutdown,

Done, with a new test

@adespawn
Copy link
Copy Markdown
Contributor Author

The only remaining thing now should be logging format (which we discussed during in person review).
Noteworthy changes:

  • Change to default behaviour
  • Internal notes on loggin

@adespawn adespawn modified the milestones: 0.5.0, GA May 18, 2026
@adespawn adespawn force-pushed the logging-tracing branch 4 times, most recently from dc55048 to ad14fec Compare May 19, 2026 13:35
@adespawn
Copy link
Copy Markdown
Contributor Author

Since I'm not exactly sure about the "Rework logging" commit, I didn't merge it to a proper place yet - will do it once those changes are be accepted

@adespawn adespawn requested a review from wprzytula May 19, 2026 14:38
Copy link
Copy Markdown
Contributor

@wprzytula wprzytula left a comment

Choose a reason for hiding this comment

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

The commit structure and descriptions are bad. Please order the commits more neatly, describe them better, and make sure commits do not introduce bad code that you fix in a later commit.

Comment thread lib/types/index.js
Comment thread lib/client-options.js
Comment thread lib/client-options.js
useBigIntAsLong: true,
useBigIntAsVarint: true,
},
logLevel: undefined,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤔 This changes nothing, right? The key set to undefined is equivalent to no such key set, right?

Comment thread lib/client-options.js
Comment on lines +733 to +747
/**
* Validates the logLevel option.
* @param {string} logLevel
* @private
*/
function validateLogLevel(logLevel) {
if (
logLevel !== undefined &&
(typeof logLevel !== "string" || !validLogLevels.includes(logLevel))
) {
throw new TypeError(
`logLevel must be one of ${validLogLevels.map((l) => `'${l}'`).join(", ")}`,
);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💭 This seems buggy.

  1. What if a non-string junk object is passed?
  2. What if a value of the log level enum is passed?

Comment thread lib/client.js Outdated
Comment thread docs/src/internal/logging.md Outdated
Comment thread docs/src/internal/logging.md Outdated
Comment thread docs/src/internal/logging.md Outdated
Comment thread src/logging.rs Outdated
Comment thread src/logging.rs Outdated
Comment on lines -91 to -106
// Collects all fields and values in a single log event into a single String, similarly to C++-rs driver
impl Visit for MessageVisitor {
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
if field.name() == "message" {
let _ = write!(&mut self.message, "{:?}", value);
if self.log_message.is_empty() {
write!(self.log_message, "{field}: {value:?}").unwrap();
} else {
if !self.extras.is_empty() {
self.extras.push_str(", ");
}

let _ = write!(&mut self.extras, "{}={:?}", field.name(), value);
}
}

fn record_str(&mut self, field: &Field, value: &str) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔧 Explain these changes in the commit message.

adespawn added 8 commits May 25, 2026 10:39
This commit introduces rust logging cleanup on client finalization.
Since we cannot deterministically predict when the client will be finalized,
this is done as a back-up to manual logging cleanup on client shutdown.

This new cleanup will trigger only when the client didn't shut down yet.
Rust unit tests:
- MessageVisitor field formatting
- rust_level_to_js and parse_js_level_to_rust mapping correctness

JS unit tests:
- FFI forwarding delivers events at all 5 tracing levels
- Message content survives FFI boundary intact
- Target field contains Rust module path
- Multiple registered callbacks each receive events (shared subscriber)
- removeLogging stops delivery without affecting other callbacks
- Level filtering only passes events at or above registered level
- Visitor field formatting end-to-end (comma separation, debug quotes, int/bool repr)
- Level-to-message pairing is correct across FFI
- Default logLevel registers Rust callback and receives events
- logLevel 'off' suppresses all events

Integration tests (against real cluster):
- Real Rust driver produces log events during connection
- JS and Rust log events coexist during connection
- cleanup both for shutdown and gc cleanup
At some point the code was changed, in a way that fixes scylladb#44.
This commit fixes scylladb#44 by removing that redundant flag
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.

Integrate logging with Rust driver's logging (tracing) subsystem

3 participants