BYO log sink — extended log retention
developerz.ai keeps the raw logs your runs produce — coding-agent traces, PR-review transcripts, command output — for 72 hours, then redacts the payloads. The run timeline keeps its shape (event kinds, timestamps, outcomes); the raw content is gone. The permanent, tamper-evident audit trail of actions is never pruned — retention applies to raw log content only.
Want logs for longer? Bring your own database. You give us a Postgres connection URL; your runners mirror raw log events straight into it. Your database, your retention — keep a week or keep forever.
The two paths
| Path | Where logs live | Retention |
|---|---|---|
| Default | Platform database | 72 hours (raw payloads), then redacted |
| BYO sink | A Postgres you own | Yours — we never delete from your database |
On the BYO path the write happens on your own servers: the runner on your box writes directly to your database (ideally through your pooler). Raw log content does not need to transit the platform to reach your sink.
Setup
-
Create a database and a scoped role for the sink (see security notes below).
-
In the dashboard, open API keys & log sink and paste the connection URL:
postgres://dz_logs_writer:PASSWORD@your-pooler.example.com:6432/developerz_logsWe validate the URL (
postgres://orpostgresql://, publicly routable host, named database), test-connect once, then store it encrypted with the same envelope custody as BYOK keys. It is delivered to your runner boxes at enrollment and never displayed again — the dashboard shows only host, port, and database. -
Runners create an append-only
developerz_logstable on first write:-- auto-created; shown for reference create table if not exists developerz_logs ( id bigint generated always as identity primary key, run_id text not null, task_id text not null, lane text not null, -- 'run' | 'review' | 'ci' kind text not null, -- tool_call | command | agent_response | … ts timestamptz not null default now(), payload jsonb );
Boxes enrolled before you set the sink pick it up at their next enrollment; to wire
an existing box immediately, add DZ_LOG_SINK_URL=… to /etc/dz-runner/env and restart
the dz-runner service.
Put a pooler in front (pgbouncer / pgcat)
Our log writers are bursty: an agent step can emit dozens of events in a second,
then nothing for minutes — multiplied by every box in your fleet. Each runner caps
itself at 2 connections, but a pooler is still strongly recommended so bursts share a
few real backend connections instead of piling up against max_connections:
; pgbouncer.ini — three lines that matter
[databases]
developerz_logs = host=10.0.0.5 dbname=developerz_logs
pool_mode = transaction
pgcat in transaction mode works equally well. Runners disable prepared statements,
so transaction pooling is safe.
Delivery semantics
- Best-effort, never blocking. The mirror can never slow down or fail a run. If
your database is unreachable, events buffer briefly on the box (bounded — oldest
entries drop first), writes back off and retry, and the affected run gets an audited
log_sink_degradedwarning event. The platform copy still lands regardless. - Batched. Events are flushed in small batches about once a second.
- At-least-once-ish. A box crash can lose its unbuffered tail; the 72-hour platform window is your recovery buffer for gaps.
Security notes
-
Send us a scoped role, not a superuser. The runner needs only
CREATEon one schema the first time, thenINSERT:create role dz_logs_writer login password '…'; create database developerz_logs owner dz_logs_writer;Never reuse a role that can read your production data.
-
The connection URL embeds credentials, so it is write-only: encrypted at rest with the platform's key-encryption envelope (the BYOK custody path), never logged, never shown again in the dashboard or API.
-
Private-network hosts (
localhost, RFC-1918 ranges, link-local) are rejected — the sink must be reachable from your own boxes over a routable address. -
Rotating the password? Just paste the new URL — it replaces the old one and is re-verified with a fresh test connection.