Skip to main content

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}