feat(registry): add logging support for requests#12033
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds configurable logging: LogConfig/LogFormat/LogLevel types, Verdaccio 6 ChangesConfigurable logging system
Sequence DiagramsequenceDiagram
participant CLI as CLI (args)
participant Home as auto_config_path($HOME)
participant Resolve as Config::resolve
participant Main as main
participant Init as init_logging
participant Server as serve/startup
CLI->>Resolve: explicit --config path (optional)
Home->>Resolve: default config path (optional)
Resolve-->>Main: (Config, ConfigSource)
Main->>Init: config.logs (LogConfig)
Init-->>Main: tracing-subscriber initialized (EnvFilter + Formatter)
Main->>Server: start serve(config)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Micro-Benchmark ResultsLinux |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #12033 +/- ##
==========================================
+ Coverage 88.67% 88.74% +0.06%
==========================================
Files 233 234 +1
Lines 30073 30461 +388
==========================================
+ Hits 26668 27032 +364
- Misses 3405 3429 +24 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Integrated-Benchmark Report (Linux)Scenario: Isolated linker: fresh restore, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.0700676520399997,
"stddev": 0.08891899200323759,
"median": 2.0459550455399995,
"user": 2.7112134999999995,
"system": 3.2608514199999994,
"min": 1.95366549754,
"max": 2.2630550175399997,
"times": [
2.0583335135399996,
2.11963642354,
2.03357657754,
2.00282011954,
2.1035213905399996,
1.95366549754,
2.2630550175399997,
2.01864997154,
2.00996079754,
2.1374572115399997
]
},
{
"command": "pacquet@main",
"mean": 2.0448043389399997,
"stddev": 0.0523177495831333,
"median": 2.0499730015399997,
"user": 2.6946814999999997,
"system": 3.2546441199999996,
"min": 1.95793422454,
"max": 2.1423618945399996,
"times": [
1.95793422454,
2.0064212255399996,
2.02863894354,
2.1026129165399996,
2.1423618945399996,
2.05142693454,
2.0521042055399996,
1.99831776154,
2.0485190685399997,
2.05970621454
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.66998612386,
"stddev": 0.028774872134010965,
"median": 0.6600702015600001,
"user": 0.35937791999999996,
"system": 1.35821016,
"min": 0.65213161856,
"max": 0.7489665295600001,
"times": [
0.7489665295600001,
0.68051075456,
0.6605268065600001,
0.6614982515600001,
0.6646816775600001,
0.6588789605600001,
0.6596135965600001,
0.65740507256,
0.65213161856,
0.65564797056
]
},
{
"command": "pacquet@main",
"mean": 0.65283859846,
"stddev": 0.021723476738687346,
"median": 0.64625536606,
"user": 0.35642352,
"system": 1.34049666,
"min": 0.63787993556,
"max": 0.71210923556,
"times": [
0.71210923556,
0.64542278556,
0.6407318415600001,
0.64708794656,
0.65741953856,
0.64823939456,
0.65494578256,
0.63787993556,
0.64400824456,
0.6405412795600001
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.4019346663,
"stddev": 0.028715136782769553,
"median": 2.3983460292,
"user": 3.9241520999999993,
"system": 3.07587692,
"min": 2.3617811432,
"max": 2.4392884642,
"times": [
2.4392884642,
2.4261321872,
2.4121274572,
2.3839099702,
2.3617811432,
2.3797103232,
2.3716955062,
2.4227868762,
2.4373501342,
2.3845646011999997
]
},
{
"command": "pacquet@main",
"mean": 2.3969373866,
"stddev": 0.028728381979746517,
"median": 2.3906718477,
"user": 3.8782845999999993,
"system": 3.09932902,
"min": 2.3653666712,
"max": 2.4437966762,
"times": [
2.3653666712,
2.4206298142,
2.3761816492,
2.3694313732,
2.3753506922,
2.4051620462,
2.4305406452,
2.3719150362,
2.4109992622,
2.4437966762
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.5759644458400002,
"stddev": 0.020894809722881012,
"median": 1.57410871994,
"user": 1.75782946,
"system": 1.8801062199999996,
"min": 1.5452762509400002,
"max": 1.61336743494,
"times": [
1.58876858594,
1.59872142694,
1.61336743494,
1.57536358194,
1.57285385794,
1.54699723494,
1.57675864294,
1.57199440494,
1.5452762509400002,
1.56954303694
]
},
{
"command": "pacquet@main",
"mean": 1.59111956634,
"stddev": 0.04014609131190034,
"median": 1.58121404444,
"user": 1.75545486,
"system": 1.88558472,
"min": 1.55562789894,
"max": 1.69246186194,
"times": [
1.58242919594,
1.69246186194,
1.57999889294,
1.62075173994,
1.58865667394,
1.56065133594,
1.57568797194,
1.55562789894,
1.56418355494,
1.59074653694
]
}
]
} |
|
| Branch | pr/12033 |
| Testbed | pacquet |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 2,401.93 ms(+4.39%)Baseline: 2,300.90 ms | 2,761.08 ms (86.99%) |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 1,575.96 ms(+8.46%)Baseline: 1,452.99 ms | 1,743.59 ms (90.39%) |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 2,070.07 ms(+1.11%)Baseline: 2,047.31 ms | 2,456.77 ms (84.26%) |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 669.99 ms(+0.81%)Baseline: 664.59 ms | 797.51 ms (84.01%) |
739252a to
e61c61b
Compare
Review Summary by QodoAdd logging configuration and source tracking to pnpm-registry
WalkthroughsDescription• Add YAML-driven logging configuration with format and level support • Implement config source tracking (CLI, auto-discovered, or bundled) • Configure TraceLayer for structured per-request access logging • Add 11 unit tests covering YAML parsing, enum serde, and auto-discovery Diagramflowchart LR
A["Config Resolution"] -->|"CLI flag"| B["ConfigSource::Cli"]
A -->|"Auto-discovered path"| C["ConfigSource::DefaultPath"]
A -->|"Neither found"| D["ConfigSource::Bundled"]
B --> E["Config with LogConfig"]
C --> E
D --> E
E --> F["init_logging"]
F --> G["TraceLayer with<br/>format & level"]
File Changes1. registry/crates/pnpm-registry/src/config.rs
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds YAML-driven logging configuration and config auto-discovery to pnpm-registry, including structured per-request access logs.
Changes:
- Introduces
LogConfig/LogFormat/LogLeveland parseslog:from YAML with defaults. - Adds config auto-discovery (
~/.config/pnpm-registry/config.yaml) and config source reporting. - Reconfigures
tower_http::TraceLayerfor a single structured access record per request.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| registry/crates/pnpm-registry/src/server.rs | Customizes HTTP tracing to emit one access log event per request. |
| registry/crates/pnpm-registry/src/main.rs | Adds config resolution/auto-discovery and initializes tracing subscriber from YAML. |
| registry/crates/pnpm-registry/src/lib.rs | Re-exports new config/logging types. |
| registry/crates/pnpm-registry/src/config.rs | Adds logging config types, config source tracking, and auto-discovery/resolve helpers + tests. |
| registry/crates/pnpm-registry/config.yaml | Updates bundled YAML to verdaccio 6+ log: shape. |
| registry/crates/pnpm-registry/Cargo.toml | Adds home dependency and enables tracing-subscriber JSON feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
registry/crates/pnpm-registry/src/config.rs (1)
247-250: ⚡ Quick winUnsupported
log.typevalues are currently accepted silently.Line [249] parses
typeas a free-form string, and Line [490] drops it entirely. That meanstype: filelooks valid but still runs stdout logging. Consider validatingtype(e.g., enum with onlystdout) so unsupported sinks fail fast.Also applies to: 488-490
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@registry/crates/pnpm-registry/src/config.rs` around lines 247 - 250, The config currently stores r#type as a free-form String (field r#type) and silently ignores unsupported values; change it to a constrained enum (e.g., enum LogType { Stdout }) deriving Deserialize and Default (use the existing default_log_type to return LogType::Stdout) so serde enforces allowed values, update the struct field type from String to LogType, and replace the place that currently drops the value (the code handling r#type around the earlier config usage) to match on LogType and error/return early on unsupported variants instead of defaulting silently; ensure serde rename/escape for "type" (r#type) stays in place so deserialization still maps correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@registry/crates/pnpm-registry/src/config.rs`:
- Around line 78-81: Update the stale documentation on the Config struct and its
LogConfig usage to reflect that the runtime parses a singular "log:" entry (not
a legacy "logs:" list) and that the value is sourced from that single "log:"
key; edit the doc comments for the pub logs: LogConfig field and the related
comment block (previously referencing "first entry of the YAML `logs:` list") to
say it reads the singular `log:` key and defaults to pretty/info, so the
comments align with the current parsing behavior of the code.
In `@registry/crates/pnpm-registry/src/main.rs`:
- Around line 73-74: The JSON logger configuration currently disables embedding
the current span and span list (LogFormat::Json uses
builder.json().with_current_span(false).with_span_list(false).init()), which
drops request span fields (e.g., method/uri added by tower-http/TraceLayer);
change the JSON formatter to include span context by enabling the current span
and span list (remove the false flags or set them to true on builder.json()) so
span fields attached to request spans are emitted in JSON logs.
In `@registry/crates/pnpm-registry/src/server.rs`:
- Around line 114-117: The access log events emitted by TraceLayer.on_response
currently use DefaultOnResponse which doesn't set the tracing target, so the
`pnpm_registry::access=info` directive is ignored; update the
TraceLayer.on_response call to configure the response handler to emit with
target "pnpm_registry::access" (e.g., call the API on DefaultOnResponse used in
on_response to set the target to "pnpm_registry::access" or replace it with a
handler that sets target to that string), keeping the same level and
latency_unit settings and leaving on_failure as-is.
---
Nitpick comments:
In `@registry/crates/pnpm-registry/src/config.rs`:
- Around line 247-250: The config currently stores r#type as a free-form String
(field r#type) and silently ignores unsupported values; change it to a
constrained enum (e.g., enum LogType { Stdout }) deriving Deserialize and
Default (use the existing default_log_type to return LogType::Stdout) so serde
enforces allowed values, update the struct field type from String to LogType,
and replace the place that currently drops the value (the code handling r#type
around the earlier config usage) to match on LogType and error/return early on
unsupported variants instead of defaulting silently; ensure serde rename/escape
for "type" (r#type) stays in place so deserialization still maps correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 252f81e7-216d-4bb5-86f4-f61514e5eeac
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (6)
registry/crates/pnpm-registry/Cargo.tomlregistry/crates/pnpm-registry/config.yamlregistry/crates/pnpm-registry/src/config.rsregistry/crates/pnpm-registry/src/lib.rsregistry/crates/pnpm-registry/src/main.rsregistry/crates/pnpm-registry/src/server.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Lint and Test (windows-latest)
- GitHub Check: Code Coverage
- GitHub Check: Run benchmark on ubuntu-latest
🧰 Additional context used
📓 Path-based instructions (3)
registry/crates/**/*.rs
📄 CodeRabbit inference engine (registry/AGENTS.md)
Follow the pacquet code-style guide (../pacquet/CODE_STYLE_GUIDE.md) for Rust-level conventions including imports, naming, ownership, error handling, and test layout
Files:
registry/crates/pnpm-registry/src/lib.rsregistry/crates/pnpm-registry/src/server.rsregistry/crates/pnpm-registry/src/main.rsregistry/crates/pnpm-registry/src/config.rs
registry/crates/**/Cargo.toml
📄 CodeRabbit inference engine (registry/AGENTS.md)
registry/crates/**/Cargo.toml: When using existing pacquet-* crates, declare them in the root [workspace.dependencies] and use { workspace = true } in the crate's Cargo.toml
New registry-only crates must be placed under registry/crates// and named pnpm-registry- in Cargo.toml, with the package name using the pnpm-registry- prefix exclusively
Do not reach for the pacquet- prefix to name new registry-side crates; use pnpm-registry- prefix exclusively for registry-only crates
Files:
registry/crates/pnpm-registry/Cargo.toml
registry/**/Cargo.toml
📄 CodeRabbit inference engine (registry/AGENTS.md)
Add new registry-only crates to [workspace.dependencies] at the root with the pnpm-registry- prefix so other crates can use { workspace = true }
Files:
registry/crates/pnpm-registry/Cargo.toml
🔇 Additional comments (6)
registry/crates/pnpm-registry/src/config.rs (1)
375-415: LGTM!Also applies to: 830-1194
registry/crates/pnpm-registry/Cargo.toml (1)
30-30: LGTM!Also applies to: 43-43
registry/crates/pnpm-registry/config.yaml (1)
69-73: LGTM!registry/crates/pnpm-registry/src/lib.rs (1)
24-25: LGTM!registry/crates/pnpm-registry/src/main.rs (1)
44-51: LGTM!Also applies to: 58-60, 78-88
registry/crates/pnpm-registry/src/server.rs (1)
11-13: LGTM!Also applies to: 102-113
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@registry/crates/pnpm-registry/src/server.rs`:
- Line 109: Update the schema reference string in the server.rs comment from
"logs:" to the singular "log:" so docs match the parser; find the comment
containing the phrase "`logs:` block — pretty or NDJSON)" and change it to
"`log:` block — pretty or NDJSON)" (ensure any adjacent documentation or test
strings that reference `logs:` are also updated to `log:` to avoid drift with
the runtime parser).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4b63a395-16b2-47bd-8738-f49b63e5f4a5
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (6)
registry/crates/pnpm-registry/Cargo.tomlregistry/crates/pnpm-registry/config.yamlregistry/crates/pnpm-registry/src/config.rsregistry/crates/pnpm-registry/src/lib.rsregistry/crates/pnpm-registry/src/main.rsregistry/crates/pnpm-registry/src/server.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
registry/crates/**/Cargo.toml
📄 CodeRabbit inference engine (registry/AGENTS.md)
registry/crates/**/Cargo.toml: When using existing pacquet-* crates, declare them in the root [workspace.dependencies] and use { workspace = true } in the crate's Cargo.toml
New registry-only crates must be placed under registry/crates// and named pnpm-registry- in Cargo.toml, with the package name using the pnpm-registry- prefix exclusively
Do not reach for the pacquet- prefix to name new registry-side crates; use pnpm-registry- prefix exclusively for registry-only crates
Files:
registry/crates/pnpm-registry/Cargo.toml
registry/**/Cargo.toml
📄 CodeRabbit inference engine (registry/AGENTS.md)
Add new registry-only crates to [workspace.dependencies] at the root with the pnpm-registry- prefix so other crates can use { workspace = true }
Files:
registry/crates/pnpm-registry/Cargo.toml
registry/crates/**/*.rs
📄 CodeRabbit inference engine (registry/AGENTS.md)
Follow the pacquet code-style guide (../pacquet/CODE_STYLE_GUIDE.md) for Rust-level conventions including imports, naming, ownership, error handling, and test layout
Files:
registry/crates/pnpm-registry/src/server.rsregistry/crates/pnpm-registry/src/lib.rsregistry/crates/pnpm-registry/src/main.rsregistry/crates/pnpm-registry/src/config.rs
🔇 Additional comments (8)
registry/crates/pnpm-registry/src/config.rs (2)
78-81: Doc comments still describe legacylogs:list behavior.Line [79] and Line [137] still describe the runtime as reading the first entry of a
logs:list, but parsing now uses singularlog:. This is stale and can mislead future changes.Also applies to: 136-144
18-31: LGTM!Also applies to: 151-200, 237-242, 284-315, 320-331, 375-414, 426-442, 485-491, 537-542, 830-1195
registry/crates/pnpm-registry/src/main.rs (2)
73-74: JSON formatter currently strips span context needed by access logs.Line [73] disables current span/span list, which can drop request-span fields (for example method/URI) from JSON access events.
In tracing-subscriber 0.3 JSON formatting, do with_current_span(false) and with_span_list(false) prevent request span fields from appearing in emitted events?
2-60: LGTM!Also applies to: 63-72, 75-76, 78-88
registry/crates/pnpm-registry/src/server.rs (1)
114-117: Access event target may not matchpnpm_registry::accessfiltering intent.
DefaultOnResponseemits its own event without an explicit custom target, so thepnpm_registry::access=...directive may not control these records as intended.In tower-http 0.6, does DefaultOnResponse emit events with a configurable/custom tracing target by default, or is a custom on_response closure required to set target = "pnpm_registry::access"?registry/crates/pnpm-registry/Cargo.toml (1)
30-30: LGTM!Also applies to: 43-43
registry/crates/pnpm-registry/config.yaml (1)
69-73: LGTM!registry/crates/pnpm-registry/src/lib.rs (1)
24-25: LGTM!
88bea45 to
979d8de
Compare
|
Actionable comments posted: 0 |
|
Actionable comments posted: 0 |
|
Actionable comments posted: 0 |
1 similar comment
|
Actionable comments posted: 0 |
resolve_cli_wins_over_default_path test
- route the per-request span and event through the pnpm_registry::access target so LogLevel::Http's filter directive actually scopes to them - keep method/uri attached to JSON access records (with_current_span) - warn at startup when log.type names an unimplemented sink - carry the config path in from_yaml read errors - correct stale logs:/log: docs to the Verdaccio 6+ singular shape
… pnpr
Extract pnpm's getConfigDir port into a new dependency-free
pacquet-config-dir crate, parameterized by app-name leaf. pacquet-config's
default_config_dir delegates to it ("pnpm"); pnpm-registry's auto-discovery
uses it ("pnpr") so the registry's global config follows the same per-OS
rules as pnpm's own config dir. The home lookup is passed as a thunk to
preserve the env-var short-circuit.
Use raw strings for Windows paths (prefer-raw-string) and drop the redundant app-name leaf test whose long assert! lines tripped macro-trailing-comma.
45edf89 to
9e4e5f6
Compare
Summary
Adds YAML-driven logging to
pnpm-registry. Format (prettyorjson) and level come from alog:block inconfig.yaml. Every HTTP request emits one structured access record (method, URI, status, latency) under thepnpm_registry::accesstracing target — pino-shaped. When-cisn't passed, the globalconfig.yamlis auto-discovered using the same per-OS rules pnpm uses for its own config dir, under apnprleaf.What's in
LogConfig/LogFormat/LogLeveltypes; defaults to pretty/info.init_loggingpicks.json()vs.compact()from the resolved config;RUST_LOGstill overrides. JSON keeps the request span'smethod/urion each access record (with_current_span(true)).TraceLayeremits exactly one INFO access record per request — both the span and the completion event undertarget: "pnpm_registry::access", with tower-http's default emissions suppressed — soLogLevel::Http's filter directive can scope to them.getConfigDirrules (XDG_CONFIG_HOME/ macOSLibrary/Preferences/ WindowsLOCALAPPDATA/~/.config) under apnprleaf. That resolution is shared withpacquet-configvia a new dependency-freepacquet-config-dircrate, parameterized by app-name leaf.log:, singular). The older plurallogs:is silently ignored.log.typevalues other thanstdoutparse (verdaccio compatibility) but are ignored at runtime with a startup warning; onlystdoutis implemented.Notes
pacquet-config-dir(std-only, used by bothpacquet-configandpnpm-registry). Newpnpm-registrydeps:homeandtracing-subscriber'sjsonfeature — both already in[workspace.dependencies].Ref: #11973
Test plan
pnpr/pnpmconfig-dir branches (XDG / macOS / Windows / Linux), config-file existence gating, and the unsupported-sink path.cargo fmt --check,cargo clippy --deny warnings,cargo dylint(perfectionist), andcargo doc -D warningsclean across the workspace.Written by an agent (Claude Code, claude-opus-4-8).
Summary by CodeRabbit
New Features
Chores
log:style and improved runtime log-level/format handling with RUST_LOG fallback.