Become a member!

LoggerPro 2.1 — Framework di Logging Asincrono per Delphi

🌐
Questo articolo è disponibile anche in altre lingue:
🇬🇧 English  •  🇪🇸 Español  •  🇩🇪 Deutsch
📚
Cerchi una versione precedente?
LoggerPro 2.0  •  LoggerPro 1.x (legacy)

TL;DR: LoggerPro 2.1 è il framework di logging asincrono e thread-safe per Delphi. Mantiene l’API fluente con pattern Builder della 2.0 e aggiunge configurazione esterna via JSON (LoggerProFromJSONFile o LoggerProFromJSONString), osservabilità cloud con ExeWatch, un renderer LogFmt conforme alla spec, un appender FileBySource per log per-tenant, output console UTF-8 per Docker, inizializzazione DLL-safe, autenticazione ElasticSearch e altro ancora. Aggiornamento drop-in dalla 2.0, licenza Apache 2.0, funziona da Delphi 10.2 Tokyo fino a Delphi 13 Florence, su Windows / Linux / macOS / Android / iOS. Documentazione LoggerPro 2.0 → · Documentazione LoggerPro 1.x →

In sintesi

Nome LoggerPro
Versione 2.1.0 (Aprile 2026)
Linguaggio Delphi / Object Pascal
Delphi minimo 10.2 Tokyo · Testato fino a 13 Florence
Piattaforme Windows, Linux, macOS, Android, iOS
Licenza Apache 2.0 (libera per uso commerciale)
Autore Daniele Teti
Repository github.com/danieleteti/loggerpro
Installazione BOSS · Release ZIP
Categoria Asincrono · Thread-safe · Pluggable · Logging strutturato
Equivalenti più prossimi Serilog (.NET), NLog (.NET), log4j / Logback (Java)

LoggerPro 2.1 Logo

Cos’è LoggerPro?

LoggerPro è il framework di logging asincrono, thread-safe e pluggable per Delphi / Object Pascal - l’equivalente Delphi più prossimo di Serilog (.NET), NLog (.NET) o log4j / Logback (Java). Offre un’API fluente con pattern Builder, contesto strutturato key-value, formatter di stack trace pluggable, 20+ appender integrati (file, console, HTTP, osservabilità cloud ExeWatch, Grafana Loki via LogFmt, ElasticSearch, UDP syslog, Windows Event Log, database, VCL e altro), e gira cross-platform su Windows, Linux, macOS, Android e iOS. LoggerPro è rilasciato con licenza Apache 2.0, mantenuto attivamente dal 2010 e utilizzato in migliaia di applicazioni Delphi in produzione.

La versione 2.1 (Aprile 2026) è la release stabile corrente. Si basa sull’API fluente con pattern Builder introdotta nella 2.0 e aggiunge un’integrazione first-class con ExeWatch per l’osservabilità cloud end-to-end, insieme a feature focalizzate sui target di deployment moderni - container Docker, aggregatori di log cloud (Grafana Loki, Elastic, Datadog), applicazioni multi-tenant e DLL Delphi - rimanendo completamente backward compatible.

Novità della 2.1

Feature Cosa ti offre
Configurazione JSON Rimodella il logger al deploy - LoggerProFromJSONFile('loggerpro.json'). Validazione stretta dei campi, diagnostica per type sconosciuti
HTML live log viewer File .html autocontenuto con barra filtri sticky, colorazione per livello, ricerca client-side, export CSV/JSON e live tailing nel browser
Integrazione ExeWatch Appender first-class per l’osservabilità cloud ExeWatch - uso imperativo, fluente o via JSON
Pattern appender pluggable I backend opzionali (ExeWatch, WindowsEventLog, ElasticSearch) si auto-registrano dalla propria unit - basta aggiungere la clausola uses
MinimumLevel a runtime ILogWriter.MinimumLevel è ora una property first-class - cambia il gate globale al volo
Webhook appender Rinominato da HTTPAppender; aggiunta autenticazione API-key (header o query-string)
Renderer LogFmt Output key=value conforme alla spec; greppable, Loki-friendly, record su singola riga
FileBySource appender Sottocartelle per-sorgente (per-tenant, per-client) con rotazione giorno+dimensione
Output console UTF-8 Unicode corretto in container Docker e console Windows (WithUTF8Output)
Init DLL-safe Risolve il deadlock del Windows Loader Lock quando LoggerPro viene usato da una DLL
Auth ElasticSearch Supporto per Basic Auth, API Key e Bearer Token
UDP Syslog local time Opzione WithUseLocalTime(True) sull’appender syslog
GetCurrentLogFileName Recupera il path del file di log attivo - utile per upload, email, riavvio

Aggiornamento dalla 2.0? Sostituzione drop-in nella maggior parte dei casi. Un solo breaking change: WriteToHTTP è stato rinominato in WriteToWebhook (basta un find-and-replace). Tutto il resto è additivo.

Quick Start con l’API Builder

uses
  LoggerPro,
  LoggerPro.Builder;

var
  Log: ILogWriter;
begin
  Log := LoggerProBuilder
    .WithDefaultTag('MYAPP')
    .WriteToFile
      .WithLogsFolder('logs')
      .WithMaxBackupFiles(5)
      .WithMaxFileSizeInKB(10000)
      .Done
    .WriteToConsole
      .Done
    .Build;

  Log.Info('Application started');
  Log.Debug('Processing item %d', [42], 'WORKER');
  Log.Error('Connection failed', 'DATABASE');

  // Contextual logging
  Log.WithProperty('user_id', 42)
     .WithProperty('session', 'abc123')
     .Info('User logged in', 'auth');

  // Exception logging
  try
    // ... code ...
  except
    on E: Exception do
      Log.LogException(E, 'Operation failed', 'error');
  end;

  // Explicit shutdown before exit
  Log.Shutdown;
end;

Configurazione JSON

Novità della 2.1. Distribuisci la tua app con un loggerpro.json accanto all’EXE e rimodella il logger al deploy senza ricompilare. Gli operatori possono cambiare backend, modificare i livelli di log o aggiungere/rimuovere appender senza toccare il codice sorgente.

Schema in breve

{
  "configVersion":        1,
  "minimumLevel":         "Debug",
  "defaultMinimumLevel":  "Warning",
  "defaultTag":           "myapp",

  "appenders": [
    { "type": "Console",  "colors": true, "colorScheme": "Midnight" },
    { "type": "File",     "logsFolder": "logs", "maxBackupFiles": 5,
                          "minimumLevel": "Debug" },
    { "type": "HTMLFile", "logsFolder": "logs", "title": "MyApp" }
  ]
}

Il gate globale accetta tutto (minimumLevel: Debug). Ogni appender che non specifica il proprio minimumLevel prende il valore template Warning - Console e HTMLFile lo ereditano entrambi. Il File appender fa opt-out e scrive l’audit trail completo a Debug. Mettere defaultMinimumLevel sotto minimumLevel sarebbe un no-op: il gate globale avrebbe già scartato quei messaggi prima che raggiungano un qualsiasi appender.

Campi root:

