Ken Johnson 594970b4d1 0.1.0: shared TLogProc logger interface for the fpc-* ecosystem
Pure declarations unit covering the entire public surface:

- TLogLevel (llTrace..llFatal)
- TLogProc = procedure(Level: TLogLevel; const Category, Msg: string) of object
- TLogProcPlain = plain-procedure variant
- NullLog / TNullLogSink fallbacks (never guard on nil in
  consumer code)
- LogLevelName / LogLevelChar utilities
- Optional TConsoleLogger sink in log.console with min-level gate

Zero dependencies outside FPC RTL.  Adopted in-tree by fpc-binkp,
fpc-comet, fpc-filexfer, and fpc-emsi; consumers supply one
method bound as TLogProc to wire logging across every fpc-* lib
from a single sink.

Build green across x86_64-linux + all 5 i386 targets (linux,
freebsd, win32, os2, go32v2).  Tests in tests/test_log.pas.
2026-04-22 15:52:55 -07:00

fpc-log

A tiny Free Pascal library that provides the canonical logger shape for the fpc-* ecosystem. Every other library — fpc-msgbase, fpc-ftn-transport, fpc-binkp, and future siblings — depends on this one for its log-callback signature. Consumers plug one sink into all their libraries at once instead of wiring up N different logger shapes.

Why a library

Each library needs to hand log messages to its consumer without imposing a concrete logging backend. Without a shared shape, every library invents its own callback type, and the consumer either writes N adapters or duplicates the sink logic N times.

This library is deliberately leaf-level — no dependency on any other fpc-* library. Pure callbacks and a level enum. Everything else (consoles, files, syslog, JSON sinks) is consumer-provided.

Scope

Concern Owned by
Log level enum + callback signature fpc-log
Null sink (no-op default) fpc-log
Console / file / syslog / JSON sinks consumer
Log rotation, filtering, formatting consumer
Concrete logger selection consumer

Status

Current: 0.1.0 — the shape is small and stable; consumers can pin this safely.

Usage (library author)

In any fpc-* library that needs to emit log messages, accept a TLogProc (or ILogger interface, below) at construction and call it:

uses log.types;

type
  TMyLibThing = class
  private
    FLog: TLogProc;
  public
    constructor Create(ALog: TLogProc);
    procedure DoWork;
  end;

constructor TMyLibThing.Create(ALog: TLogProc);
begin
  FLog := ALog;
  if not Assigned(FLog) then
    FLog := @NullLog;   { default — discards everything }
end;

procedure TMyLibThing.DoWork;
begin
  FLog(llInfo, 'mylib', 'starting work');
  // ...
  FLog(llDebug, 'mylib', 'work done');
end;

Usage (consumer)

Implement one method in your app that takes (Level, Category, Msg) and pass it to every library:

procedure TMyApp.LogMessage(Level: TLogLevel;
  const Category, Msg: string);
begin
  WriteLn(Format('[%s] %s: %s', [
    LogLevelName(Level), Category, Msg]));
end;

// ...
MsgBase := TMsgBase.Create(@Self.LogMessage);
Binkp   := TBPSession.Create(..., @Self.LogMessage);
Bso     := TBSOQueue.Create(..., @Self.LogMessage);

One sink, used everywhere. Filter by category to separate messages per library; by level to mute verbosity.

Layout

fpc-log/
├── src/
│   ├── log.version.pas   — LOG_VERSION constant
│   ├── log.types.pas     — TLogLevel, TLogProc, NullLog
│   └── log.console.pas   — optional: TConsoleLogger helper
├── tests/
│   └── test_log.pas
├── README.md
├── CHANGELOG.md
├── build.sh
├── fpc.cfg
└── run_tests.sh

License

GPL-2.0 — same as the rest of the fpc-* ecosystem.

Description
Shared TLogProc logger interface for the fpc-* ecosystem
Readme 36 KiB
Languages
Pascal 72.6%
Shell 27.4%