diff --git a/docs/deploy.md b/docs/deploy.md index 7be7515..2bdc40e 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -85,6 +85,21 @@ flowchart LR create the dir; you **uncomment** the line and pick the container path. - **Named volumes** (`cache`, …) — yours; Docker owns them, no host paths to manage. + !!! warning "Two kinds of logs — and crashes go to the other one" + `${LOGS_DIR}` holds **only** what your app writes to disk through its logger + (e.g. `log_setup` writing a file) — your own structured logging. It does **not** + capture the process's stdout/stderr, and that's where **startup crashes and + uncaught exceptions land** — a traceback from a failed import or a missing file + never reaches your logger. So if a service dies on startup, or you don't see the + error in your log files, it's in the process output, not `${LOGS_DIR}`. Make + fatal errors visible — and to route uncaught exceptions into your log file too, + install a top-level hook: + + ```python + import sys, logging + sys.excepthook = lambda *exc: logging.getLogger().critical("uncaught", exc_info=exc) + ``` + !!! success "Same file, both places" Locally, `docker compose up` needs nothing set — the `${VAR:-./default}` fallbacks use `./logs` / `./config`. When deployed, the ops tooling sets the diff --git a/docs/workflow.md b/docs/workflow.md index ae49de5..77ec948 100644 --- a/docs/workflow.md +++ b/docs/workflow.md @@ -241,3 +241,48 @@ gitcs() { - **`gl`** — a readable branch graph for understanding history at a glance. - **`pyenv`** — per-project Python versions, so each repo builds against the version it targets. + +## Paste service + +A shared, self-hosted pastebin at +[paste.rethinkstudios.io](https://paste.rethinkstudios.io) — for quickly sharing +logs, snippets, or command output when you're pairing, filing an issue, or handing +output to a coding agent. Pastes are **unlisted** (random URL), **expire** by +default, and support **burn-after-read**. Anonymous — no login. + +The easy way: pipe anything into it and get back a URL. Drop this into your +`.zshrc` / `.bashrc` — a **function** is preferred over a plain alias because it +reads stdin cleanly and has room to grow options (needs `jq` + `curl`): + +=== "Function (recommended)" + + ```bash + # paste stdin to the rethink paste service, print the URL. usage: cat file | pb + pb() { + jq -Rns '{text: inputs, expires: 259200}' \ + | curl -s -H 'Content-Type: application/json' --data-binary @- https://paste.rethinkstudios.io/ \ + | jq -r '"https://paste.rethinkstudios.io" + .path' + } + ``` + +=== "Alias (alternative)" + + Same behaviour as a one-liner — note the extra escaping the alias form needs: + + ```bash + alias pb="jq -Rns '{text: inputs, expires: 259200}' | curl -s -H 'Content-Type: application/json' --data-binary @- https://paste.rethinkstudios.io/ | jq -r '\"https://paste.rethinkstudios.io\" + .path'" + ``` + +Usage — pipe any file or command output straight in: + +```bash +cat latest.log | pb # -> https://paste.rethinkstudios.io/xxxxxxx +mycommand 2>&1 | pb # pipe any command's output (stderr too) +``` + +`expires` is in **seconds** — `259200` = 72h (the default). Change it (e.g. +`86400` for 24h) or drop the field entirely. + +!!! info "Rate-limited on creation" + The service rate-limits paste **creation** (not viewing), so it's built for + occasional shares — not bulk or automated posting.