Campo Tipo Scopo
configVersion integer Versione dello schema. Assente = ultima versione. Superiore alla versione della libreria = errore bloccante.
minimumLevel string Gate globale pre-coda. "Debug" / "Info" / "Warning" / "Error" / "Fatal". I messaggi sotto questa severity non entrano mai in coda - zero overhead per le chiamate filtrate.
defaultMinimumLevel string Valore template che ogni appender usa come proprio minimumLevel quando l’entry non ne specifica uno. Non è un gate - pre-popola soltanto la soglia per-appender al momento del parsing.
defaultTag string Tag di default per chiamate come Log.Info('msg') senza argomento tag.
appenders array Obbligatorio. Un oggetto per appender, ciascuno con un "type" e campi type-specific.

Campi comuni per-appender:

Campo Note
type Obbligatorio. Case-insensitive, confrontato con i nomi di tipo registrati.
minimumLevel Opzionale. Severity minima che questo appender emette. I messaggi sotto vengono silenziosamente scartati da QUESTO appender (gli altri appender li vedono comunque). Stesso dominio di valori del minimumLevel root. Default a defaultMinimumLevel (o Debug se anche quello è assente). Impostarlo sotto il minimumLevel root è un no-op: quei messaggi non arrivano all’appender perché non hanno passato il gate pre-coda.

I campi type-specific sono elencati nella sezione di ciascun appender in questa guida; i typo vengono intercettati (vedi Diagnostica degli errori sotto).

I tre concetti, disambiguati. Ogni chiamata di log porta con sé la propria severity - Log.Info è Info, Log.Error è Error, e così via. Né minimumLeveldefaultMinimumLevel lo cambiano; decidono soltanto chi vede cosa. Il minimumLevel root è un filtro pre-coda (gratuito: il TLogItem non viene nemmeno costruito per messaggi sotto soglia). Il minimumLevel per-appender è un gate di emissione (valutato sul worker thread dell’appender, decide se QUESTO appender scrive il messaggio). Il defaultMinimumLevel al root è un default a write-time per il gate per-appender, non un filtro runtime - ti permette di dire “ogni appender va di default a Warning se non specifica diversamente” senza ripetere il campo su ogni entry.

Cos’è obbligatorio, cosa ha default

Il minimo assoluto è una singola entry nell’array:

{ "appenders": [ { "type": "Console" } ] }

Fine. Tutto il resto è opzionale o inferito. La chiave appenders al root è obbligatoria (può essere un array vuoto per costruire un logger no-op, ma deve essere presente). Ogni entry deve avere un "type"; ogni altro campo è opzionale.

Valori di default quando un campo è omesso:

Campo Se assente Note
Root configVersion Trattato come l’ultima versione di schema nota (attualmente 1). Un valore superiore è un errore bloccante (guard forward-compat).
Root minimumLevel Debug - tutto passa il gate globale pre-coda. I messaggi sotto questa severity vengono filtrati prima dell’accodamento (zero overhead).
Root defaultMinimumLevel Debug Usato come minimumLevel di default per ogni appender che non ne specifica uno.
Root defaultTag "main" Usato dalle chiamate che non passano un tag (es. Log.Info('msg')).
Appender minimumLevel defaultMinimumLevel (o Debug se anche quello è assente). L’appender emette solo messaggi a questa severity o superiore.
Campi type-specific dell’appender Ogni appender porta i propri default (elencati nella sua sezione). Es. logsFolder di File punta di default alla directory dell’EXE; Console ha i colori ON con scheme Midnight (usa "colorScheme": null o "colors": false per disattivarli).

JSON minimali pronti all’uso

Log su file rotante (il deploy più semplice). Usa la directory dell’EXE per logsFolder e il nome dell’EXE come base filename; 5 backup da 1 MB ciascuno.

{
  "appenders": [
    { "type": "File" }
  ]
}

Vuoi piazzare i file altrove e tenere più storia:

{
  "appenders": [
    {
      "type": "File",
      "logsFolder": "C:/ProgramData/MyApp/logs",
      "fileBaseName": "myapp",
      "maxBackupFiles": 30,
      "maxFileSizeInKB": 5000
    }
  ]
}

Log sulla console colorata. I colori sono ON di default con il professionale scheme Midnight - è sufficiente una singola entry:

{
  "appenders": [
    { "type": "Console" }
  ]
}

Sovrascrivi lo scheme per nome (case-insensitive), o disattiva totalmente i colori:

// Pick a different scheme
{ "appenders": [ { "type": "Console", "colorScheme": "Nord" } ] }

// Opt out: explicit null...
{ "appenders": [ { "type": "Console", "colorScheme": null } ] }

// ...or explicit empty string
{ "appenders": [ { "type": "Console", "colorScheme": "" } ] }

// ...or explicit colors:false
{ "appenders": [ { "type": "Console", "colors": false } ] }

Tutte e tre le forme “opt out” producono testo piano, senza ANSI. Inoltre, ogni scheme colorato si auto-degrada a testo piano quando stdout è rediretto su file o pipato a un altro processo - non ti ritroverai mai con codici escape nei tuoi file di log per sbaglio.

Gli schemi di colore predefiniti

Undici schemi sono inclusi con LoggerPro. Tutti rispettano lo stesso contratto di palette (colore per-livello + tag colorato, metadati, chiavi e valori di contesto), ma enfatizzano parti diverse. I nomi degli scheme sono case-insensitive in JSON; gli screenshot sotto sono di riferimento - lancia samples/03b_console_with_colors_appender per vedere ogni scheme renderizzato nel tuo terminale con gli stessi messaggi seed.

Scheme Descrizione
Default Baseline Gin-inspired solo foreground; colore livello per severità.
Monochrome Nessun ANSI - testo piano. Auto-applicato quando stdout è pipato/rediretto.
GinBadge Toni Default più “badge” con sfondo colorato per il livello.
GinMinimal Tutto grigio scuro, solo la parola livello mantiene il colore.
GinVibrant Arcobaleno saturato - ogni campo un colore distinto acceso.
Midnight Prefisso/tag magenta, chiavi verdi, valori cyan. Default JSON - si legge bene su terminali chiari e scuri.
Nord Tema Frost con blu/cyan artici, warning gialli, fatal rossi.
Matrix Tutto verde; livelli renderizzati come badge di sfondo.
Amber Monitor CRT ambrato anni ‘80 - famiglia giallo/arancio, rosso solo per errori.
Ocean Blu e cyan stratificati - tag teal, valori cyan brillante.
Cyberpunk Prefisso magenta neon, tag cyan, valori gialli; badge di livello vivaci.

Selezione da JSON. Basta referenziarlo per nome:

// A calm palette for a dev console
{ "appenders": [ { "type": "Console", "colors": true, "colorScheme": "Nord" } ] }
// Level badges - fastest level scanning
{ "appenders": [ { "type": "Console", "colors": true, "colorScheme": "GinBadge" } ] }
// Plain text, no ANSI - useful in tests or when piping to a file
{ "appenders": [ { "type": "Console", "colors": true, "colorScheme": "Monochrome" } ] }

Selezione da codice:

