From 731019829cdb1c2de1125aab8c15b3a66e913f23 Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 17:58:15 +0530 Subject: [PATCH 01/11] Add PR 10 logging initialization design --- ...4-02-pr10-logging-initialization-design.md | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-02-pr10-logging-initialization-design.md diff --git a/docs/superpowers/specs/2026-04-02-pr10-logging-initialization-design.md b/docs/superpowers/specs/2026-04-02-pr10-logging-initialization-design.md new file mode 100644 index 00000000..4bf5af21 --- /dev/null +++ b/docs/superpowers/specs/2026-04-02-pr10-logging-initialization-design.md @@ -0,0 +1,69 @@ +# PR 10 Logging Initialization Design + +**Goal:** Keep logging backend initialization adapter-owned so `trusted-server-core` remains platform-agnostic while Fastly continues to initialize its own `log-fastly` backend. + +## Problem + +`trusted-server-core` still declares a `log-fastly` dependency even though log +backend setup already happens in the Fastly adapter entrypoint. That keeps a +Fastly-specific crate in the core dependency graph and weakens the migration +boundary needed for future EdgeZero adapters such as Cloudflare, Spin, and +Axum. + +## Design + +### Responsibility split + +- `trusted-server-core` emits logs only through `log` macros. +- Each adapter crate owns logger initialization and backend wiring. +- Fastly-specific logger setup moves behind an adapter-local module boundary. + +This keeps core free of platform logging backends while establishing a clean +pattern future adapters can mirror without forcing a shared abstraction too +early. + +### Fastly adapter shape + +Create an adapter-local logging module in +`crates/trusted-server-adapter-fastly/src/logging.rs` that exposes a small +`init_logger()` function. The implementation stays Fastly-specific and can keep +using `log-fastly`, `fern`, and the existing formatting choices. + +`crates/trusted-server-adapter-fastly/src/main.rs` should only import that +module and call `logging::init_logger()` during startup. + +### Core crate shape + +Remove `log-fastly` from +`crates/trusted-server-core/Cargo.toml`. No production code in core should +change unless compilation reveals an unexpected dependency. The intended end +state is that core depends on `log` only. + +## File impact + +- Create: `crates/trusted-server-adapter-fastly/src/logging.rs` +- Modify: `crates/trusted-server-adapter-fastly/src/main.rs` +- Modify: `crates/trusted-server-core/Cargo.toml` +- Modify: `Cargo.lock` + +## Testing and verification + +- Add or update small adapter-local tests only if needed for the extracted + logging module. +- Run the standard project gates: + - `cargo fmt --all -- --check` + - `cargo clippy --workspace --all-targets --all-features -- -D warnings` + - `cargo test --workspace` + +## Out of scope + +- Introducing a cross-adapter logging trait in core +- Changing log formatting semantics beyond what is needed to extract the module +- Adding logging implementations for non-Fastly adapters + +## Acceptance + +- `log-fastly` exists only in the Fastly adapter dependency graph +- Core uses `log` macros without any Fastly-specific logging backend dependency +- Fastly adapter still initializes logging at startup +- Workspace verification gates pass From a05189e471d29df6af862ee0194940c5a943cda0 Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:02:36 +0530 Subject: [PATCH 02/11] Add PR 10 logging initialization plan --- .../2026-04-02-pr10-logging-initialization.md | 294 ++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md diff --git a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md new file mode 100644 index 00000000..03b52daa --- /dev/null +++ b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md @@ -0,0 +1,294 @@ +# PR 10 Logging Initialization Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Keep logging backend initialization adapter-owned by extracting Fastly logging setup into an adapter-local module and removing `log-fastly` from `trusted-server-core`. + +**Architecture:** `trusted-server-core` continues to emit logs only through `log` macros and has no platform logging backend dependency. `trusted-server-adapter-fastly` owns Fastly-specific logger initialization behind a local `logging.rs` module, and `main.rs` just calls into that adapter-local entrypoint. + +**Tech Stack:** Rust 2024 edition conventions, `log`, `log-fastly`, `fern`, `chrono` + +--- + +## File Structure + +- Create: `crates/trusted-server-adapter-fastly/src/logging.rs` + - Own Fastly-specific logger setup and any small formatting helpers needed for unit testing. +- Modify: `crates/trusted-server-adapter-fastly/src/main.rs` + - Stop carrying logger implementation details directly; import the adapter-local module and call `logging::init_logger()`. +- Modify: `crates/trusted-server-core/Cargo.toml` + - Remove `log-fastly` from core dependencies. +- Modify: `Cargo.lock` + - Lockfile update after dependency removal. + +The plan intentionally avoids any core logging trait or shared abstraction. Future adapters can mirror the same adapter-local module shape without forcing a premature common interface. + +## Tasks + +### Task 1: Extract Fastly logger formatting into an adapter-local module + +**Files:** +- Create: `crates/trusted-server-adapter-fastly/src/logging.rs` + +- [ ] **Step 1: Write a failing unit test for the extracted formatting helper** + +Create `crates/trusted-server-adapter-fastly/src/logging.rs` with a test-first skeleton. Add a helper test that defines the intended log line shape without trying to install a global logger: + +```rust +#[cfg(test)] +mod tests { + use super::*; + use log::{Level, Record}; + + #[test] + fn format_log_line_uses_last_target_segment_and_message() { + let record = Record::builder() + .args(format_args!("hello world")) + .level(Level::Info) + .target("trusted_server_adapter_fastly::proxy") + .build(); + + let line = format_log_line( + "2026-04-02T00:00:00.000Z", + &record, + ); + + assert!( + line.contains("INFO [proxy] hello world"), + "should use the final target segment and message text" + ); + } +} +``` + +Also add a production skeleton so the file compiles but the test fails: + +```rust +pub(crate) fn format_log_line(_timestamp: &str, _record: &log::Record<'_>) -> String { + String::new() +} +``` + +- [ ] **Step 2: Run the adapter test to verify it fails** + +Run: + +```bash +cargo test --package trusted-server-adapter-fastly logging -- --nocapture +``` + +Expected: FAIL because `format_log_line()` returns the wrong string. + +- [ ] **Step 3: Implement the minimal formatting helper and adapter logger initializer** + +Replace the skeleton with the real adapter-local module: + +```rust +use chrono::{Local, SecondsFormat}; +use log_fastly::Logger; + +pub(crate) fn format_log_line(timestamp: &str, record: &log::Record<'_>) -> String { + format!( + "{} {} [{}] {}", + timestamp, + record.level(), + record.target().split("::").last().unwrap_or(record.target()), + record.args() + ) +} + +pub(crate) fn init_logger() { + let logger = Logger::builder() + .default_endpoint("tslog") + .echo_stdout(true) + .max_level(log::LevelFilter::Info) + .build() + .expect("should build Logger"); + + fern::Dispatch::new() + .format(|out, _message, record| { + let timestamp = + Local::now().to_rfc3339_opts(SecondsFormat::Millis, true); + out.finish(format_args!("{}", format_log_line(×tamp, record))); + }) + .chain(Box::new(logger) as Box) + .apply() + .expect("should initialize logger"); +} +``` + +Keep the logic semantically equivalent to the current `main.rs` formatting. + +- [ ] **Step 4: Run the adapter test to verify it passes** + +Run: + +```bash +cargo test --package trusted-server-adapter-fastly logging -- --nocapture +``` + +Expected: PASS. + +- [ ] **Step 5: Commit the extracted logging module** + +```bash +git add crates/trusted-server-adapter-fastly/src/logging.rs +git commit -m "Extract Fastly logging initialization into adapter module" +``` + +--- + +### Task 2: Wire `main.rs` to the adapter-local logging module + +**Files:** +- Modify: `crates/trusted-server-adapter-fastly/src/main.rs` + +- [ ] **Step 1: Write a failing compile-time integration step for the new module wiring** + +Update `main.rs` to reference `logging::init_logger()` before the module exists in the file: + +```rust +mod logging; + +#[fastly::main] +fn main(req: Request) -> Result { + logging::init_logger(); + // ... +} +``` + +Delete the old inline `init_logger()` function and remove imports that only it used: + +- `use log_fastly::Logger;` +- any `chrono`/`fern` imports that are no longer needed in `main.rs` + +- [ ] **Step 2: Run the adapter package tests to verify the extraction is wired correctly** + +Run: + +```bash +cargo test --package trusted-server-adapter-fastly -- --nocapture +``` + +Expected: PASS. If compilation fails, fix the module imports and remaining references in `main.rs`. + +- [ ] **Step 3: Commit the adapter wiring cleanup** + +```bash +git add crates/trusted-server-adapter-fastly/src/main.rs +git commit -m "Wire Fastly main.rs to adapter-local logging module" +``` + +--- + +### Task 3: Remove `log-fastly` from core + +**Files:** +- Modify: `crates/trusted-server-core/Cargo.toml` +- Modify: `Cargo.lock` + +- [ ] **Step 1: Verify core does not reference `log-fastly` directly** + +Run: + +```bash +rg -n "log_fastly|Logger::builder|Logger::from_env" crates/trusted-server-core +``` + +Expected: no matches. + +- [ ] **Step 2: Remove `log-fastly` from core dependencies** + +In `crates/trusted-server-core/Cargo.toml`, delete: + +```toml +log-fastly = { workspace = true } +``` + +Do not remove `log = { workspace = true }`. + +- [ ] **Step 3: Update the lockfile** + +Run: + +```bash +cargo test --package trusted-server-core --lib --no-run +``` + +Expected: `Cargo.lock` updates only as needed for the dependency graph while core still compiles. + +- [ ] **Step 4: Confirm `log-fastly` remains adapter-only** + +Run: + +```bash +rg -n "log-fastly" crates +``` + +Expected: match only in `crates/trusted-server-adapter-fastly/Cargo.toml`. + +- [ ] **Step 5: Commit the dependency cleanup** + +```bash +git add crates/trusted-server-core/Cargo.toml Cargo.lock +git commit -m "Remove log-fastly from trusted-server-core" +``` + +--- + +### Task 4: Run project verification gates + +**Files:** +- Verify the whole workspace after the logging extraction and dependency cleanup + +- [ ] **Step 1: Format check** + +Run: + +```bash +cargo fmt --all -- --check +``` + +Expected: PASS. If it fails, run `cargo fmt --all` and re-run the check. + +- [ ] **Step 2: Clippy** + +Run: + +```bash +cargo clippy --workspace --all-targets --all-features -- -D warnings +``` + +Expected: PASS. + +- [ ] **Step 3: Full workspace tests** + +Run: + +```bash +cargo test --workspace +``` + +Expected: PASS. + +- [ ] **Step 4: Commit any formatting fallout** + +Only if `cargo fmt --all` changed files: + +```bash +git add -A +git commit -m "Fix formatting after logging extraction" +``` + +--- + +## Acceptance Checklist + +- [ ] `crates/trusted-server-adapter-fastly/src/logging.rs` exists +- [ ] `crates/trusted-server-adapter-fastly/src/main.rs` no longer contains the inline Fastly logger implementation +- [ ] `crates/trusted-server-core/Cargo.toml` no longer depends on `log-fastly` +- [ ] `rg -n "log-fastly" crates` reports only the Fastly adapter crate +- [ ] `trusted-server-core` still uses `log` macros and compiles without a Fastly-specific logging backend dependency +- [ ] `cargo fmt --all -- --check` passes +- [ ] `cargo clippy --workspace --all-targets --all-features -- -D warnings` passes +- [ ] `cargo test --workspace` passes From 4617253fe9ba4ab4e85a16032490335bbf4d48da Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:25:55 +0530 Subject: [PATCH 03/11] Fix PR 10 logging plan to avoid per-log allocation --- .../2026-04-02-pr10-logging-initialization.md | 57 +++++++------------ 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md index 03b52daa..93c319a8 100644 --- a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md +++ b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md @@ -25,37 +25,26 @@ The plan intentionally avoids any core logging trait or shared abstraction. Futu ## Tasks -### Task 1: Extract Fastly logger formatting into an adapter-local module +### Task 1: Extract Fastly logger helper and initializer into an adapter-local module **Files:** - Create: `crates/trusted-server-adapter-fastly/src/logging.rs` -- [ ] **Step 1: Write a failing unit test for the extracted formatting helper** +- [ ] **Step 1: Write a failing unit test for a non-allocating formatting helper** -Create `crates/trusted-server-adapter-fastly/src/logging.rs` with a test-first skeleton. Add a helper test that defines the intended log line shape without trying to install a global logger: +Create `crates/trusted-server-adapter-fastly/src/logging.rs` with a test-first skeleton. Add a helper test for the target-label extraction logic without trying to install a global logger: ```rust #[cfg(test)] mod tests { use super::*; - use log::{Level, Record}; #[test] - fn format_log_line_uses_last_target_segment_and_message() { - let record = Record::builder() - .args(format_args!("hello world")) - .level(Level::Info) - .target("trusted_server_adapter_fastly::proxy") - .build(); - - let line = format_log_line( - "2026-04-02T00:00:00.000Z", - &record, - ); - - assert!( - line.contains("INFO [proxy] hello world"), - "should use the final target segment and message text" + fn target_label_uses_last_target_segment() { + assert_eq!( + target_label("trusted_server_adapter_fastly::proxy"), + "proxy", + "should use the final target segment" ); } } @@ -64,8 +53,8 @@ mod tests { Also add a production skeleton so the file compiles but the test fails: ```rust -pub(crate) fn format_log_line(_timestamp: &str, _record: &log::Record<'_>) -> String { - String::new() +pub(crate) fn target_label(target: &str) -> &str { + target } ``` @@ -77,9 +66,9 @@ Run: cargo test --package trusted-server-adapter-fastly logging -- --nocapture ``` -Expected: FAIL because `format_log_line()` returns the wrong string. +Expected: FAIL because `target_label()` returns the full target instead of the final segment. -- [ ] **Step 3: Implement the minimal formatting helper and adapter logger initializer** +- [ ] **Step 3: Implement the minimal helper and adapter logger initializer** Replace the skeleton with the real adapter-local module: @@ -87,14 +76,8 @@ Replace the skeleton with the real adapter-local module: use chrono::{Local, SecondsFormat}; use log_fastly::Logger; -pub(crate) fn format_log_line(timestamp: &str, record: &log::Record<'_>) -> String { - format!( - "{} {} [{}] {}", - timestamp, - record.level(), - record.target().split("::").last().unwrap_or(record.target()), - record.args() - ) +pub(crate) fn target_label(target: &str) -> &str { + target.split("::").last().unwrap_or(target) } pub(crate) fn init_logger() { @@ -107,9 +90,13 @@ pub(crate) fn init_logger() { fern::Dispatch::new() .format(|out, _message, record| { - let timestamp = - Local::now().to_rfc3339_opts(SecondsFormat::Millis, true); - out.finish(format_args!("{}", format_log_line(×tamp, record))); + out.finish(format_args!( + "{} {} [{}] {}", + Local::now().to_rfc3339_opts(SecondsFormat::Millis, true), + record.level(), + target_label(record.target()), + record.args() + )); }) .chain(Box::new(logger) as Box) .apply() @@ -117,7 +104,7 @@ pub(crate) fn init_logger() { } ``` -Keep the logic semantically equivalent to the current `main.rs` formatting. +Keep the logic semantically equivalent to the current `main.rs` formatting and avoid introducing a new heap allocation on each log call. - [ ] **Step 4: Run the adapter test to verify it passes** From 236eecfbeb5db364ff781a443f34ceba47b1e33b Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:28:13 +0530 Subject: [PATCH 04/11] Extract Fastly logging initialization into adapter module --- .../src/logging.rs | 44 +++++++++++++++++++ .../trusted-server-adapter-fastly/src/main.rs | 1 + 2 files changed, 45 insertions(+) create mode 100644 crates/trusted-server-adapter-fastly/src/logging.rs diff --git a/crates/trusted-server-adapter-fastly/src/logging.rs b/crates/trusted-server-adapter-fastly/src/logging.rs new file mode 100644 index 00000000..3a6a3384 --- /dev/null +++ b/crates/trusted-server-adapter-fastly/src/logging.rs @@ -0,0 +1,44 @@ +use chrono::{Local, SecondsFormat}; +use log_fastly::Logger; + +pub(crate) fn target_label(target: &str) -> &str { + target.split("::").last().unwrap_or(target) +} + +#[allow(dead_code)] +pub(crate) fn init_logger() { + let logger = Logger::builder() + .default_endpoint("tslog") + .echo_stdout(true) + .max_level(log::LevelFilter::Info) + .build() + .expect("should build Logger"); + + fern::Dispatch::new() + .format(|out, _message, record| { + out.finish(format_args!( + "{} {} [{}] {}", + Local::now().to_rfc3339_opts(SecondsFormat::Millis, true), + record.level(), + target_label(record.target()), + record.args() + )); + }) + .chain(Box::new(logger) as Box) + .apply() + .expect("should initialize logger"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn target_label_uses_last_target_segment() { + assert_eq!( + target_label("trusted_server_adapter_fastly::proxy"), + "proxy", + "should use the final target segment" + ); + } +} diff --git a/crates/trusted-server-adapter-fastly/src/main.rs b/crates/trusted-server-adapter-fastly/src/main.rs index 345a6bbf..1ecbad1e 100644 --- a/crates/trusted-server-adapter-fastly/src/main.rs +++ b/crates/trusted-server-adapter-fastly/src/main.rs @@ -30,6 +30,7 @@ use trusted_server_core::settings_data::get_settings; mod error; mod management_api; mod platform; +mod logging; use crate::error::to_error_response; use crate::platform::{build_runtime_services, open_kv_store, UnavailableKvStore}; From cd6835743b1bc134317889b2207ec2c2beb5326f Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:37:47 +0530 Subject: [PATCH 05/11] Wire Fastly main.rs to adapter-local logging module --- .../trusted-server-adapter-fastly/src/main.rs | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/crates/trusted-server-adapter-fastly/src/main.rs b/crates/trusted-server-adapter-fastly/src/main.rs index 1ecbad1e..69ecf76f 100644 --- a/crates/trusted-server-adapter-fastly/src/main.rs +++ b/crates/trusted-server-adapter-fastly/src/main.rs @@ -1,7 +1,6 @@ use error_stack::Report; use fastly::http::Method; use fastly::{Error, Request, Response}; -use log_fastly::Logger; use trusted_server_core::auction::endpoints::handle_auction; use trusted_server_core::auction::{build_orchestrator, AuctionOrchestrator}; @@ -37,7 +36,7 @@ use crate::platform::{build_runtime_services, open_kv_store, UnavailableKvStore} #[fastly::main] fn main(req: Request) -> Result { - init_logger(); + logging::init_logger(); // Keep the health probe independent from settings loading and routing so // readiness checks still get a cheap liveness response during startup. @@ -242,30 +241,3 @@ fn finalize_response(settings: &Settings, geo_info: Option<&GeoInfo>, response: response.set_header(key, value); } } - -fn init_logger() { - let logger = Logger::builder() - .default_endpoint("tslog") - .echo_stdout(true) - .max_level(log::LevelFilter::Info) - .build() - .expect("should build Logger"); - - fern::Dispatch::new() - .format(|out, message, record| { - out.finish(format_args!( - "{} {} [{}] {}", - chrono::Local::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true), - record.level(), - record - .target() - .split("::") - .last() - .unwrap_or(record.target()), - message - )) - }) - .chain(Box::new(logger) as Box) - .apply() - .expect("should initialize logger"); -} From 41cb0df71b1359d77d38869d8b82c7bcdfbd71ff Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:40:52 +0530 Subject: [PATCH 06/11] Remove log-fastly from core dependencies --- Cargo.lock | 1 - crates/trusted-server-core/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 263fcbd1..1706fd27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2822,7 +2822,6 @@ dependencies = [ "iab_gpp", "jose-jwk", "log", - "log-fastly", "lol_html", "matchit", "pin-project-lite", diff --git a/crates/trusted-server-core/Cargo.toml b/crates/trusted-server-core/Cargo.toml index 061c4d27..ddc8e2e2 100644 --- a/crates/trusted-server-core/Cargo.toml +++ b/crates/trusted-server-core/Cargo.toml @@ -33,7 +33,6 @@ iab_gpp = { workspace = true } jose-jwk = { workspace = true } log = { workspace = true } rand = { workspace = true } -log-fastly = { workspace = true } lol_html = { workspace = true } matchit = { workspace = true } pin-project-lite = { workspace = true } From e4374548c5d65f47ff60866be6d79f0410933c2b Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:44:00 +0530 Subject: [PATCH 07/11] Format Fastly logging module declaration --- crates/trusted-server-adapter-fastly/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/trusted-server-adapter-fastly/src/main.rs b/crates/trusted-server-adapter-fastly/src/main.rs index 69ecf76f..6b81637a 100644 --- a/crates/trusted-server-adapter-fastly/src/main.rs +++ b/crates/trusted-server-adapter-fastly/src/main.rs @@ -27,9 +27,9 @@ use trusted_server_core::settings::Settings; use trusted_server_core::settings_data::get_settings; mod error; +mod logging; mod management_api; mod platform; -mod logging; use crate::error::to_error_response; use crate::platform::{build_runtime_services, open_kv_store, UnavailableKvStore}; From f9b4d62bcb45c3a2abebb3f8d6d49f77c392ca5c Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Thu, 2 Apr 2026 18:50:45 +0530 Subject: [PATCH 08/11] format plan docs --- .../plans/2026-04-02-pr10-logging-initialization.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md index 93c319a8..edc937ce 100644 --- a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md +++ b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md @@ -28,6 +28,7 @@ The plan intentionally avoids any core logging trait or shared abstraction. Futu ### Task 1: Extract Fastly logger helper and initializer into an adapter-local module **Files:** + - Create: `crates/trusted-server-adapter-fastly/src/logging.rs` - [ ] **Step 1: Write a failing unit test for a non-allocating formatting helper** @@ -128,6 +129,7 @@ git commit -m "Extract Fastly logging initialization into adapter module" ### Task 2: Wire `main.rs` to the adapter-local logging module **Files:** + - Modify: `crates/trusted-server-adapter-fastly/src/main.rs` - [ ] **Step 1: Write a failing compile-time integration step for the new module wiring** @@ -171,6 +173,7 @@ git commit -m "Wire Fastly main.rs to adapter-local logging module" ### Task 3: Remove `log-fastly` from core **Files:** + - Modify: `crates/trusted-server-core/Cargo.toml` - Modify: `Cargo.lock` @@ -226,6 +229,7 @@ git commit -m "Remove log-fastly from trusted-server-core" ### Task 4: Run project verification gates **Files:** + - Verify the whole workspace after the logging extraction and dependency cleanup - [ ] **Step 1: Format check** From 49e3f1d02f90314eb192d1b99581db1de63f22cb Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Mon, 6 Apr 2026 15:37:58 +0530 Subject: [PATCH 09/11] Restore idiomatic fern logging and improve target label extraction - Reverted gratuitous _message rename and record.args() usage in logging.rs, returning to the idiomatic message parameter inside the fern format closure. - Refactored target_label to use .rsplit_once("::") rather than .split("::").last(). This provides a more explicit and robust way to extract the final module segment. - Expanded target_label test coverage to explicitly test edge cases such as inputs without :: separators, empty strings, and inputs with trailing ::. --- .../src/logging.rs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/crates/trusted-server-adapter-fastly/src/logging.rs b/crates/trusted-server-adapter-fastly/src/logging.rs index 3a6a3384..60a36b33 100644 --- a/crates/trusted-server-adapter-fastly/src/logging.rs +++ b/crates/trusted-server-adapter-fastly/src/logging.rs @@ -2,10 +2,9 @@ use chrono::{Local, SecondsFormat}; use log_fastly::Logger; pub(crate) fn target_label(target: &str) -> &str { - target.split("::").last().unwrap_or(target) + target.rsplit_once("::").map_or(target, |(_, last)| last) } -#[allow(dead_code)] pub(crate) fn init_logger() { let logger = Logger::builder() .default_endpoint("tslog") @@ -15,13 +14,13 @@ pub(crate) fn init_logger() { .expect("should build Logger"); fern::Dispatch::new() - .format(|out, _message, record| { + .format(|out, message, record| { out.finish(format_args!( "{} {} [{}] {}", Local::now().to_rfc3339_opts(SecondsFormat::Millis, true), record.level(), target_label(record.target()), - record.args() + message )); }) .chain(Box::new(logger) as Box) @@ -34,11 +33,23 @@ mod tests { use super::*; #[test] - fn target_label_uses_last_target_segment() { + fn target_label_extracts_correct_segment() { assert_eq!( target_label("trusted_server_adapter_fastly::proxy"), "proxy", - "should use the final target segment" + "should handle standard single-separator case" ); + assert_eq!( + target_label("foo::bar::baz"), + "baz", + "should handle multiple separators" + ); + assert_eq!( + target_label("no_separators_here"), + "no_separators_here", + "should handle inputs without ::" + ); + assert_eq!(target_label(""), "", "should handle empty strings"); + assert_eq!(target_label("trailing::"), "", "should handle trailing ::"); } } From dd6929c33d9b7fd816508d62b0b9230c07122d2b Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Fri, 10 Apr 2026 13:04:33 +0530 Subject: [PATCH 10/11] Resolve review findings --- .../src/logging.rs | 25 +++++++++++++++++-- .../2026-04-02-pr10-logging-initialization.md | 4 ++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/crates/trusted-server-adapter-fastly/src/logging.rs b/crates/trusted-server-adapter-fastly/src/logging.rs index 60a36b33..59a05a01 100644 --- a/crates/trusted-server-adapter-fastly/src/logging.rs +++ b/crates/trusted-server-adapter-fastly/src/logging.rs @@ -1,10 +1,27 @@ use chrono::{Local, SecondsFormat}; use log_fastly::Logger; +/// Extracts the final `::` segment from a Rust module path for use as a log label. +/// +/// Falls back to the full target string when the input contains no separator or +/// when the separator appears at the trailing position (e.g. `"foo::"`), which +/// would otherwise produce an empty label in log output. pub(crate) fn target_label(target: &str) -> &str { - target.rsplit_once("::").map_or(target, |(_, last)| last) + target.rsplit_once("::").map_or( + target, + |(_, last)| if last.is_empty() { target } else { last }, + ) } +/// Initialises the Fastly-backed `fern` logger and installs it as the global logger. +/// +/// Log records are forwarded to the `tslog` Fastly endpoint and echoed to stdout. +/// Each line is prefixed with an RFC 3339 timestamp, level, and the final segment +/// of the record's target module path. +/// +/// # Panics +/// +/// Panics if the logger cannot be built or if a global logger has already been set. pub(crate) fn init_logger() { let logger = Logger::builder() .default_endpoint("tslog") @@ -50,6 +67,10 @@ mod tests { "should handle inputs without ::" ); assert_eq!(target_label(""), "", "should handle empty strings"); - assert_eq!(target_label("trailing::"), "", "should handle trailing ::"); + assert_eq!( + target_label("trailing::"), + "trailing::", + "should fall back to full target when segment after :: is empty" + ); } } diff --git a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md index edc937ce..d1fa2f57 100644 --- a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md +++ b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md @@ -78,7 +78,9 @@ use chrono::{Local, SecondsFormat}; use log_fastly::Logger; pub(crate) fn target_label(target: &str) -> &str { - target.split("::").last().unwrap_or(target) + target + .rsplit_once("::") + .map_or(target, |(_, last)| if last.is_empty() { target } else { last }) } pub(crate) fn init_logger() { From 1acbfa7bde4c1e14c5618b7e4535f926c15f2f21 Mon Sep 17 00:00:00 2001 From: prk-Jr Date: Wed, 15 Apr 2026 20:56:03 +0530 Subject: [PATCH 11/11] Resolve PR review feedback on logging module --- .../src/logging.rs | 19 ++++++++++--------- .../2026-04-02-pr10-logging-initialization.md | 16 +++++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/crates/trusted-server-adapter-fastly/src/logging.rs b/crates/trusted-server-adapter-fastly/src/logging.rs index 59a05a01..3322677b 100644 --- a/crates/trusted-server-adapter-fastly/src/logging.rs +++ b/crates/trusted-server-adapter-fastly/src/logging.rs @@ -1,4 +1,4 @@ -use chrono::{Local, SecondsFormat}; +use chrono::{SecondsFormat, Utc}; use log_fastly::Logger; /// Extracts the final `::` segment from a Rust module path for use as a log label. @@ -6,11 +6,12 @@ use log_fastly::Logger; /// Falls back to the full target string when the input contains no separator or /// when the separator appears at the trailing position (e.g. `"foo::"`), which /// would otherwise produce an empty label in log output. -pub(crate) fn target_label(target: &str) -> &str { - target.rsplit_once("::").map_or( - target, - |(_, last)| if last.is_empty() { target } else { last }, - ) +fn target_label(target: &str) -> &str { + match target.rsplit_once("::") { + Some((head, "")) => head, + Some((_, last)) => last, + None => target, + } } /// Initialises the Fastly-backed `fern` logger and installs it as the global logger. @@ -34,7 +35,7 @@ pub(crate) fn init_logger() { .format(|out, message, record| { out.finish(format_args!( "{} {} [{}] {}", - Local::now().to_rfc3339_opts(SecondsFormat::Millis, true), + Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true), record.level(), target_label(record.target()), message @@ -69,8 +70,8 @@ mod tests { assert_eq!(target_label(""), "", "should handle empty strings"); assert_eq!( target_label("trailing::"), - "trailing::", - "should fall back to full target when segment after :: is empty" + "trailing", + "should strip separator when trailing segment is empty" ); } } diff --git a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md index d1fa2f57..d699df60 100644 --- a/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md +++ b/docs/superpowers/plans/2026-04-02-pr10-logging-initialization.md @@ -54,7 +54,7 @@ mod tests { Also add a production skeleton so the file compiles but the test fails: ```rust -pub(crate) fn target_label(target: &str) -> &str { +fn target_label(target: &str) -> &str { target } ``` @@ -74,13 +74,15 @@ Expected: FAIL because `target_label()` returns the full target instead of the f Replace the skeleton with the real adapter-local module: ```rust -use chrono::{Local, SecondsFormat}; +use chrono::{SecondsFormat, Utc}; use log_fastly::Logger; -pub(crate) fn target_label(target: &str) -> &str { - target - .rsplit_once("::") - .map_or(target, |(_, last)| if last.is_empty() { target } else { last }) +fn target_label(target: &str) -> &str { + match target.rsplit_once("::") { + Some((head, "")) => head, + Some((_, last)) => last, + None => target, + } } pub(crate) fn init_logger() { @@ -95,7 +97,7 @@ pub(crate) fn init_logger() { .format(|out, _message, record| { out.finish(format_args!( "{} {} [{}] {}", - Local::now().to_rfc3339_opts(SecondsFormat::Millis, true), + Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true), record.level(), target_label(record.target()), record.args()