Skip to content

richardpiazza/Occurrence

Occurrence

A multi-platform log handler for swift-log.

Usage

SwiftLog provides a unified, performant, and ergonomic logging API that can be adopted by libraries and applications across the Swift ecosystem.

The thing SwiftLog does not provide is a LogHandler - any instance that consumes logs being generated by libraries and applications. This is where Occurrence steps in. This package provides a SQLite backed storage mechanism to capture, query, and export logs. In order to provide this functionality, a LogHandler must first be bootstrapped into the logging system. Occurrence provides a convenience method to configure itself as the LogHandler:

Occurrence.bootstrap()

Bootstrapping must be completed before the initialization of any Logger instance. Typically this is done at the very start of your application. For instance:

@main
struct MyApp: App {
  init() {
    Occurrence.bootstrap()
    // … continued initialization.
  }
}

That's everything needed to start capturing logs!

Queries & Exports

Capturing logs is great, but somewhat useless if you can't do anything with them. To allow for observation, querying, and export of logging data, Occurrence defines LogStreamer and LogProvider instances.

LogStreamer

protocol LogStreamer: Sendable {
  var stream: AsyncStream<Logger.Entry> { get }
  func log(_ entry: Logger.Entry)
}

A LogStream provides an AsyncStream of Logger.Entry types as they are processed by framework. These entries can easily be observed:

let task = Task {
  for await entry in Occurrence.logStreamer.stream {
    // process entry
  }
}

LogProvider

protocol LogProvider: Sendable {
    func log(_ entry: Logger.Entry)
    func subsystems() -> [Logger.Subsystem]
    func entries(matching filter: Logger.Filter?, ascending: Bool, limit: UInt) -> [Logger.Entry]
    func purge(matching filter: Logger.Filter?)
}

A LogProvider consumes log entries as they are registered and provides data about those entries as requested. Various filters can be provided to fine-tune the results you're looking for.

Conveniences

LogView

If you are in a SwiftUI environment the LogView view provides a way to observe, manage, and export log entries. This offers a prime example of how the LogStreamer and LogProvider types can be utilized within an application.

LoggableError

A LoggableError is an Error type that can be easily converted to Logger.Metadata. Many standard error types have conformances for this protocol, including:

  • CocoaError
  • DecodingError
  • EncodingError
  • URLError

There are also extensions to the Logger instance that allow for passthrough of a LoggableError instance:

@LazyLogger("MyApp") var logger: Logger

enum AppError: LoggableError {
  case badData
}

func throwingFunction() throws {
  guard condition else {
    throw logger.error("Condition not met.", AppError.badData)
  }
}

LazyLogger

Every Logger instance supplies a label (Internally Occurrence uses the type Logger.Subsystem for this). As a convenience to creating a Logger reference, use the LazyLogger property wrapper which will create a Logger with the specific label (Logger.Subsystem).

@LazyLogger("LoggerLabel") var logger: Logger

About

A multi-platform log handler for 'swift-log'.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Languages