uses LoggerPro, LoggerPro.Builder;

Log := LoggerProBuilder
  .WriteToConsole
    .WithColorScheme(LogColorSchemes.Midnight)   // or .Nord / .Matrix / ...
    .Done
  .Build;

Scheme custom. Ogni scheme è un record TLogColorScheme - puoi costruirne uno tuo partendo da qualsiasi preset e sovrascrivendo i campi che contano:

var lScheme: TLogColorScheme;
begin
  lScheme := LogColorSchemes.Midnight;
  lScheme.TagColor := FORE_YELLOW;
  lScheme.LevelColor[TLogType.Info] := STYLE_BRIGHT + FORE_WHITE;

  Log := LoggerProBuilder
    .WriteToConsole.WithColorScheme(lScheme).Done
    .Build;
end;

Auto-downgrade. Quando stdout è rediretto su file o pipato a un altro processo, il renderer degrada automaticamente a testo piano (equivalente a Monochrome). Non ti ritroverai mai con codici escape nei tuoi file di log per sbaglio.

Altri campi opzionali:

{
  "appenders": [
    {
      "type": "Console",
      "colors": true,
      "colorScheme": "Nord",
      "prefix": "MYAPP",    // shows as [MYAPP] before each line
      "utf8Output": true    // safe output in Docker / Windows consoles
    }
  ]
}

Combina i due per un tipico setup di sviluppo - console colorata più un file rotante con livelli separati:

{
  "minimumLevel": "Debug",
  "appenders": [
    { "type": "Console", "colors": true, "colorScheme": "Midnight" },
    { "type": "File",    "logsFolder": "logs", "minimumLevel": "Info"  }
  ]
}

Entry point

Due funzioni globali nell’unit LoggerPro - una restituisce un ILogWriter pronto all’uso, l’altra restituisce l’ILoggerProBuilder non finalizzato così il chiamante può continuare a chainare:

uses LoggerPro;

// 1. Pure JSON → ILogWriter (simplest, covers most cases)
Log := LoggerProFromJSONFile('loggerpro.json');

// 1b. Pure JSON from an embedded resource or a hand-assembled string
Log := LoggerProFromJSONString(MyEmbeddedConfig);
uses LoggerPro, LoggerPro.Builder;

// 2. JSON base + more appenders from code (the "mixed" pattern)
Log := LoggerProBuilderFromJSONFile('loggerpro.json')
         .WriteToCallback
           .WithCallback(MyProc)
           .Done
         .Build;   // you call .Build yourself

Entrambe le funzioni sollevano ELoggerProConfigError su qualsiasi problema con il file - vedi Diagnostica degli errori sotto per il testo esatto.

Mescolare config da file con appender solo a runtime

Alcuni appender non possono essere descritti in JSON perché richiedono un riferimento a un oggetto runtime che non sta in un file di configurazione: una callback, un TStrings, un componente VCL, una TFDConnection viva. Il pattern è sempre lo stesso:

  1. Carica la parte JSON-descrivibile con LoggerProBuilderFromJSONFile.
  2. Chaina gli extra sul builder restituito.
  3. Chiama .Build tu stesso.

Esempio 1 - Base JSON + callback UI per una status bar.

uses
  LoggerPro, LoggerPro.Builder;

Log := LoggerProBuilderFromJSONFile('loggerpro.json')
  .WriteToCallback
    .WithCallback(
      procedure(const aLogItem: TLogItem; const aFormattedMessage: string)
      begin
        // The callback appender marshals to the main thread for us.
        StatusBar1.SimpleText := aFormattedMessage;
      end)
    .WithSynchronizeToMainThread(True)
    .Done
  .Build;

Esempio 2 - Base JSON + mirror VCL TListView. L’utente configura file/console da JSON; il live-tail GUI resta in codice.

uses
  LoggerPro, LoggerPro.Builder;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  FLog := LoggerProBuilderFromJSONFile('loggerpro.json')
    .WriteToVCLListView(ListViewLogs)
      .WithMaxLogLines(1000)
      .Done
    .Build;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  FLog.Shutdown;   // before the form - and the ListView - are freed
  FLog := nil;
end;

Esempio 3 - Base JSON + TMemo FMX. TMemo.Lines è un TStrings, quindi l’appender cross-platform WriteToStrings copre FMX, VCL e qualsiasi altro componente che esponga un TStrings.

FLog := LoggerProBuilderFromJSONFile('loggerpro.json')
  .WriteToStrings(MemoLog.Lines)
    .WithMaxLogLines(500)
    .WithClearOnStartup(True)
    .Done
  .Build;

Esempio 4 - Base JSON + appender database. Il JSON controlla console/file/HTML; la connessione DB resta in codice perché TFDConnection non è serializzabile.

uses
  LoggerPro, LoggerPro.Builder, LoggerPro.DBAppender.FireDAC;

FLog := LoggerProBuilderFromJSONFile('loggerpro.json')
  .WriteToFireDAC
    .WithConnectionDefName('MAIN_DB')
    .WithStoredProcName('sp_insert_log')
    .WithMinimumLevel(TLogType.Warning)     // DB only gets Warning+
    .Done
  .Build;

Scenari e casi limite

Il minimumLevel per-appender è indipendente dal minimumLevel root. Il gate root decide se un messaggio viene accodato; il gate del singolo appender decide se quell‘appender scrive il messaggio. Un messaggio sotto il minimumLevel root non raggiunge mai alcun appender; un messaggio che passa il gate root ma è sotto il minimumLevel di un appender viene scartato da quell’appender, mentre gli altri lo ricevono comunque.

{
  "minimumLevel": "Debug",
  "appenders": [
    { "type": "Console",                    "minimumLevel": "Debug"   },
    { "type": "File", "logsFolder": "logs", "minimumLevel": "Info"    },
    { "type": "Webhook", "url": "https://ops/alerts",
                                              "minimumLevel": "Error"   }
  ]
}

Risultato: lo sviluppatore vede tutto in console, il file di log tiene Info+, il webhook scatta solo su errori.

L’array appenders vuoto è ammesso - ottieni un logger “black hole” utile per test di integrazione:

{ "configVersion": 1, "appenders": [] }

Logging effettivamente disabilitato significa solo un gate globale abbastanza alto da non far passare nulla:

{ "configVersion": 1, "minimumLevel": "Fatal", "appenders": [] }

Oppure, in codice, modifica la property a runtime su un writer già costruito: Log.MinimumLevel := TLogType.Fatal;

Appender pluggable (ExeWatch, WindowsEventLog, ElasticSearch e qualsiasi appender di terze parti che segua la stessa convenzione) richiedono la loro unit nella clausola uses. Dimenticarla produce un errore preciso (vedi sotto).

Sorgente JSON opzionale. Incorpora un JSON di default nelle risorse e sovrascrivi con un file su disco se presente:

uses System.IOUtils;

if TFile.Exists('loggerpro.json') then
  Log := LoggerProFromJSONFile('loggerpro.json')
else
  Log := LoggerProFromJSONString(LoadDefaultConfigFromResources);

Diagnostica degli errori

