# swarm-debug — OpenSwarm's logger for App backends `swarm_debug` (also importable as `debug` for legacy reasons) is OpenSwarm's opinionated `print()` replacement for the App Builder's backend code. It prints colored, indented, frame-aware log lines that read at a glance and land in the App Builder's **Terminal** tab under the `[BACKEND]` prefix. It's pre-installed in every App Builder workspace that has a backend (i.e. after `bash backend_init.sh`). Use it instead of `print()`. --- ## Basic usage ```python from swarm_debug import debug debug("hello") # [endpoint_name] : hello debug({"user_id": 42, "ok": True}) # [endpoint_name] : {'user_id': 42, 'ok': True} debug(some_dataframe) # auto-truncated to 3000 chars ``` The function reads the **calling line of source code** to extract the variable name(s), so: ```python result = compute_thing(input_data) debug(result) # prints: [my_endpoint] : result = {'sum': 42, 'rows': [...]} ``` Variable name is inferred from the AST of the line that called `debug()`. If you pass a literal (string, number, raw dict), it just prints the value. --- ## Multiple args Pass several values in one call — each is labeled separately: ```python debug(user_id, request.body, response.status_code) # [endpoint_name] : user_id = 42 # [endpoint_name] : request.body = {...} # [endpoint_name] : response.status_code = 200 ``` --- ## Calling from inside a class `swarm_debug` introspects the caller's frame, so methods on a class print under `ClassName.method` instead of just `method`: ```python class JobService: def fetch(self, query): debug(query) # [JobService.fetch] : query = "machine learning engineer" ``` Indentation also scales with the call's lexical depth so nested-loop debugging stays readable: ```python for batch in batches: debug(batch.id) # |\t[fn] : batch.id = 1 for item in batch.items: debug(item) # |\t |-- [fn] : item = {...} ``` --- ## Error highlighting Pass an `Exception` (or a name containing `err`/`error`) and `swarm_debug` flips the color to red + prefixes a ❌ emoji so the error stands out in the Terminal pane: ```python try: risky_thing() except Exception as err: debug(err) # ❌ [endpoint_name] : err = ValueError("bad input") ``` --- ## Long values are truncated By default `swarm_debug` cuts values longer than 3000 characters with a `…\n…` separator in the middle. Override per-call: ```python debug(huge_payload, override_max_chars=True) ``` --- ## Modes (custom log levels) `debug` accepts a `mode` kwarg that maps to a configurable log channel. Default is `'debug'`. The Terminal pane shows all modes; if you want to hide a category, configure it in `Debugleton` (see `debugger_backend/`). ```python debug(payload, mode='info') debug(suspicious_input, mode='warning') ``` --- ## When to use `print()` instead Don't. `swarm_debug.debug()` IS the answer for backend logging. Reasons: - `print()` doesn't show the variable name or class/function context. - `print()` doesn't truncate huge payloads. - `print()` doesn't color-code errors. - `print()` writes raw stdout, which is harder to scan in the Terminal pane when the agent is also running and producing output. `print()` is fine for human-only one-off scripts the agent runs via Bash — not for endpoint code. --- ## What NOT to do - **Don't call `debug()` inside a hot loop** without a guard — every call reads the source file to extract variable names, which gets expensive at 10k+ iterations. - **Don't pass functions / class objects** expecting useful output — you'll get something like ``. Call the function or stringify intentionally. - **Don't rely on `debug()` for production logging.** It's a development aid. For structured server logs that survive past the App Builder session, use `logging` from the standard library. --- ## How it lands in the Terminal tab Every line `debug()` prints goes to stdout/stderr of your backend subprocess. The App Builder's runtime captures both streams, prefixes each line with `[BACKEND]`, and streams them via WebSocket into the Terminal pane in real time. Frontend `console.log` calls in the running app land in the same Terminal pane prefixed `[FRONTEND]`. Use this to correlate cause and effect across the two halves of your stack. --- ## Quick reference | Want to… | Do this | |---|---| | Log a value with auto-inferred name | `debug(value)` | | Log several values in one call | `debug(a, b, c)` | | Log an exception with red coloring | `debug(err)` (variable name must contain "err" or "error", or pass an `Exception` instance) | | Avoid truncation | `debug(value, override_max_chars=True)` | | Use a different log channel | `debug(value, mode='info')` | | Same thing, legacy import | `import debug; debug(value)` (function and module share the name — see swarm_debug.py shim) |