Skip to content

Commit a3bcd3f

Browse files
committed
feat: write portal log files
1 parent 37e4f43 commit a3bcd3f

File tree

11 files changed

+191
-24
lines changed

11 files changed

+191
-24
lines changed

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AGENT_PORTAL_HOST_GH=$HOME/.nix-profile/bin/gh

.envrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
use flake
22
export PATH=$PWD/target/debug:$PATH
3+
dotenv

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/target
22
demo.gif
33
result
4-
.direnv/
4+
.direnv/
5+
.env

ab/src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ fn maybe_start_managed_portal(
3535
return Ok(None);
3636
}
3737

38+
let socket_path = per_container_portal_socket_path();
39+
let log_path = agent_portal::logging::init(None, Some(&socket_path), false)?;
40+
eprintln!("managed portal log file: {}", log_path.display());
41+
3842
Ok(Some(agent_portal::host::spawn_managed(
3943
config.portal.clone(),
40-
per_container_portal_socket_path(),
44+
socket_path,
4145
)?))
4246
}
4347

docs/src/how-to/portal/debug-wrapper-failures.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,20 @@ Find and fix common failures for `wl-paste`/`gh` wrappers and other Portal clien
2020
```bash
2121
echo "$AGENT_PORTAL_SOCKET"
2222
```
23-
4. Enable host logs:
23+
4. Enable host logging with `RUST_LOG`:
2424
```bash
25-
RUST_LOG=debug agent-portal-host
25+
RUST_LOG=agent_portal=debug,agent_portal_host=trace agent-portal-host
2626
```
27+
When `agent-portal-host` is run directly, logs are visible in the terminal and also written to the log file. Managed hosts started by `ab spawn` log only to files.
28+
5. Inspect the log file:
29+
- Log files live under:
30+
```text
31+
${XDG_STATE_HOME:-$HOME/.local/state}/agent-box/logs/
32+
```
33+
- The log filename matches the socket filename, with `.sock` replaced by `.log`.
34+
- Example: `portal.sock` -> `portal.log`
35+
- In managed per-container mode (`[portal].global = false`), each spawned socket gets its own matching log file.
36+
- Use `RUST_LOG=debug ab spawn ...` if you want more verbose managed-host logs.
2737

2838
## Common failures
2939

docs/src/reference/common/env-vars.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
- `RUST_LOG`
1515
- Controls tracing filter for `agent-portal-host` and other Rust binaries using tracing subscriber.
1616

17+
- `XDG_STATE_HOME`
18+
- Used to resolve the default Portal log directory.
19+
- Default Portal log directory: `$XDG_STATE_HOME/agent-box/logs/`
20+
- Fallback when unset: `~/.local/state/agent-box/logs/`
21+
- Each Portal log filename is derived from the socket filename, replacing `.sock` with `.log`
22+
1723
## Runtime passthrough
1824

1925
Variables listed in `[runtime].env_passthrough` are copied from host into container at spawn time.

docs/src/reference/portal/config.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ Portal config lives under `[portal]` in `~/.agent-box.toml`.
1212
- used directly when `global = true`
1313
- ignored by `ab spawn` when `global = false`, because `ab` allocates a unique per-container socket path
1414
- `prompt_command` (string|null, default: unset)
15+
- Logging is controlled at process startup, not in config:
16+
- `RUST_LOG=...` provides tracing filter control
17+
- logs are written under `${XDG_STATE_HOME:-~/.local/state}/agent-box/logs/`
18+
- each log filename is derived from the socket filename, replacing `.sock` with `.log`
1519
- `timeouts.request_ms` (u64, default: `0` = no timeout)
1620
- `timeouts.prompt_ms` (u64, default: `0` = no timeout)
1721
- `limits.max_inflight` (usize, default: `32`)

portal/README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,33 @@ Policy mode is configured in `~/.agent-box.toml` via `portal.policy.defaults.gh_
2525

2626
## Logging
2727

28-
`agent-portal-host` uses `tracing` + `RUST_LOG` filtering.
28+
`agent-portal-host` uses `tracing` and writes logs to stderr and a log file when run directly. Managed per-container Portal instances started by `ab spawn` write logs only to files.
29+
30+
Default log file location:
31+
32+
```text
33+
${XDG_STATE_HOME:-~/.local/state}/agent-box/logs/<socket-name>.log
34+
```
35+
36+
The log filename is derived from the socket filename by replacing `.sock` with `.log`.
37+
38+
Examples:
39+
40+
```text
41+
portal.sock -> portal.log
42+
portal-12345-abc.sock -> portal-12345-abc.log
43+
```
44+
45+
Use `RUST_LOG` for tracing filter control.
2946

3047
Example:
3148

3249
```bash
33-
RUST_LOG=debug agent-portal-host
50+
RUST_LOG=agent_portal=debug,agent_portal_host=trace agent-portal-host
3451
```
3552

53+
Managed per-container Portal instances started by `ab spawn` also initialize logging this way, so each managed socket gets a matching per-instance log file.
54+
3655
## Development
3756

3857
From repo root:

portal/src/bin/agent-portal-host.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use agent_box_common::config::load_config;
22
use clap::Parser;
33
use eyre::Result;
4-
use std::io::IsTerminal;
54
use std::path::PathBuf;
65
use std::sync::Arc;
76
use std::sync::atomic::AtomicBool;
87
use tracing::error;
9-
use tracing_subscriber::EnvFilter;
108

119
#[derive(Parser, Debug)]
1210
#[command(name = "agent-portal-host")]
@@ -17,33 +15,38 @@ struct Cli {
1715
socket: Option<String>,
1816
}
1917

20-
fn init_logging() {
21-
let env_filter = EnvFilter::try_from_default_env()
22-
.unwrap_or_else(|_| EnvFilter::new("info,agent_portal_host=info"));
23-
24-
tracing_subscriber::fmt()
25-
.with_env_filter(env_filter)
26-
.with_ansi(std::io::stderr().is_terminal())
27-
.init();
28-
}
29-
3018
fn main() {
31-
init_logging();
19+
let cli = Cli::parse();
3220

33-
if let Err(e) = run() {
21+
let config = match load_config() {
22+
Ok(config) => config,
23+
Err(e) => {
24+
eprintln!("Error: {e}");
25+
std::process::exit(1);
26+
}
27+
};
28+
let socket_path = PathBuf::from(
29+
cli.socket
30+
.clone()
31+
.unwrap_or_else(|| config.portal.socket_path.clone()),
32+
);
33+
34+
if let Err(e) = agent_portal::logging::init(None, Some(&socket_path), true) {
35+
eprintln!("Error: {e}");
36+
std::process::exit(1);
37+
}
38+
39+
if let Err(e) = run(cli, config.portal) {
3440
error!(error = %e, "portal host failed");
3541
std::process::exit(1);
3642
}
3743
}
3844

39-
fn run() -> Result<()> {
45+
fn run(cli: Cli, portal: agent_box_common::portal::PortalConfig) -> Result<()> {
4046
let path = std::env::var("PATH").unwrap_or_default();
4147
let path = path.split(':').collect::<Vec<_>>();
4248
tracing::info!(path = ?path, "PATH");
4349

44-
let cli = Cli::parse();
45-
let config = load_config()?;
46-
let portal = config.portal;
4750
let socket_path = PathBuf::from(cli.socket.unwrap_or_else(|| portal.socket_path.clone()));
4851

4952
agent_portal::host::run_with_config_and_socket(

portal/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
pub mod host;
2+
pub mod logging;

0 commit comments

Comments
 (0)