Il parser è strict by design - le misconfigurazioni falliscono ad alta voce invece di funzionare a metà silenziosamente. Tutti gli errori vengono sollevati come ELoggerProConfigError (dichiarata in LoggerPro.pas, quindi un singolo uses LoggerPro; è sufficiente per intercettarla).

Campo sconosciuto (cattura dei typo):

appenders[0] (type=Console): unknown field "colour".
Valid fields: minimumLevel, colors, colorScheme, prefix, utf8Output.

Type di appender sconosciuto (uses mancante):

appenders[1]: unknown type "ExeWatch".
Currently registered types: console, elasticsearch, file, filebysource,
htmlfile, jsonlfile, memory, outputdebugstring, simpleconsole,
timerotatingfile, udpsyslog, webhook.
If you want "ExeWatch", make sure the unit that registers it is in your
`uses` clause (typically LoggerPro.ExeWatchAppender) - optional
appenders self-register from their initialization section, so simply
including the unit is enough. For custom factories use
TLoggerProConfig.RegisterAppenderType.

Schema version troppo nuova:

configVersion 2 is newer than supported (max 1). Update LoggerPro.

Valore enum non valido:

appenders[0] (type=Console): invalid colorScheme "NEON".
Valid values: Default, Monochrome, GinBadge, GinMinimal, GinVibrant,
              Midnight, Nord, Matrix, Amber, Ocean, Cyberpunk.

File mancante o JSON malformato sollevano anch’essi ELoggerProConfigError, rispettivamente con il path del file e la diagnostica del parser.

Fallback graceful

Per scenari di first-run o deploy misconfigurati, intercetta l’errore e costruisci un default difensivo in codice così l’app continua a loggare invece di crashare:

uses LoggerPro, LoggerPro.Builder;

function BuildLoggerSafe(const aConfigPath: string): ILogWriter;
begin
  try
    Result := LoggerProFromJSONFile(aConfigPath);
  except
    on E: ELoggerProConfigError do
    begin
      Result := LoggerProBuilder
        .WriteToConsole.Done
        .WithMinimumLevel(TLogType.Info)
        .Build;
      Result.Warn(
        Format('Config fallback: %s', [E.Message]),
        'CONFIG');
    end;
  end;
end;

Il warning finisce nel logger di fallback stesso, così gli operatori notano il problema la prossima volta che fanno il tail dell’output.

Tipi di appender custom

LoggerPro.Config è un registry di tipi; i tuoi appender possono collegarsi nello stesso modo in cui lo fanno quelli predefiniti:

uses LoggerPro, LoggerPro.Config;

procedure MyCustomFactory(const aBuilder: ILoggerProBuilder;
  const aConfig: TJSONObject);
begin
  aBuilder.WriteToAppender(TMyCustomAppender.Create(
    aConfig.GetValue('endpoint').Value));
end;

initialization
  TLoggerProConfig.RegisterAppenderType(
    'MyCustom',
    MyCustomFactory,
    ['minimumLevel', 'endpoint']);   // closed set of allowed fields

Da quel momento in poi { "type": "MyCustom", "endpoint": "..." } funziona semplicemente, e i typo nei nomi di campo scatenano la stessa diagnostica strict dei predefiniti.

Sample: samples/240_config_simple, 241_config_advanced, 242_config_fallback.

Appender Pluggable (Pattern Auto-register)

Gli appender che puntano a sistemi esterni - ExeWatch, WindowsEventLog, ElasticSearch - restano FUORI dal package runtime core. Questo mantiene il core senza dipendenze e impedisce che SDK opzionali (come il client ExeWatch) diventino un requisito per ogni utente LoggerPro.

Come funziona: ogni unit di appender opzionale registra la propria factory JSON dalla propria sezione initialization. Aggiungere l’unit alla clausola uses di qualsiasi modulo del tuo progetto è sufficiente ad abilitare il suo valore "type" in loggerpro.json.

// main.dpr
uses
  LoggerPro,
  LoggerPro.ExeWatchAppender,          // enables "type": "ExeWatch"
  LoggerPro.WindowsEventLogAppender,   // enables "type": "WindowsEventLog"
  LoggerPro.ElasticSearchAppender;     // enables "type": "ElasticSearch"
begin
  Log := LoggerProFromJSONFile('loggerpro.json');
end.

Se un file JSON referenzia un appender la cui unit non è in uses, il messaggio di errore indica esattamente quale unit aggiungere.

Output LogFmt (Strutturato, grep-friendly)

LogFmt è un formato di logging strutturato orientato alle righe, reso popolare da Heroku e Brandur Leach. Ogni riga di log è una sequenza di coppie key=value separate da singoli spazi. I valori sono nudi quando è sicuro, altrimenti racchiusi tra doppie virgolette con escape \" e \\. È il punto di equilibrio fra testo leggibile dall’umano e JSON parseabile dalla macchina.

Esempio di output

time=2026-04-18T12:30:45.123Z threadid=7932 type=INFO msg="order placed" tag=ORDERS order_id=42 amount=99.95 paid=true

Come abilitarlo

Collega il renderer TLogItemRendererLogFmt a qualsiasi appender tramite il Builder:

uses
  LoggerPro, LoggerPro.Builder, LoggerPro.Renderers;

Log := LoggerProBuilder
  .WriteToConsole
    .WithRenderer(TLogItemRendererLogFmt.Create)
    .Done
  .WriteToFile
    .WithRenderer(TLogItemRendererLogFmt.Create)
    .Done
  .Build;

Log.Info('order placed', 'ORDERS', [
  LogParam.I('order_id', 42),
  LogParam.F('amount', 99.95),
  LogParam.B('paid', True)
]);

Oppure impostalo globalmente come renderer di default:

LoggerPro.Renderers.gDefaultLogItemRenderer := TLogItemRendererLogFmt;

Perché LogFmt

  • Leggibile nei terminali: record su una riga, nessun rumore finale.
  • Banalmente greppable: grep 'order_id=42' funziona e basta.
  • Streaming-friendly: ogni riga è autocontenuta - nessun oggetto JSON multi-riga da ricomporre dallo stdout del container.
  • Economico da produrre: nessun serializzatore JSON escape-heavy nel path caldo.
  • Tooling: parsato nativamente da humanlog, lnav, Grafana Loki, Vector, Fluent Bit, Promtail, Filebeat.

Conformità alla spec

Il renderer LogFmt di LoggerPro:

  • Virgoletta i valori contenenti spazio, ", =, \ o caratteri di controllo.
  • Escapa " come \", \ come \\, \n \r \t come sequenze di escape letterali.
  • I byte di controllo non stampabili diventano \uNNNN.
  • Sanifica le chiavi di contesto a [a-zA-Z0-9_.-] (i caratteri invalidi diventano _).
  • I float usano sempre . come separatore decimale (locale-independent).
  • I booleani vengono renderizzati come true / false nudi.

Questo significa che l’output è sicuro da streamare una-riga-alla-volta attraverso grep, awk, jq -R, il parser logfmt di Loki, ecc., senza corruzione.

Interrogare log LogFmt su Windows

1. ripgrep (rg) - filtro universale

