Silk

silk/logger

Typed semantic logging with replaceable stdout and bounded in-memory providers.

When to use

Require Logger when code emits whole semantic messages but should not choose storage or destination. Provide StdoutLogger at a process edge. Use InMemoryLogger for deterministic observation and failure tests.

Details

Each invocation carries one LogLevel and one valid UTF-8 message. The service does not add formatting, newlines, timestamps, or allocation requirements. The stdout provider forwards only the message bytes; the in-memory provider retains at most eight committed events and 64 message bytes, and exposes attempted calls separately from successful commits.

Gotchas

Logger failures are typed LogError values and do not guarantee that a message committed. In-memory accessors require an event index less than length and a valid message-byte index.

Examples

Record and inspect one warning

import silk.effect { Effect }

import silk.logger { Logger }
import silk.logger { LogLevel }

import silk.usize as usize

effect fn program() -> i32
! Logger.LogError {
  let mut logger = Logger.inMemoryProvider()
  let logged = run Effect.logWarning("cache miss")
    |> Effect.provideMut(&mut logger)
  if Logger.length(&logger) != usize.ONE {
    return 1
  }
  if Logger.levelAt(&logger, usize.ZERO) != LogLevel.Warning {
    return 2
  }
  return 42
}

effect fn recover(error: Logger.LogError) -> i32 {
  return 0
}

pub fn main() -> i32 {
  return run Effect.catchAll(program(), recover)
}

Import as Logger with import silk.logger.

Public declarations: 14.

LogLevel

pub enum LogLevel

One closed logging severity from Trace through Error.

Trace

Trace = 0

Detailed diagnostic events.

Debug

Debug = 1

Development diagnostic events.

Info

Info = 2

Ordinary operational events.

Warning

Warning = 3

Recoverable abnormal conditions.

Error

Error = 4

Operations that did not complete as intended.

LogError

pub struct LogError

A typed failure reported by one Logger provider.

Details

The numeric code belongs to the provider. Portable code can recover from LogError without assigning one meaning to that code across different providers.

errorCode

pub fn errorCode(error: LogError) -> i32

Returns the provider-defined failure code for diagnostics.

Gotchas

Interpret this code only with knowledge of the selected provider. Different providers can use the same code for different failures.

Logger

pub service Logger

A replaceable service that receives one complete semantic log event per call.

When to use

Use this service when library code must emit events without selecting stdout, memory, or another destination.

Details

Each call carries one severity and one valid UTF-8 message. The service does not require a newline, timestamp, prefix, allocation, or output destination. The provider owns those choices.

Operation log

effect fn log(level: LogLevel, message: string) -> () ! LogError ? &mut Logger

Submits one complete UTF-8 message at one severity to the active provider.

Details

The call preserves the message bytes exactly. It does not add a newline, severity label, timestamp, or other formatting. A provider failure produces LogError.

StdoutLogger

pub struct StdoutLogger

A Logger provider that writes each complete message to process standard output.

Details

The provider ignores the severity for physical formatting and writes only the UTF-8 message bytes. It adds no newline and performs no message allocation.

stdoutProvider

pub fn stdoutProvider() -> StdoutLogger

Creates a logger that forwards each complete message to process standard output.

Gotchas

The caller must include a newline in message when line separation is required. A standard- output write failure becomes a provider-defined LogError.

Implementation Logger for StdoutLogger

impl Logger for StdoutLogger

Operation log

log = StdoutLogger.writeStdout

InMemoryLogger

pub struct InMemoryLogger

A deterministic Logger provider that retains up to eight events and 64 total message bytes.

When to use

Use this provider in tests that must inspect event order, severity, message bytes, or failure behavior without process output.

Details

The provider copies each committed message into fixed internal storage. It records attempted calls separately from committed events. Capacity failure and configured failure do not commit an event.

inMemoryProvider

pub fn inMemoryProvider() -> InMemoryLogger

Creates an empty in-memory logger with capacity for eight events and 64 message bytes.

Gotchas

A call fails when eight events are already committed. A call also fails when its bytes exceed the remaining 64-byte total. Neither failure commits the event.

inMemoryProviderFailAt

pub fn inMemoryProviderFailAt(failAt: usize) -> InMemoryLogger

Creates an in-memory logger that rejects one zero-based attempted-call ordinal.

Details

The configured attempt increases attempts but does not increase length or consume message capacity. Other attempts retain the eight-event and 64-byte limits of inMemoryProvider.

Implementation Logger for InMemoryLogger

impl Logger for InMemoryLogger

Operation log

log = InMemoryLogger.record

length

pub fn length(self: &silk/logger.InMemoryLogger) -> usize

Returns the number of events that the in-memory logger committed.

Details

Failed attempts do not increase this count. Use attempts when rejected calls must also be observed.

levelAt

pub fn levelAt(self: &silk/logger.InMemoryLogger, index: usize) -> LogLevel

Returns the severity of one committed event.

Gotchas

index must be less than length. An unused index below eight returns the initial Trace value instead of trapping. An index of eight or more traps.

messageLengthAt

pub fn messageLengthAt(self: &silk/logger.InMemoryLogger, index: usize) -> usize

Returns the UTF-8 byte length of one committed message.

Gotchas

index must be less than length. An unused index below eight returns zero instead of trapping. An index of eight or more traps.

messageByteAt

pub fn messageByteAt(self: &silk/logger.InMemoryLogger, eventIndex: usize, byteIndex: usize) -> u8

Returns one UTF-8 byte from a committed message.

Gotchas

eventIndex must be less than length. byteIndex must be less than messageLengthAt for that event. An unused event or invalid byte index traps. An event index of eight or more also traps.

attempts

pub fn attempts(self: &silk/logger.InMemoryLogger) -> usize

Returns the number of calls attempted, including calls that produced LogError.

On this page