Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/router_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,17 @@ The router exposes Prometheus metrics at `/metrics`. Basic counters
track request volume, latency and cache hits. Logs are written to
`logs/router.log` and rotated daily. Configure the log level via the
`LOG_LEVEL` environment variable.

Tail the log file using the CLI:

```bash
python -m router.cli show-logs --no-follow
```

Use `--follow` to stream updates or pass a custom path.

Export metrics in Prometheus format:

```bash
python -m router.cli export-metrics
```
41 changes: 41 additions & 0 deletions router/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import json
import os
from pathlib import Path
import time

import httpx
import typer
Expand Down Expand Up @@ -103,5 +104,45 @@ def refresh_openai() -> None:
typer.echo(f"Inserted {len(data)} models")


@app.command("show-logs")
def show_logs(
path: Path | None = typer.Argument(None),
follow: bool = True,
) -> None:
"""Tail the router log file."""

file_path = (
path if path is not None else Path(os.getenv("LOG_PATH", "logs/router.log"))
)
if not file_path.exists():
typer.echo(f"Log file '{file_path}' not found", err=True)
raise typer.Exit(1)

with file_path.open() as fh:
if follow:
fh.seek(0, os.SEEK_END)
try:
while True:
line = fh.readline()
if not line:
time.sleep(0.5)
continue
typer.echo(line, nl=False)
except KeyboardInterrupt:
pass
else:
for line in fh:
typer.echo(line, nl=False)


@app.command("export-metrics")
def export_metrics(url: str = "http://localhost:8000/metrics") -> None:
"""Fetch metrics from the router and print them."""

resp = httpx.get(url, timeout=10)
resp.raise_for_status()
typer.echo(resp.text)


if __name__ == "__main__":
app()
26 changes: 26 additions & 0 deletions tests/router/test_cli_logs_metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typer.testing import CliRunner
import router.cli as cli


def test_show_logs(tmp_path):
log_file = tmp_path / "router.log"
log_file.write_text("line1\nline2\n")
runner = CliRunner()
result = runner.invoke(cli.app, ["show-logs", str(log_file), "--no-follow"])
assert result.exit_code == 0
assert "line1" in result.stdout
assert "line2" in result.stdout


def test_export_metrics(monkeypatch):
class Resp:
text = "router_requests_total 1"

def raise_for_status(self):
pass

monkeypatch.setattr(cli.httpx, "get", lambda url, timeout=10: Resp())
runner = CliRunner()
result = runner.invoke(cli.app, ["export-metrics"])
assert result.exit_code == 0
assert "router_requests_total" in result.stdout
Loading