Installazione:

# Option A: winget (Windows 10/11)
winget install BurntSushi.ripgrep.MSVC

# Option B: Scoop
scoop install ripgrep

# Option C: download ripgrep-*.zip from GitHub releases, unzip, put rg.exe on PATH

Uso:

# All errors
rg "type=ERROR" logs\myapp*.log

# One specific order, any log level
rg "order_id=42\b" logs\myapp*.log

# Errors for a given user in the last file only
rg "type=ERROR.*user_id=7" (Get-ChildItem logs\myapp*.log | Sort LastWriteTime -Desc | Select -First 1).FullName

# Count errors per tag
rg -o "tag=\S+" logs\myapp*.log | Group-Object | Sort Count -Desc

2. humanlog - pretty-printer & filtro logfmt-aware

humanlog è un binario Go che comprende logfmt (e JSON) nativamente: colora i livelli, allinea le colonne, parsa i timestamp e ti permette di filtrare con un mini-linguaggio di espressioni. Molto più piacevole di rg quando stai leggendo i log, non solo greppando.

Installazione:

# Download humanlog_<version>_windows_amd64.zip from GitHub releases, unzip, put
# humanlog.exe on PATH. Or via Scoop:
scoop bucket add extras
scoop install humanlog

Uso:

# Pretty-print a static log file
Get-Content logs\myapp.20260418.log | humanlog

# Pipe directly from your Delphi app's stdout (console appender + logfmt)
.\MyApp.exe | humanlog

# Filter: only errors (mini-expression language)
Get-Content logs\*.log | humanlog --skip "type!=ERROR"

# Keep only matching records
Get-Content logs\*.log | humanlog --keep "tag=ORDERS and type=ERROR"

# Hide noisy context keys
Get-Content logs\*.log | humanlog --ignore "threadid,time"

Live tail (stile tail -f)

Get-Content -Wait di PowerShell è il mattoncino per il live tailing su Windows:

Get-Content logs\myapp.20260418.log -Wait -Tail 20

Nota che Get-Content -Wait osserva l’handle del file originale e non seguirà la rotazione giornaliera/dimensionale di LoggerPro. Per tecniche avanzate (loop re-tail, piping dello stdout di processo, insidie di encoding), vedi il blog.

Fallback zero-install: Select-String

Se non puoi installare nulla su una macchina di produzione, Select-String è incluso in ogni installazione Windows:

# Errors for tag ORDERS
Select-String -Path logs\myapp*.log -Pattern "type=ERROR.*tag=ORDERS"

# Context block around a match (2 lines before/after)
Select-String -Path logs\*.log -Pattern "order_id=42\b" -Context 2,2

Quando andare oltre i tool grep-style

Una volta che hai molti file, host multipli o >GB/giorno di log, smetti di greppare e inizia a spedire:

  • Grafana Loki + Promtail - LogQL con parser nativo | logfmt:

    {app="myapp"} | logfmt | type="ERROR" | order_id="42"
    
  • Vector (singolo .exe, config-driven) - parsa con il codec logfmt, spedisci a Elastic, Clickhouse, Datadog, S3, ecc.

  • Fluent Bit (singolo .exe) - simile, leggero.

LogFmt vs JSONL - quando scegliere quale

LoggerPro supporta anche JSONL (un oggetto JSON per riga) tramite TLoggerProJSONLFileAppender. Regola del pollice:

  • LogFmt → macchine di sviluppo, stdout di container, log di produzione greppable, volume basso/medio, contesto flat.
  • JSONL → strutture annidate, pipeline di analytics, ingest Elastic/Datadog/OpenObserve, volume alto, schema stretto.

Entrambi i renderer condividono la stessa API di contesto LogParam.S/I/F/B/D, quindi puoi passare dall’uno all’altro senza cambiare il codice applicativo.

FileBySource Appender

Novità della 2.1. Organizza i log in sottocartelle per-sorgente - perfetto per applicazioni multi-tenant dove ogni client, device o account ottiene il proprio stream di log. La chiave sorgente viene estratta dal contesto del log.

uses
  LoggerPro.Builder;

Log := LoggerProBuilder
  .WriteToFileBySource
    .WithLogsFolder('logs')
    .WithMaxFileSizeInKB(5000)
    .WithRetainDays(30)
    .WithDefaultSource('default')
    .Done
  .Build;

// Source comes from the context
Log.Info('Order placed', 'ORDERS', [
  LogParam.S('source', 'ClientA'),
  LogParam.I('order_id', 42)
]);
// → logs/ClientA/ClientA.ORDERS.20260418.00.log

La rotazione è giorno + dimensione: un nuovo file viene aperto al cambio giorno, e quando il file corrente supera WithMaxFileSizeInKB. I file più vecchi di WithRetainDays vengono eliminati automaticamente all’avvio e a ogni cambio giorno.

Visualizzatore HTML di Log in Tempo Reale

Novità della 2.1. Un file di log HTML autocontenuto che puoi aprire in qualsiasi browser - nessun server, nessun asset esterno, un .html per rotazione. Utile per consegnare un artefatto compatto di troubleshooting a utenti, QA o supporto.

uses LoggerPro, LoggerPro.Builder;

Log := LoggerProBuilder
  .WriteToHTMLFile
    .WithLogsFolder('logs')
    .WithFileBaseName('myapp')
    .WithTitle('MyApp - Operations Log')
    .WithMaxFileSizeInKB(1000)
    .WithMaxBackupFiles(10)
    .Done
  .Build;

La pagina generata include:

  • Barra filtri sticky - checkbox per-livello e una casella di ricerca full-text.
  • Colorazione delle righe - le righe WARNING / ERROR / FATAL portano una tinta di sfondo delicata così le anomalie saltano all’occhio durante lo scroll.
  • Rendering del contesto - il contesto strutturato LogParam viene mostrato come coppie key=value in una riga secondaria, nascosta o mostrata dagli stessi controlli di filtro.
  • Export CSV / JSON - scarica le righe attualmente visibili.
  • Live tail - mentre il file è ancora in scrittura, la pagina si ricarica automaticamente ogni 3 secondi e fa sempre lo scroll al fondo.
  • Consapevolezza LIVE / FINALIZED - la pagina sa se il file di log è ancora in scrittura o è stato chiuso e ferma l’auto-reload nel momento in cui viene finalizzato.

Sample: samples/230_html_file_appender. Esposto anche alla config JSON come "type": "HTMLFile".

Output Console UTF-8 (Docker / Windows)

Di default, il Writeln di Delphi converte all’encoding del locale di sistema, il che storpia i caratteri non-ASCII nei container Docker (locale POSIX/C) e nelle console Windows (CP 437/1252). Abilita WithUTF8Output per scrivere byte UTF-8 direttamente su stdout:

Log := LoggerProBuilder
  .WriteToConsole
    .WithUTF8Output
    .Done
  .Build;

// Also available for the plain (no-color) console appender
Log := LoggerProBuilder
  .WriteToSimpleConsole
    .WithUTF8Output
    .Done
  .Build;

