bee/debug/loggers.rs
1//! `/loggers` endpoints — list, query by expression, set verbosity.
2//! Mirrors bee-go's `pkg/debug/loggers.go`.
3
4use base64::Engine;
5use base64::engine::general_purpose::URL_SAFE;
6use reqwest::Method;
7use serde::Deserialize;
8
9use crate::client::request;
10use crate::swarm::Error;
11
12use super::DebugApi;
13
14/// Verbosity levels accepted by Bee's `PUT /loggers/{exp}/{verbosity}`
15/// route (`pkg/api/logger.go`). Anything outside this set is rejected
16/// by Bee with a 400.
17pub const LOG_LEVELS: &[&str] = &["none", "error", "warning", "info", "debug", "all"];
18
19/// One logger row in [`LoggerListing`].
20#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
21pub struct Logger {
22 /// Fully qualified logger name.
23 pub logger: String,
24 /// Verbosity level (`"info"`, `"debug"`, `"warning"`, …).
25 pub verbosity: String,
26 /// Subsystem the logger belongs to.
27 pub subsystem: String,
28 /// Stable logger ID (base64).
29 pub id: String,
30}
31
32/// `GET /loggers` and `GET /loggers/{expr}` response. The `tree`
33/// payload is recursive and rarely needed — it is preserved as a raw
34/// JSON value.
35#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
36pub struct LoggerListing {
37 /// Recursive logger tree as raw JSON.
38 #[serde(default)]
39 pub tree: serde_json::Value,
40 /// Flat list of registered loggers.
41 #[serde(default)]
42 pub loggers: Vec<Logger>,
43}
44
45impl DebugApi {
46 /// `GET /loggers` — every logger registered in the running node.
47 pub async fn loggers(&self) -> Result<LoggerListing, Error> {
48 let builder = request(&self.inner, Method::GET, "loggers")?;
49 self.inner.send_json(builder).await
50 }
51
52 /// `GET /loggers/{base64url(expression)}` — loggers matching the
53 /// regex / subsystem expression. The expression is base64url
54 /// (padded) encoded per the Bee `/loggers/{exp}` contract.
55 pub async fn loggers_by_expression(&self, expression: &str) -> Result<LoggerListing, Error> {
56 let enc = URL_SAFE.encode(expression.as_bytes());
57 let path = format!("loggers/{enc}");
58 let builder = request(&self.inner, Method::GET, &path)?;
59 self.inner.send_json(builder).await
60 }
61
62 /// `PUT /loggers/{base64url(expression)}/{verbosity}` — set the
63 /// verbosity of every logger matching `expression`. `verbosity`
64 /// must be one of [`LOG_LEVELS`] (`none|error|warning|info|debug|
65 /// all`); anything else is rejected client-side with
66 /// [`Error::Argument`] before the request is built.
67 ///
68 /// Example: `set_logger("node/pushsync", "debug")` raises the
69 /// pushsync subsystem to debug verbosity. To bump every logger
70 /// at once, pass `"."` (Bee treats it as a regex match-all).
71 pub async fn set_logger(&self, expression: &str, verbosity: &str) -> Result<(), Error> {
72 if !LOG_LEVELS.contains(&verbosity) {
73 return Err(Error::argument(format!(
74 "verbosity {verbosity:?} not in {LOG_LEVELS:?}"
75 )));
76 }
77 let enc = URL_SAFE.encode(expression.as_bytes());
78 let path = format!("loggers/{enc}/{verbosity}");
79 let builder = request(&self.inner, Method::PUT, &path)?;
80 self.inner.send(builder).await?;
81 Ok(())
82 }
83
84 /// **Deprecated, broken method.** Bee's actual route is
85 /// `PUT /loggers/{exp}/{verbosity}` — verbosity is **mandatory**
86 /// in the path, but this method emits `PUT /loggers/{exp}` which
87 /// 404s on every real Bee build. Always returned 404 against a
88 /// live node; only ever "succeeded" against mock servers wired
89 /// to the wrong path.
90 ///
91 /// Use [`DebugApi::set_logger`] instead — it takes both the
92 /// expression and verbosity and emits the correct path.
93 #[deprecated(
94 since = "1.6.0",
95 note = "broken — emits the wrong path. Use `set_logger(expr, verbosity)` instead."
96 )]
97 pub async fn set_logger_verbosity(&self, _expression: &str) -> Result<(), Error> {
98 Err(Error::argument(
99 "set_logger_verbosity is broken — Bee's route requires a verbosity component. \
100 Call set_logger(expression, verbosity) instead.",
101 ))
102 }
103}