-
Notifications
You must be signed in to change notification settings - Fork 0
Loggers
Logger extensions are fan-out sinks for log records. Every logger receives every record; each decides whether to drop, format, or write it.
contractVersion: 1.0.0
Loggers externalize the session. A stdout logger prints for the local operator; a file logger persists to ~/.stud/logs/; a remote logger ships to an external service. Loggers are extensions because the set of destinations is open and deployment-specific.
Loggers do not own observability primitives — correlation IDs, spans, and audit events are core constructs (see Observability). Loggers are the sinks through which those records flow outward.
classDiagram
class LoggerContract {
kind : "Logger"
contractVersion : SemVer
requiredCoreVersion : SemVerRange
configSchema : JSONSchema
loadedCardinality : unlimited
activeCardinality : unlimited
stateSlot : optional
validationSeverity : optional
discoveryRules : DiscoveryRules
reloadBehavior : in-turn
accepts : LogKindFilter
}
class LogKindFilter {
events : bool
audit : bool
diagnostics : bool
minSeverity : trace | debug | info | warn | error
}
LoggerContract --> LogKindFilter
accepts lets a logger declare which record kinds it wants — a metrics sink might take events but skip audit; a compliance sink might take only audit.
Every logger's configSchema must accept:
| Field | Meaning |
|---|---|
enabled |
Whether this logger participates. |
level |
Minimum severity to emit — trace, debug, info, warn, error. Default: info. Overridden by the --debug flag or logging.level: "debug" in settings.json. |
redactSecrets |
Whether to apply the default redaction filter before writing. Default: true. Must remain true whenever level is debug or below — see Debug-level redaction. |
Plus sink-specific options (file path, remote URL, rotation size).
Debug and trace levels are the highest-risk levels for secret exfiltration — they widen the aperture on request/response bodies, tool inputs, and provider metadata that might carry resolved secrets. Therefore:
- A conforming logger must not disable the redaction filter when its effective
levelisdebugortrace. A configuration that pairslevel: "debug"withredactSecrets: falseis a validation error, not a warning. - The redaction pipeline that runs for debug logs is the same pipeline that runs for
info-level logs. There is no "debug-only" bypass. See Secrets Hygiene § Redaction pipeline. - A debug log entry that contains a resolved secret is a bug in the record producer, not a logger configuration question. Loggers are defense in depth; the primary duty remains on producers.
| Phase | Logger responsibilities |
|---|---|
init |
Validate config; open the file / connect the socket / prepare the queue. |
activate |
Subscribe to the log stream. |
deactivate |
Flush pending records; stop accepting new ones. |
dispose |
Close the file / socket; flush one final time. Idempotent. |
Loggers write asynchronously where possible. A logger that blocks on every record creates backpressure into core and is non-conformant. Use a bounded queue and drop-with-warning on overflow.
Loaded: unlimited.
Active: unlimited. Every loaded logger receives every record that passes its accepts filter.
Optional. Typical uses:
- Rotation counters (file loggers that roll every N MB).
- Last-flushed watermark (remote loggers that batch).
See Extension State.
Optional by default. A logger that fails to load skips with a warning; the session runs without it. A critical record that no logger accepts still lands in the Audit Trail because audit is a core durable surface, not a logger responsibility.
Config may escalate a specific logger to critical (useful for regulated environments where a compliance sink must be present).
Loggers live in a loggers/ folder under each configuration scope layer:
| Layer | Location |
|---|---|
| Bundled | Ships with the package. See File logger reference — the bundled file logger is always loaded. |
| Global | ~/.stud/loggers/… |
| Project | <cwd>/.stud/loggers/… |
Loggers are an unordered category. Fan-out order is undefined; every logger receives a copy.
reloadBehavior: in-turn. Loggers are among the few categories safe to reload mid-turn — reattaching a sink does not change any semantic output. The previous logger drains pending records, then detaches; the new one attaches fresh.
A logger reads and writes only through the Host API:
-
host.events.subscribe(kinds)— subscribe to events, audit records, diagnostics. -
host.cancel.session— react to session shutdown by flushing. -
host.session.stateSlot(extId)— own slot for rotation/batch state.
A logger never:
- Drives the Interaction Protocol.
- Writes to the tool registry.
- Reads env values directly — record payloads already carry whatever values should appear.
-
Log records are external by default. Treat every field as externally visible.
redactSecretsis defense in depth; the primary duty is on the record producer to not carry a secret in the first place. - No resolved-secret exfiltration via logging. See LLM Context Isolation and Secrets Hygiene.
-
Audit records are special. A logger may redact non-audit fields but must not mutate audit records — they are legally/operationally meaningful. If
redactSecretsistrue, apply it to event payloads, not to audit. - Backpressure is a security concern. A logger that blocks core starves the UI and slows down approvals. Bounded queue + drop-with-warn is the contract.
- Observability
- Audit Trail
- Secrets Hygiene
- Event Bus
- Launch Arguments § --debug
- Settings Shape § logging
- File logger reference
- Logger contract as documented above. Fan-out model;
in-turnreload; audit records pass through un-redacted.
- Execution Model
- Message Loop
- Concurrency and Cancellation
- Error Model
- Event and Command Ordering
- Event Bus
- Command Model
- Interaction Protocol
- Hook Taxonomy
- Host API
- Extension Lifecycle
- Env Provider
- Prompt Registry
- Resource Registry
- Session Lifecycle
- Session Manifest
- Persistence and Recovery
- Stage Executions
- Subagent Sessions
- Contract Pattern
- Versioning and Compatibility
- Deprecation Policy
- Capability Negotiation
- Dependency Resolution
- Validation Pipeline
- Cardinality and Activation
- Extension State
- Conformance and Testing
- Providers
- Provider Params
- Tools
- Hooks
- UI
- Loggers
- State Machines
- SM Stage Lifecycle
- Stage Definitions
- Commands
- Session Store
- Context Providers
- Settings Shape
- Trust Model
- Project Trust
- Extension Isolation
- Extension Integrity
- LLM Context Isolation
- Secrets Hygiene
- Security Modes
- Tool Approvals
- MCP Trust
- Sandboxing
- Configuration Scopes
- Project Root
- Extension Discovery
- Extension Installation
- Extension Reloading
- Headless and Interactor
- Determinism and Ordering
- Launch Arguments
- Network Policy
- Platform Integration
Tools
UI
Session Stores
Loggers
Providers
Hooks
Context Providers
Commands
- First Run
- Default Chat
- Tool Call Cycle
- Hook Interception
- Guard Deny Reproposal
- State Machine Workflow
- SM Stage Retry
- Hot Model Switch
- Capability Mismatch Switch
- Session Resume
- Session Resume Drift
- Approval and Auth
- Interaction Timeout
- Headless Run
- Parallel Tool Approvals
- Subagent Delegation
- Scope Layering
- Project First-Run Trust
- Reload Mid-Turn
- Compaction Warning
- MCP Remote Tool Call
- MCP Prompt Consume
- MCP Resource Bind
- MCP Reconnect