È particolarmente utile quando esegui applicazioni Delphi in container Docker o quando logghi testo Unicode (CJK, cirillico, emoji, ecc.) su Windows.

Inizializzazione DLL-Safe

LoggerPro 2.1 funziona correttamente all’interno di DLL caricate via LoadLibrary o P/Invoke. L’inizializzazione del thread logger rileva il contesto DLL ed evita il deadlock del Windows Loader Lock che affliggeva le versioni precedenti.

library MyPlugin;

uses
  LoggerPro, LoggerPro.Builder;

var
  GLog: ILogWriter;

begin
  // Safe during DLL_PROCESS_ATTACH
  GLog := LoggerProBuilder
    .WriteToFile.Done
    .Build;
  GLog.Info('DLL loaded successfully');
end.

Nota: Chiama GLog.Shutdown prima che la DLL venga scaricata se devi garantire il flush dei messaggi in coda.

Logging Contestuale

Le feature di logging contestuale di LoggerPro ti permettono di arricchire ogni chiamata di log con coppie key-value strutturate senza ripeterti.

WithProperty (contesto ad-hoc)

Log.WithProperty('order_id', 12345)
   .WithProperty('amount', 99.99)
   .Info('Order processed', 'orders');

WithDefaultTag (sub-logger)

var
  OrderLog: ILogWriter;
begin
  OrderLog := Log.WithDefaultTag('ORDERS');
  OrderLog.Info('Processing started');   // tag = 'ORDERS'
  OrderLog.Warn('Stock low');            // tag = 'ORDERS'
end;

WithDefaultContext (contesto persistente)

var
  RequestLog: ILogWriter;
begin
  RequestLog := Log.WithDefaultContext([
    LogParam.S('request_id', 'req-123'),
    LogParam.S('client_ip', '192.168.1.100')
  ]);

  RequestLog.Info('Request received');    // includes request_id, client_ip
  RequestLog.Info('Response sent');       // includes request_id, client_ip
end;

Contesto strutturato inline

Log.Info('Order completed', 'ORDERS', [
  LogParam.I('order_id', 12345),
  LogParam.S('customer', 'John Doe'),
  LogParam.F('total', 299.99),
  LogParam.B('paid', True)
]);

Exception Logging

try
  // Code that may raise
except
  on E: Exception do
  begin
    Log.LogException(E);
    Log.LogException(E, 'Database query failed');
    Log.LogException(E, 'Query failed', 'db');
  end;
end;

Formatter di stack trace

Integra con JCL, madExcept, EurekaLog o qualsiasi libreria di stack trace:

Log := LoggerProBuilder
  .WithStackTraceFormatter(
    function(E: Exception): string
    begin
      Result := JclLastExceptStackListToString;
    end)
  .WriteToFile.Done
  .Build;

Filtro per Livello Minimo

Filtra i messaggi globalmente prima che vengano accodati - overhead zero per i messaggi filtrati:

Log := LoggerProBuilder
  .WithMinimumLevel(TLogType.Warning)  // Debug and Info filtered
  .WriteToFile.Done
  .Build;

Log.Debug('Not logged');   // Filtered - no TLogItem created
Log.Info('Not logged');    // Filtered - no TLogItem created
Log.Warn('Logged');        // OK

Novità della 2.1: il gate è una property first-class su ILogWriter, così puoi cambiarlo a runtime senza cast:

Log.MinimumLevel := TLogType.Fatal;  // effectively mute

// Later
Log.MinimumLevel := TLogType.Debug;  // re-enable everything

ElasticSearch con Autenticazione

Novità della 2.1. L’appender ElasticSearch ora supporta tutti e tre i meccanismi di autenticazione comuni:

// Basic Auth
Log := LoggerProBuilder
  .WriteToElasticSearch
    .WithURL('https://elastic.example.com:9200/logs/_doc')
    .WithBasicAuth('username', 'password')
    .Done
  .Build;

// API Key
Log := LoggerProBuilder
  .WriteToElasticSearch
    .WithHost('https://elastic.example.com')
    .WithPort(9200)
    .WithIndex('app-logs')
    .WithAPIKey('your-api-key-here')
    .Done
  .Build;

// Bearer Token (JWT, OAuth2)
Log := LoggerProBuilder
  .WriteToElasticSearch
    .WithURL('https://elastic.example.com:9200/logs/_doc')
    .WithBearerToken('your-jwt-token')
    .Done
  .Build;

Integrazione con ExeWatch (Cloud Observability)

Cos’è ExeWatch. ExeWatch è un servizio di cloud observability per applicazioni desktop e backend: raccoglie log, eccezioni, breadcrumb, identità utente, info device e metriche custom, e ti dà una dashboard per investigare gli incident in produzione senza dover spostare file di log.

Perché un appender dedicato. ExeWatch distribuisce il proprio SDK Delphi (ExeWatchSDKv1.pas). Il bridge LoggerPro - unit LoggerPro.ExeWatchAppender - trasforma ogni chiamata Log.Info / Warn / Error / Fatal / LogException nella corrispondente chiamata SDK, così mantieni l’API LoggerPro e guadagni trasparentemente la pipeline ExeWatch. Non fa parte del package runtime di LoggerPro, quindi i progetti che non usano ExeWatch non pagano nulla.

Abilitare il bridge. Aggiungi la cartella SDK al search path del progetto (il sample usa C:\dev\exewatchsamples\DelphiCommons) e includi l’unit bridge:

uses
  LoggerPro,
  LoggerPro.Builder,
  LoggerPro.ExeWatchAppender;

L’SDK viene inizializzato automaticamente al Setup dell’appender - NON devi chiamare tu InitializeExeWatch, e l’appender non interferirà con un SDK già inizializzato da altro codice.

Quattro modi per collegarlo

1. Builder fluente - tutto in codice; OK quando API key, customer ID e versione sono literal o arrivano da variabili globali semplici. Chaina come qualsiasi appender predefinito:

Log := WithExeWatch(LoggerProBuilder)
    .WithAPIKey('ew_win_xxxxxx')
    .WithCustomerId('Acme Corp')
    .WithAppVersion('2.3.1')
    .WithAnonymizeDeviceId(False)  // True = per-install ID (GDPR-friendly)
    .Done
  .WriteToConsole.WithColors.Done  // mirror to the console too
  .Build;

2. Chain fluente su base JSON - abbina un loggerpro.json con la configurazione ExeWatch lato codice. Il file di base porta il setup console/file/HTML; i segreti SDK restano in codice, da dove possono essere letti da un vault, una variabile d’ambiente o un license server:

uses
  LoggerPro, LoggerPro.Builder, LoggerPro.ExeWatchAppender;

Log := WithExeWatch(
      LoggerProBuilderFromJSONFile('loggerpro.json'))
    .WithAPIKey(LoadFromVault('ew_api_key'))
    .WithCustomerId(CurrentTenant)
    .WithAppVersion(GetFileVersion)
    .Done
  .Build;

3. Imperativo (minor attrito quando i valori arrivano da oggetti di configurazione):

Log := LoggerProBuilder
  .WriteToAppender(NewExeWatchAppender(
    'ew_win_xxxxxx', 'Acme Corp', '2.3.1'))
  .Build;

