mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-09-14 04:45:07 +00:00
fix(logging): scope bare levels to the application
Production NGIT_LOG_LEVEL=info currently enables INFO records from every dependency as well as ngit-grasp, obscuring application health with SDK and protocol chatter. Expand bare levels into an explicit warn dependency baseline plus the requested ngit_grasp level. Preserve full EnvFilter expressions verbatim so operators retain precise temporary diagnostics, and document the severity contract consistently across source, NixOS, the environment example, and reference material. This commit deliberately does not reclassify individual application call sites; those changes remain separately reviewable. Validated with cargo fmt --check and the focused logging unit tests (4 passed).
This commit is contained in:
+2
-1
@@ -116,10 +116,11 @@
|
||||
# LOGGING
|
||||
# ============================================================================
|
||||
|
||||
# Log level for application logging
|
||||
# Application log level or explicit tracing filter expression
|
||||
# CLI: --log-level <level>
|
||||
# Default: info
|
||||
# Options: error, warn, info, debug, trace
|
||||
# Bare levels keep dependency logging at warn
|
||||
# Can also use filter expressions: ngit_grasp=debug,actix_web=info
|
||||
# NGIT_LOG_LEVEL=info
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Scope bare log levels to ngit-grasp while keeping dependencies at warnings;
|
||||
explicit tracing filter expressions remain unchanged.
|
||||
- Metrics compatibility: removed the
|
||||
`ngit_sync_naughty_relay_info{relay,category,reason}` metric because its relay
|
||||
and raw reason labels were peer-controlled and unbounded. Use the unchanged
|
||||
|
||||
@@ -50,6 +50,24 @@ flowchart TB
|
||||
| Abuse threshold | `--abuse-threshold` | `NGIT_ABUSE_THRESHOLD` | `10` | Max connections per IP before flagging |
|
||||
| Top N repos | `--top-n-repos` | `NGIT_TOP_N_REPOS` | `10` | Number of top bandwidth repos to track |
|
||||
|
||||
## Logging severity policy
|
||||
|
||||
Operational logging classifies records by who can act on them:
|
||||
|
||||
- `error` identifies an internal, persistence, or process failure that may
|
||||
require an operator response.
|
||||
- `warn` identifies a degraded application path, bounded retry, or cooldown
|
||||
that affects service behavior but remains recoverable.
|
||||
- `info` records application lifecycle, aggregate batch outcomes, and durable
|
||||
state transitions.
|
||||
- `debug` carries individual client, peer, event, filter, and capability
|
||||
negotiation details. Invalid or unsupported remote input is expected on a
|
||||
public relay and is not operator-actionable by itself.
|
||||
|
||||
For a bare `NGIT_LOG_LEVEL`, dependencies remain at `warn` while the selected
|
||||
level applies to ngit-grasp. Use an explicit tracing filter expression when a
|
||||
dependency needs temporary diagnostics.
|
||||
|
||||
## Privacy Model
|
||||
|
||||
IP addresses are **never exposed in Prometheus metrics**. The connection tracker maintains per-IP counts internally only for abuse detection:
|
||||
|
||||
@@ -1586,7 +1586,7 @@ equivalent standard NIP-11 field, so it remains documented configuration only.
|
||||
|
||||
#### `NGIT_LOG_LEVEL`
|
||||
|
||||
**Description:** Logging level and filters for application logging
|
||||
**Description:** Application logging level or explicit tracing filter expression
|
||||
**Type:** String (log level or filter expression)
|
||||
**Default:** `info`
|
||||
**Required:** No
|
||||
@@ -1595,11 +1595,11 @@ equivalent standard NIP-11 field, so it remains documented configuration only.
|
||||
|
||||
```bash
|
||||
# Simple levels
|
||||
NGIT_LOG_LEVEL=error # Errors only
|
||||
NGIT_LOG_LEVEL=warn # Warnings and errors
|
||||
NGIT_LOG_LEVEL=info # Info, warnings, errors (default)
|
||||
NGIT_LOG_LEVEL=debug # Debug and above
|
||||
NGIT_LOG_LEVEL=trace # Everything (very verbose)
|
||||
NGIT_LOG_LEVEL=error # ngit-grasp errors; dependency warnings and errors
|
||||
NGIT_LOG_LEVEL=warn # ngit-grasp warnings and errors; dependency warnings and errors
|
||||
NGIT_LOG_LEVEL=info # ngit-grasp info and above; dependency warnings and errors (default)
|
||||
NGIT_LOG_LEVEL=debug # ngit-grasp debug and above; dependency warnings and errors
|
||||
NGIT_LOG_LEVEL=trace # ngit-grasp trace and above; dependency warnings and errors
|
||||
|
||||
# Module-specific filtering
|
||||
NGIT_LOG_LEVEL=ngit_grasp=debug,actix_web=info
|
||||
@@ -1608,6 +1608,11 @@ NGIT_LOG_LEVEL=ngit_grasp=debug,actix_web=info
|
||||
NGIT_LOG_LEVEL=debug,hyper=info,tokio=warn
|
||||
```
|
||||
|
||||
Bare levels are expanded to `warn,ngit_grasp=<level>` so application
|
||||
diagnostics do not also enable verbose internals from every dependency.
|
||||
Expressions containing target directives or commas are passed through
|
||||
unchanged, leaving dependency verbosity under explicit operator control.
|
||||
|
||||
**Log levels (most to least verbose):**
|
||||
|
||||
1. `trace` - Very detailed, performance impact
|
||||
@@ -1631,6 +1636,7 @@ NGIT_LOG_LEVEL=info
|
||||
**Notes:**
|
||||
|
||||
- Uses Rust's `tracing` crate filter syntax
|
||||
- Bare levels apply to ngit-grasp while dependencies remain at `warn`
|
||||
- Supports module-level filtering (e.g., `ngit_grasp=debug,hyper=info`)
|
||||
- `trace` level can significantly impact performance
|
||||
- For production, `info` or `warn` is recommended
|
||||
|
||||
+2
-1
@@ -204,7 +204,8 @@ let
|
||||
default = "info";
|
||||
example = "debug";
|
||||
description = ''
|
||||
Logging level for application logging.
|
||||
Application logging level or explicit tracing filter expression.
|
||||
Bare levels keep dependency logging at warn.
|
||||
Can be a simple level (trace, debug, info, warn, error) or a filter expression.
|
||||
Examples: "info", "debug", "ngit_grasp=debug,actix_web=info"
|
||||
'';
|
||||
|
||||
+2
-1
@@ -679,7 +679,8 @@ pub struct Config {
|
||||
#[arg(long, env = "NGIT_RELAY_FILTER_LIMIT", default_value_t = 500)]
|
||||
pub relay_filter_limit: usize,
|
||||
|
||||
/// Log level for application logging
|
||||
/// Application log level or an explicit tracing filter expression.
|
||||
/// Bare levels keep dependency logging at warn.
|
||||
#[arg(long, env = "NGIT_LOG_LEVEL", default_value = "info")]
|
||||
pub log_level: String,
|
||||
}
|
||||
|
||||
+40
-1
@@ -6,6 +6,26 @@ use tracing_subscriber::layer::{Context, Filter};
|
||||
const LOCAL_RELAY_TARGET: &str = "nostr_sdk::local_relay::local::inner";
|
||||
const UNCLEAN_RESET: &str = "WebSocket protocol error: Connection reset without closing handshake";
|
||||
|
||||
/// Expand a bare application level into an explicit `EnvFilter` directive.
|
||||
///
|
||||
/// `NGIT_LOG_LEVEL` is documented as the application log level. Applying a
|
||||
/// bare level directly to `EnvFilter` also enables every dependency at that
|
||||
/// level, which makes ordinary `info` deployments inherit verbose SDK and
|
||||
/// protocol diagnostics. Keep dependencies at warnings for bare levels while
|
||||
/// preserving explicit operator-authored filter expressions verbatim.
|
||||
pub fn effective_log_filter(configured: &str) -> String {
|
||||
let trimmed = configured.trim();
|
||||
let level = trimmed.to_ascii_lowercase();
|
||||
if matches!(
|
||||
level.as_str(),
|
||||
"trace" | "debug" | "info" | "warn" | "error" | "off"
|
||||
) {
|
||||
format!("warn,ngit_grasp={level}")
|
||||
} else {
|
||||
configured.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Suppresses the routine unclean-disconnect event emitted by the embedded relay.
|
||||
///
|
||||
/// Internet clients commonly disappear without completing the WebSocket close
|
||||
@@ -56,7 +76,26 @@ fn is_routine_disconnect_message(message: &str) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::is_routine_disconnect_message;
|
||||
use super::{effective_log_filter, is_routine_disconnect_message};
|
||||
|
||||
#[test]
|
||||
fn bare_levels_scope_verbose_output_to_ngit_grasp() {
|
||||
assert_eq!(effective_log_filter("debug"), "warn,ngit_grasp=debug");
|
||||
assert_eq!(effective_log_filter(" INFO "), "warn,ngit_grasp=info");
|
||||
assert_eq!(effective_log_filter("off"), "warn,ngit_grasp=off");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_filter_expressions_remain_operator_controlled() {
|
||||
assert_eq!(
|
||||
effective_log_filter("ngit_grasp=debug,nostr_sdk=info"),
|
||||
"ngit_grasp=debug,nostr_sdk=info"
|
||||
);
|
||||
assert_eq!(
|
||||
effective_log_filter("debug,hyper=info,tokio=warn"),
|
||||
"debug,hyper=info,tokio=warn"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn identifies_reset_without_close_handshake() {
|
||||
|
||||
+11
-4
@@ -7,7 +7,10 @@ use tracing::info;
|
||||
use tracing_subscriber::{filter::FilterExt, layer::SubscriberExt, EnvFilter, Layer};
|
||||
|
||||
use ngit_grasp::{
|
||||
cleanup_empty_repos, config::Config, logging::SuppressRoutineDisconnects, nostr,
|
||||
cleanup_empty_repos,
|
||||
config::Config,
|
||||
logging::{effective_log_filter, SuppressRoutineDisconnects},
|
||||
nostr,
|
||||
server::RelayServer,
|
||||
};
|
||||
|
||||
@@ -70,8 +73,8 @@ async fn main() -> Result<()> {
|
||||
/// this function only owns concerns specific to the standalone binary:
|
||||
/// the global tracing subscriber and signal handling.
|
||||
async fn run_relay(config: Config) -> Result<()> {
|
||||
// Initialize tracing with configured log level
|
||||
let filter = EnvFilter::new(&config.log_level).and(SuppressRoutineDisconnects);
|
||||
let effective_filter = effective_log_filter(&config.log_level);
|
||||
let filter = EnvFilter::new(&effective_filter).and(SuppressRoutineDisconnects);
|
||||
// Only colorize when stdout is a terminal: ANSI escape codes in redirected
|
||||
// logs corrupt journald/file output and break log-scraping consumers.
|
||||
let subscriber = tracing_subscriber::registry().with(
|
||||
@@ -81,7 +84,11 @@ async fn run_relay(config: Config) -> Result<()> {
|
||||
);
|
||||
tracing::subscriber::set_global_default(subscriber)?;
|
||||
|
||||
info!("Starting ngit-grasp with log level: {}", config.log_level);
|
||||
info!(
|
||||
configured_log_level = %config.log_level,
|
||||
effective_log_filter = %effective_filter,
|
||||
"Starting ngit-grasp"
|
||||
);
|
||||
|
||||
let server = RelayServer::start(config).await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user