@arki/log for agents
For @arki/[email protected] · source docs/agent-guide.md
The long form of llms.txt. When they disagree, src/core/index.ts wins.
The model
- A logger is
getLogger('arki:kv'). Its category is:-separated. It obeys aconfigure()that runs later. - A record has a template, fields, a level and a resource. Values stay fields. Formatters render the text.
- A channel is a named sink. A rule maps a category to a level and channels. The nearest configured ancestor wins and replaces.
- Processors (
redact,enrich,dropWhen) change or drop a record before a sink sees it. - Wrappers (
fingersCrossed,buffer,deduplicate) sit around a sink. - The core has no dependencies.
@arki/log/nodeadds sinks and env.@arki/log/oteladds OpenTelemetry.@arki/log/testingaddsfakeLog.
Task map
Log from a library
import { getLogger } from '@arki/log';
const log = getLogger('arki:kv'); // module scope is fine
export function connect(url: string): void {
log.debug('connecting to {host}', { host: new URL(url).host });
}Never call configure() in a library.
Configure logging in an app
Call configure() once at the entry file. See the README quick start.
Keep secrets out of records
Add redact(['password', 'headers.authorization']) to processors. Redaction runs before any formatter.
Test that code logs
import { test } from 'vitest';
import { getLogger } from '@arki/log';
import { fakeLog } from '@arki/log/testing';
test('logs a warning', () => {
using log = fakeLog();
getLogger('app:jobs').warn('job {id} is late', { id: 'job_1' });
log.assertLogged({ level: 'warn', template: 'job {id} is late' });
});Rules that bite
- Before
configure(), onlywarnand above are kept, and only the first 64 records. - A second
configure()throwsARKI_LOG_E001. Usereconfigure()on the handle. App entries pass{ owner: import.meta.url }, so a dev server's re-run of the entry replaces the setup instead of throwing. withContextfields crossawaitonly withasyncContext()from@arki/log/node.- A failure value logged as a field prints its cause chain, at most 64 links.
fatalnever ends the process.- Importing
@arki/log/nodereads nothing.fromEnv()readsLOG_LEVEL,DEBUGandNO_COLORwhen called.
Errors
| Code | Meaning | What to do |
|---|---|---|
ARKI_LOG_E001 | configure() ran twice | Call it once; use reconfigure() |
ARKI_LOG_E002 | A rule or to() names an undefined channel | Add it to configure({ channels }) |
ARKI_LOG_E003 | A level that does not exist | Use one of the six names or 1 to 24 |
ARKI_LOG_E004 | fakeLog() while another fake is active | Restore the first fake |
ARKI_LOG_E005 | reconfigure() on a stale handle | Use the latest handle |
Verify
bun run test
bun run test:docs
bun run test:runtimes