4. Configurazione JSON pura (grazie al pattern auto-register, non serve alcuna chiamata extra di registrazione):

{
  "configVersion": 1,
  "appenders": [
    { "type": "Console" },
    {
      "type": "ExeWatch",
      "apiKey": "ew_win_xxxxxx",
      "customerId": "Acme Corp",
      "appVersion": "2.3.1",
      "anonymizeDeviceId": false
    }
  ]
}
uses LoggerPro, LoggerPro.ExeWatchAppender;
Log := LoggerProFromJSONFile('loggerpro.json');

Mappatura dei livelli

TLogType Severity SDK ExeWatch
Debug EW.Debug
Info EW.Info
Warning EW.Warning
Error EW.Error
Fatal EW.Fatal

Il Tag del log viene inoltrato come tag SDK. Il contesto LogParam strutturato viene collassato nel corpo del messaggio formattato - se vuoi le feature SDK più ricche (breadcrumb, timings, identità utente, gauge), chiama direttamente EW.AddBreadcrumb / EW.SetUser / EW.StartTiming affianco a LoggerPro. I due livelli convivono liberamente.

Shutdown

Log.Shutdown drena la coda LoggerPro e poi chiama EW.Flush, così ogni evento accodato lato client viene spedito prima che il processo termini. La finalization dell’SDK si occupa del resto.

Sample: samples/260_exewatch_appender.

UDP Syslog (RFC 5424) con Local Time

Nuova opzione WithUseLocalTime - la RFC 5424 richiede UTC, ma molti server syslog on-premise si aspettano local time.

Log := LoggerProBuilder
  .WriteToUDPSyslog
    .WithHost('syslog.example.com')
    .WithPort(514)
    .WithApplication('MyApp')
    .WithUseLocalTime(True)   // default: False (UTC)
    .Done
  .Build;

Ottenere il Nome del File di Log Corrente

Novità della 2.1. Utile per upload, invio via email o attach di un file di log on-demand.

uses LoggerPro, LoggerPro.Builder, LoggerPro.FileAppender;

var
  lAppender: TLoggerProSimpleFileAppender;
  Log: ILogWriter;
begin
  lAppender := TLoggerProSimpleFileAppender.Create;
  Log := LoggerProBuilder
    .WriteToAppender(lAppender)
    .Build;

  Log.Info('Message');
  UploadLogFile(lAppender.GetCurrentLogFileName);
end;

Per TLoggerProFileAppender (un file per tag):

var
  lAppender: TLoggerProFileAppender;
begin
  lAppender := TLoggerProFileAppender.Create;
  // Get file for a specific tag
  lFileName := lAppender.GetCurrentLogFileName('ORDERS');
  // Or all current log files
  lAllFiles := lAppender.GetAllCurrentLogFileNames;
end;

Shutdown

Chiama Shutdown nella finalization della tua applicazione per garantire che tutti i log pendenti vengano scritti:

procedure TMyApp.Finalize;
begin
  Log.Shutdown;   // Flush queue, stop thread
  Log := nil;
end;

Comportamenti chiave:

  • Idempotente: sicuro da chiamare più volte.
  • Fa il flush di tutti i messaggi pendenti.
  • Termina il thread logger.
  • Dopo lo shutdown, le chiamate di log vengono ignorate silenziosamente (Release) o scattano un assert (Debug).

Appender Integrati

LoggerPro 2.1 include 20+ appender. Tutti sono asincroni, thread-safe e configurabili tramite il Builder.

File Appender

Appender Metodo Builder Descrizione
FileAppender WriteToFile Un file per tag con rotazione per dimensione. Default: 5 backup, 1 MB max. Supporta rotazione per tempo.
SimpleFileAppender WriteToFile Tutti i log in un singolo file (nessuna separazione per tag). Stesse opzioni di rotazione.
JSONLFileAppender WriteToJSONLFile Un oggetto JSON per riga. Ideale per aggregatori di log.
TimeRotatingFileAppender WriteToTimeRotatingFile Nuovo file a ogni intervallo temporale (orario/giornaliero/settimanale/mensile).
FileByFolderAppender (diretto) Organizza i log in sottocartelle giornaliere (Logs/20260418/app.00.log).
FileBySourceAppender (nuovo) WriteToFileBySource Sottocartelle per-sorgente con rotazione giorno+dimensione e retention per giorni.
HTMLFileAppender (nuovo) WriteToHTMLFile .html autocontenuto navigabile con barra filtri, colorazione per livello, export CSV/JSON e live tail.

Console Appender

Appender Metodo Builder Descrizione
ConsoleAppender WriteToConsole Cross-platform con colori (Windows API / ANSI). Auto-crea la console per le app GUI su Windows. WithUTF8Output per Docker/Unicode.
SimpleConsoleAppender WriteToSimpleConsole Writeln semplice, nessun colore. Funziona ovunque. WithUTF8Output disponibile.

Appender Remoti / Network

Appender Metodo Builder Descrizione
ExeWatchAppender (pluggable) WithExeWatch(builder) Osservabilità cloud first-class via ExeWatch. Si auto-registra in JSON.
WebhookAppender (rinominato) WriteToWebhook HTTP POST verso endpoint REST. Timeout, header custom, autenticazione API-key (header o query string).
ElasticSearchAppender (pluggable) WriteToElasticSearch Spedisce log a ElasticSearch 6.4+. Supporta Basic Auth, API Key, Bearer Token. Si auto-registra in JSON.
UDPSyslogAppender WriteToUDPSyslog Syslog UDP RFC 5424. Local time o UTC.
EMailAppender (diretto) SMTP (via Indy TIdSMTP).
NSQAppender (diretto) Pubblica i log sulla message queue distribuita NSQ.
RedisAppender (contrib) Memorizza i log in liste Redis.

UI Appender

Appender Metodo Builder Descrizione
StringsAppender WriteToStrings Aggiunge a qualsiasi TStrings (TMemo.Lines, TStringList). Cross-platform.
VCLMemoAppender WriteToVCLMemo TMemo VCL. Solo Windows.
VCLListBoxAppender WriteToVCLListBox TListBox VCL. Solo Windows.
VCLListViewAppender WriteToVCLListView TListView VCL multi-colonna. Solo Windows.

Appender di Sistema / Debug

Appender Metodo Builder Descrizione
OutputDebugStringAppender WriteToOutputDebugString OutputDebugString di Windows.
WindowsEventLogAppender (pluggable) WriteToWindowsEventLog Windows Event Log (applicazioni e Service). Si auto-registra in JSON.
MemoryAppender WriteToMemory Ring buffer thread-safe.
CallbackAppender WriteToCallback Invoca la tua callback per ogni log item.

Appender Database

Appender Metodo Builder Descrizione
FireDACAppender WriteToFireDAC Logging su database via stored procedure FireDAC.
ADOAppender (diretto) Logging su database via stored procedure ADO.

Filtro / Proxy

Appender Metodo Builder Descrizione
FilterProxy WriteToFilteredAppender Avvolge un qualsiasi appender con una funzione di filtro custom.

Gli appender marcati (diretto) si usano via BuildLogWriter([appender]) o .WriteToAppender(appender).

Integrazione Windows Event Log

Applicazioni regolari

Log := LoggerProBuilder
  .WriteToWindowsEventLog
    .WithSourceName('MyApplication')
    .WithMinimumLevel(TLogType.Warning)
    .Done
  .Build;

Windows Service

procedure TMyService.ServiceCreate(Sender: TObject);
begin
  FLog := LoggerProBuilder
    .WriteToWindowsEventLogForService(Self)
      .Done
    .WriteToFile
      .WithLogsFolder('C:\ProgramData\MyService\Logs')
      .Done
    .Build;
end;

Livelli di Log

Log.Debug('Detailed debug information');   // TLogType.Debug
Log.Info('General information');           // TLogType.Info
Log.Warn('Warning conditions');            // TLogType.Warning
Log.Error('Error conditions');             // TLogType.Error
Log.Fatal('Critical failures');            // TLogType.Fatal

Compatibilità con le Versioni Delphi

Versione LoggerPro Delphi minimo Note
2.1.x (corrente) Delphi 10.2 Tokyo Piena compatibilità da 10.2+
2.0.x Delphi 10.3 Rio Guida precedente
1.x (legacy) Delphi 10 Seattle Guida legacy

Testato su: Delphi 13 Florence, 12 Athens, 11 Alexandria, 10.4 Sydney, 10.3 Rio.

Piattaforme: Windows (32/64-bit), Linux, macOS, Android, iOS.

Installazione

Opzione 1: Download della release (consigliato)

Scarica LoggerPro 2.1.0

  1. Estrai lo ZIP in una cartella (es. C:\Libraries\LoggerPro).
  2. In Delphi: Tools > Options > Language > Delphi > Library.
  3. Aggiungi al Library Path per la tua target platform:
    • C:\Libraries\LoggerPro (unit principali)
    • C:\Libraries\LoggerPro\contrib (opzionale: appender Redis ed Email)
  4. uses LoggerPro, LoggerPro.Builder; nel tuo codice.

Tutte le release: github.com/danieleteti/loggerpro/releases

Opzione 2: BOSS

BOSS è un package manager open-source per Delphi e Lazarus.

boss init        # skip if you already have a boss.json
boss install github.com/danieleteti/loggerpro

BOSS scarica LoggerPro in modules/ e aggiorna il search path del progetto. Committa boss.json e boss-lock.json; aggiungi modules/ al .gitignore.

Opzione 3: Clone del repository (solo contributor)

git clone https://github.com/danieleteti/loggerpro.git

Aggiungi la cartella root e contrib al tuo Library Path. Usa questo solo se vuoi testare feature non rilasciate o contribuire; il branch master potrebbe essere instabile.


Progetti Correlati

Progetto Descrizione
DMVCFramework Framework REST API con integrazione LoggerPro built-in
DelphiRedisClient Client Redis per TLoggerProRedisAppender

FAQ

Cosa c’è di nuovo in LoggerPro 2.1?

Configurazione JSON (LoggerProFromJSONFile), un visualizzatore HTML di log autocontenuto, integrazione first-class con l’osservabilità cloud ExeWatch, un renderer LogFmt conforme alla spec, un appender FileBySource per log per-tenant, output console UTF-8 per Docker, inizializzazione DLL-safe, autenticazione ElasticSearch (Basic/APIKey/Bearer), UDP Syslog local time e un’API GetCurrentLogFileName sugli appender file.

LoggerPro 2.1 è backward compatible con la 2.0?

Sì, è un aggiornamento drop-in. Non serve alcuna modifica al codice. Tutti i metodi Builder della 2.0 e tutti i pattern BuildLogWriter della 1.x continuano a funzionare.

Come emetto output LogFmt?

Collega il renderer: .WriteToConsole.WithRenderer(TLogItemRendererLogFmt.Create).Done. Vedi la sezione Output LogFmt.

Come interrogo log LogFmt su Windows?

Installa ripgrep (singolo .exe, winget install BurntSushi.ripgrep.MSVC) per filtri regex veloci, o humanlog per pretty-printing colorato. Combina con Get-Content -Wait per il live tailing. Vedi la sezione Interrogare log LogFmt su Windows.

LoggerPro può essere usato in una DLL?

Sì, la 2.1 rileva il contesto DLL ed evita il deadlock del Windows Loader Lock. Chiama Shutdown prima dell’unload della DLL.

Come ottengo output UTF-8 corretto in Docker?

Usa .WriteToConsole.WithUTF8Output.Done. Scrive byte UTF-8 direttamente su stdout, bypassando la conversione locale di Delphi.

Come aggiungo contesto ai log?

Usa Log.WithProperty('key', value).Info('msg') per contesto ad-hoc, o Log.WithDefaultContext([...]) per contesto persistente. Oppure passa contesto strutturato inline: Log.Info('msg', 'tag', [LogParam.I('id', 42)]).

Devo chiamare Shutdown?

Sì, chiama Log.Shutdown nella finalization della tua applicazione. È idempotente e garantisce che i log pendenti vengano scritti prima dell’uscita. Particolarmente importante all’interno di DLL, Windows Service e app containerizzate con lifetime brevi.

LoggerPro supporta il logging asincrono?

Sì - ogni appender gira sul proprio thread di background. Le chiamate di log ritornano immediatamente; un thread logger dispaccia gli item alla coda di ogni appender.

Quali appender hanno supporto Builder nativo?

File, JSONL File, Time Rotating File, FileBySource (nuovo), Console, Simple Console, OutputDebugString, HTTP, ElasticSearch, UDP Syslog, FireDAC, Memory, Callback, Strings, VCL (Memo, ListBox, ListView), Windows Event Log. Redis, Email, NSQ vengono aggiunti via .WriteToAppender().

Posso filtrare i log per livello a runtime?

Sì, sia globalmente con .WithMinimumLevel() al build, sia dinamicamente via Log.MinimumLevel := TLogType.Fatal;.

Come loggo su Windows Event Log da un Windows Service?

FLog := LoggerProBuilder
  .WriteToWindowsEventLogForService(Self).Done
  .Build;

Passa l’istanza TService - LoggerPro usa TService.LogMessage per un logging corretto in modalità Service.

Quali versioni di Delphi sono supportate?

La 2.1 supporta Delphi 10.2 Tokyo e successive (fino a Delphi 13 Florence). Linux, macOS, Android e iOS sono pienamente supportati.


LoggerPro 2.1 è il moderno framework di logging asincrono per Delphi / Object Pascal - API con pattern Builder, logging contestuale strutturato, renderer LogFmt conforme alla spec per Grafana Loki, appender FileBySource per-tenant, output console UTF-8 per Docker, inizializzazione DLL-safe, appender ElasticSearch / UDP Syslog / Windows Event Log. L’equivalente Delphi di Serilog. Thread-safe, cross-platform (Windows / Linux / macOS / Android / iOS), licenza Apache 2.0, mantenuto attivamente dal 2010.

Comments

comments powered by Disqus