Become a member!

LoggerPro 2.1 — Framework de Logging Asíncrono para Delphi

🌐
Este artículo está disponible también en otros idiomas:
🇬🇧 English  •  🇮🇹 Italiano  •  🇩🇪 Deutsch
📚
¿Buscas una versión anterior?
LoggerPro 2.0  •  LoggerPro 1.x (legacy)

TL;DR: LoggerPro 2.1 es el framework de logging asíncrono y thread-safe para Delphi. Mantiene la API fluida con patrón Builder de la 2.0 y añade configuración externa vía JSON (LoggerProFromJSONFile o LoggerProFromJSONString), observabilidad cloud con ExeWatch, un renderer LogFmt conforme a la especificación, un appender FileBySource para logs por tenant, salida UTF-8 en consola para Docker, inicialización segura desde DLL, autenticación ElasticSearch y más. Upgrade drop-in desde 2.0, licencia Apache 2.0, funciona desde Delphi 10.2 Tokyo hasta Delphi 13 Florence, en Windows / Linux / macOS / Android / iOS. Documentación LoggerPro 2.0 → · Documentación LoggerPro 1.x →

De un vistazo

NombreLoggerPro
Versión2.1.0 (abril de 2026)
LenguajeDelphi / Object Pascal
Delphi mínimo10.2 Tokyo · Probado hasta 13 Florence
PlataformasWindows, Linux, macOS, Android, iOS
LicenciaApache 2.0 (gratis para uso comercial)
AutorDaniele Teti
Repositoriogithub.com/danieleteti/loggerpro
InstalaciónBOSS · Release ZIP
CategoríaAsíncrono · Thread-safe · Pluggable · Logging estructurado
Equivalentes más cercanosSerilog (.NET), NLog (.NET), log4j / Logback (Java)

Logo LoggerPro 2.1

¿Qué es LoggerPro?

LoggerPro es el framework de logging asíncrono, thread-safe y pluggable para Delphi / Object Pascal - el equivalente Delphi más cercano a Serilog (.NET), NLog (.NET) o log4j / Logback (Java). Ofrece una API Builder fluida, contexto estructurado clave-valor, formatters de stack trace pluggables, más de 20 appenders integrados (archivo, consola, HTTP, observabilidad cloud ExeWatch, Grafana Loki vía LogFmt, ElasticSearch, UDP syslog, Windows Event Log, base de datos, VCL y más), y funciona multiplataforma en Windows, Linux, macOS, Android e iOS. LoggerPro tiene licencia Apache 2.0, se mantiene activamente desde 2010 y está en uso en miles de aplicaciones Delphi en producción.

La versión 2.1 (abril de 2026) es la release estable actual. Se apoya sobre la API fluida con patrón Builder introducida en 2.0 y añade una integración de primera clase con ExeWatch para observabilidad cloud end-to-end, además de features enfocadas a objetivos de despliegue modernos - contenedores Docker, agregadores de logs en la nube (Grafana Loki, Elastic, Datadog), aplicaciones multi-tenant y DLLs Delphi - manteniendo retrocompatibilidad total.

Novedades de la 2.1

FeatureQué te aporta
Configuración JSONReconfigura el logger en tiempo de despliegue - LoggerProFromJSONFile('loggerpro.json'). Validación estricta de campos, diagnósticos para tipos desconocidos
Visor HTML de logs en vivoArchivo .html autocontenido con barra de filtros fija, coloreo por nivel, búsqueda client-side, exportación CSV/JSON y live tailing en el navegador
Integración con ExeWatchAppender de observabilidad cloud de primera clase para ExeWatch - uso imperativo, fluido o vía JSON
Patrón de appenders pluggablesBackends opcionales (ExeWatch, WindowsEventLog, ElasticSearch) se auto-registran desde su propia unit - solo añade la cláusula uses
MinimumLevel en runtimeILogWriter.MinimumLevel es ahora una propiedad de primera clase - cambia el gate global al vuelo
Appender WebhookRenombrado desde HTTPAppender; añadida autenticación por API-key (header o query-string)
Renderer LogFmtSalida key=value conforme a spec; greppable, amigable con Loki, registros de una sola línea
Appender FileBySourceSubcarpetas por fuente (por tenant, por cliente) con rotación día+tamaño
Salida UTF-8 en consolaUnicode correcto en contenedores Docker y consolas Windows (WithUTF8Output)
Inicialización segura desde DLLCorrige el deadlock del Windows Loader Lock al usar LoggerPro desde una DLL
Autenticación ElasticSearchSoporte para Basic Auth, API Key y Bearer Token
UDP Syslog hora localOpción WithUseLocalTime(True) en el appender de syslog
GetCurrentLogFileNameRecupera la ruta del archivo de log activo - útil para upload, email, restart

¿Actualizando desde 2.0? Mayormente un reemplazo drop-in. Un solo breaking change: WriteToHTTP se renombró a WriteToWebhook (basta un buscar-y-reemplazar). Todo lo demás es aditivo.

Inicio rápido con la 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;

Configuración JSON

Novedad de la 2.1. Distribuye tu app con un loggerpro.json junto al EXE y reconfigura el logger en tiempo de despliegue sin recompilar. Los operadores pueden cambiar backends, ajustar log levels o añadir/eliminar appenders sin tocar el código fuente.

Esquema de un vistazo

{
  "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" }
  ]
}

El gate global acepta todo (minimumLevel: Debug). Cada appender que no especifique su propio minimumLevel toma el valor plantilla Warning - Console y HTMLFile lo heredan ambos. El appender File opta por salirse y escribe el audit trail completo a Debug. Poner defaultMinimumLevel por debajo de minimumLevel sería un no-op: el gate global ya habría descartado esos mensajes antes de que alcanzaran cualquier appender.

Campos raíz:

CampoTipoPropósito
configVersionenteroVersión del esquema. Ausente = la más reciente. Superior a la de la librería = error duro.
minimumLevelstringGate global pre-cola. "Debug" / "Info" / "Warning" / "Error" / "Fatal". Los mensajes por debajo de esta severidad nunca entran en la cola - cero overhead para las llamadas filtradas.
defaultMinimumLevelstringValor plantilla que cada appender usa como su propio minimumLevel cuando la entrada no lo especifica. No es un gate - solo pre-rellena la umbral por appender en tiempo de parsing.
defaultTagstringTag por defecto para llamadas como Log.Info('msg') sin argumento de tag.
appendersarrayObligatorio. Un objeto por appender, cada uno con un "type" y campos específicos de tipo.

Campos comunes por appender:

CampoNotas
typeObligatorio. Case-insensitive, contrastado contra los nombres de tipo registrados.
minimumLevelOpcional. Severidad mínima que emite este appender. Los mensajes por debajo son descartados silenciosamente por ESTE appender (los otros los siguen viendo). Mismo dominio de valores que el minimumLevel raíz. Default a defaultMinimumLevel (o Debug si tampoco existe). Ponerlo por debajo del minimumLevel raíz es un no-op: esos mensajes no llegan al appender porque no pasaron el gate pre-cola.

Los campos específicos de cada tipo se listan en la sección del appender correspondiente en esta guía; los typos se detectan (ver Diagnósticos de error más abajo).

Los tres conceptos, desambiguados. Cada llamada de log lleva su propia severidad - Log.Info es Info, Log.Error es Error, y así. Ni minimumLevel ni defaultMinimumLevel la cambian; solo deciden quién ve qué. El minimumLevel raíz es un filtro pre-cola (gratuito: el TLogItem ni siquiera se construye para mensajes por debajo). El minimumLevel por appender es un gate de emisión (evaluado en el worker thread del appender, decide si ESTE appender escribe el mensaje). El defaultMinimumLevel en la raíz es un default a tiempo de escritura para el gate por appender, no un filtro runtime - te permite decir “cada appender por defecto Warning salvo que especifique otra cosa” sin repetir el campo en cada entrada.

Qué es obligatorio, qué tiene defaults

El mínimo absoluto es una sola entrada en el array:

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

Eso es todo. Todo lo demás es opcional o inferido. La clave appenders en la raíz es obligatoria (puede ser un array vacío para construir un logger no-op, pero debe estar presente). Cada entrada debe tener un "type"; cualquier otro campo es opcional.

Valores por defecto cuando un campo se omite:

CampoSi está ausenteNotas
configVersion raízSe trata como el último esquema conocido (actualmente 1).Un valor superior es error duro (guardia de forward-compat).
minimumLevel raízDebug - todo pasa el gate global pre-cola.Los mensajes por debajo de esta severidad se filtran antes del encolado (cero overhead).
defaultMinimumLevel raízDebugUsado como minimumLevel por defecto de cada appender que no fije el suyo.
defaultTag raíz"main"Usado por llamadas que no pasan tag (p. ej. Log.Info('msg')).
minimumLevel de appenderdefaultMinimumLevel (o Debug si tampoco existe).El appender emite solo mensajes a esta severidad o superior.
Campos específicos del appenderCada appender trae sus propios defaults (listados en su sección).P. ej. logsFolder de File es el directorio del EXE; Console por defecto tiene colores ON con el esquema Midnight (usa "colorScheme": null o "colors": false para optar por no tenerlos).

JSONs mínimos listos para usar

Loguear a un archivo con rotación (el despliegue más simple). Toma el directorio del EXE como logsFolder y el nombre del EXE como nombre base del archivo; 5 backups de 1 MB cada uno.

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

Si quieres colocar los archivos en otro sitio y mantener más historial:

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

Loguear a consola coloreada. Los colores están ON por defecto con el esquema profesional Midnight - basta un array de una sola entrada:

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

Sobrescribe el esquema por nombre (case-insensitive), o desactiva los colores por completo:

// 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 } ] }

Las tres formas de “opt out” producen texto plano, sin ANSI. Además, cada esquema coloreado se degrada automáticamente a texto plano cuando stdout se redirige a un archivo o se pipea a otro proceso - nunca acabas con códigos de escape en tus archivos de log por accidente.

Esquemas de color integrados

LoggerPro trae once esquemas. Todos respetan el mismo contrato de paleta (color por nivel + tag coloreado, metadata, claves y valores de contexto), solo enfatizan partes distintas. Los nombres de esquema son case-insensitive en JSON; las capturas de abajo son de referencia - lanza samples/03b_console_with_colors_appender para ver cada esquema renderizado en tu propio terminal con los mismos mensajes de ejemplo.

EsquemaDescripción
DefaultBaseline inspirado en Gin, solo foreground; color de nivel por severidad.
MonochromeSin ANSI - texto plano. Se aplica automáticamente cuando stdout se pipea/redirige.
GinBadgeTonos Default más “badge” con fondo coloreado para el nivel.
GinMinimalTodo gris tenue, solo la palabra de nivel mantiene color.
GinVibrantArcoíris saturado - cada campo un color distinto y llamativo.
MidnightPrefijo/tag magenta, claves verdes, valores cian. Default en JSON - legible en terminales claros y oscuros.
NordAzules y cianes fríos tipo Frost ártico, amarillo para warnings, rojo para fatal.
MatrixTodo verde; niveles renderizados como badges de fondo.
AmberMonitor CRT ámbar de los 80 - familia amarilla/naranja, rojo solo para errores.
OceanAzules y cianes por capas - tag verde azulado, valores cian brillante.
CyberpunkPrefijo magenta neón, tag cian, valores amarillos; badges de nivel vivos.

Elegir uno desde JSON. Solo referéncialo por nombre:

// 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" } ] }

Elegir uno desde código:

uses LoggerPro, LoggerPro.Builder;

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

Esquema custom. Cada esquema es un record TLogColorScheme - puedes construir el tuyo partiendo de cualquier preset y sobrescribiendo los campos que importen:

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. Cuando stdout se redirige a un archivo o se pipea a otro proceso, el renderer se degrada automáticamente a texto plano (equivalente a Monochrome). Nunca acabas con códigos de escape en tus archivos de log por accidente.

Otros campos opcionales:

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

Combina los dos para un setup típico de desarrollo - consola coloreada más archivo con rotación y niveles separados:

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

Puntos de entrada

Dos funciones globales en la unit LoggerPro - una devuelve un ILogWriter listo para usar, la otra devuelve el ILoggerProBuilder no finalizado para que el llamante pueda seguir encadenando:

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

Ambas funciones lanzan ELoggerProConfigError ante cualquier problema con el archivo - ver Diagnósticos de error más abajo para la redacción exacta.

Mezclar configuración de archivo con appenders solo en runtime

Algunos appenders no pueden describirse en JSON porque necesitan una referencia a un objeto en runtime que no cabe en un archivo de configuración: un callback, un TStrings, un componente VCL, una TFDConnection viva. El patrón es siempre el mismo:

  1. Carga la parte describible en JSON con LoggerProBuilderFromJSONFile.
  2. Encadena los extras sobre el builder devuelto.
  3. Llama .Build tú mismo.

Ejemplo 1 - Base JSON + callback de UI para una barra de estado.

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;

Ejemplo 2 - Base JSON + mirror en TListView VCL. El usuario configura archivos/consola desde JSON; el live-tail en GUI se queda en código.

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;

Ejemplo 3 - Base JSON + TMemo FMX. TMemo.Lines es un TStrings, así que el appender multiplataforma WriteToStrings cubre FMX, VCL y cualquier otra cosa que exponga un TStrings.

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

Ejemplo 4 - Base JSON + appender de base de datos. El JSON controla consola/archivo/HTML; la conexión a la BD se queda en código porque TFDConnection no es serializable.

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;

Escenarios y casos límite

El minimumLevel por appender es independiente del minimumLevel raíz. El gate raíz decide si un mensaje siquiera se encola; el gate del appender decide si ese appender escribe el mensaje. Un mensaje por debajo del minimumLevel raíz nunca alcanza ningún appender; un mensaje que pasa el gate raíz pero está por debajo del minimumLevel de un appender se descarta en ese appender, mientras que los demás sí lo reciben.

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

Resultado: dev ve todo en consola, el archivo de log mantiene Info+, el webhook solo se dispara ante errores.

Un array appenders vacío está permitido - obtienes un logger “agujero negro” útil para tests de integración:

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

Logging efectivamente deshabilitado es simplemente un gate global lo bastante alto como para que nada pase nunca:

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

O, en código, cambia la propiedad en runtime sobre un writer ya construido: Log.MinimumLevel := TLogType.Fatal;

Los appenders pluggables (ExeWatch, WindowsEventLog, ElasticSearch, y cualquier appender de terceros que siga la misma convención) necesitan su unit en uses. Olvidarlo produce un error preciso (ver abajo).

Fuente JSON opcional. Embebe un JSON por defecto en los recursos y sobrescríbelo con un archivo en disco si está presente:

uses System.IOUtils;

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

Diagnósticos de error

El parser es estricto por diseño - las malas configuraciones fallan en voz alta en lugar de funcionar a medias en silencio. Todos los errores emergen como ELoggerProConfigError (declarado en LoggerPro.pas, así que un único uses LoggerPro; basta para capturarlo).

Campo desconocido (detección de typos):

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

Tipo de appender desconocido (falta un uses):

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.

Versión del esquema demasiado nueva:

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

Valor de enum inválido:

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

Archivo ausente o JSON malformado también levantan ELoggerProConfigError, con la ruta del archivo y el diagnóstico del parser respectivamente.

Fallback con degradación controlada

Para escenarios de primer arranque o despliegue mal configurado, captura el error y construye un default defensivo en código para que la app siga logueando en lugar de caerse:

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;

El warning cae en el propio logger de fallback, así que los operadores notan el problema la próxima vez que hagan tail de la salida.

Tipos de appender custom

LoggerPro.Config es un registro de tipos; tus propios appenders pueden engancharse igual que los integrados:

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

Desde entonces { "type": "MyCustom", "endpoint": "..." } simplemente funciona, y los typos en los nombres de campo disparan el mismo diagnóstico estricto que los integrados.

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

Appenders Pluggables (patrón de auto-registro)

Los appenders que apuntan a sistemas externos - ExeWatch, WindowsEventLog, ElasticSearch - permanecen FUERA del package runtime principal. Eso mantiene el core libre de dependencias, y evita que SDKs opcionales (como el cliente de ExeWatch) sean requeridos por todos los usuarios de LoggerPro.

Cómo funciona: cada unit de appender opcional registra su propia factory JSON desde su sección initialization. Añadir la unit a la cláusula uses de cualquier módulo de tu proyecto basta para habilitar su valor "type" en 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.

Si un archivo JSON referencia a un appender cuya unit no está en uses, el mensaje de error deletrea exactamente qué unit añadir.

Salida LogFmt (estructurada, amigable con grep)

LogFmt es un formato de logging estructurado orientado a línea popularizado por Heroku y Brandur Leach. Cada línea de log es una secuencia de pares key=value separados por un único espacio. Los valores van sin entrecomillar cuando es seguro, si no van entrecomillados con " y escapes \" y \\. Es el punto medio entre logs de texto legibles por humanos y JSON parseable por máquinas.

Ejemplo de salida

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

Habilitarlo

Enchufa el renderer TLogItemRendererLogFmt a cualquier appender vía 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)
]);

O fíjalo globalmente como el renderer por defecto:

LoggerPro.Renderers.gDefaultLogItemRenderer := TLogItemRendererLogFmt;

Por qué LogFmt

  • Legible en terminales: registros de una línea, sin ruido colgante.
  • Trivialmente greppable: grep 'order_id=42' simplemente funciona.
  • Amigable con streaming: cada línea es autocontenida - sin objetos JSON multi-línea que recomponer desde el stdout de un contenedor.
  • Barato de producir: sin serializador JSON cargado de escapes en la ruta caliente.
  • Tooling: parseado nativamente por humanlog, lnav, Grafana Loki, Vector, Fluent Bit, Promtail, Filebeat.

Conformidad con la spec

El renderer LogFmt de LoggerPro:

  • Entrecomilla valores que contienen espacio, ", =, \ o caracteres de control.
  • Escapa " como \", \ como \\, \n \r \t como secuencias de escape literales.
  • Los bytes de control no imprimibles se convierten en \uNNNN.
  • Sanea las claves de contexto a [a-zA-Z0-9_.-] (los caracteres inválidos se vuelven _).
  • Los floats usan siempre . como separador decimal (independiente de locale).
  • Los booleanos se renderizan como true / false sin entrecomillar.

Esto significa que la salida es segura para ser transmitida línea-a-línea a través de grep, awk, jq -R, el parser logfmt de Loki, etc., sin corrupción.

Consultar logs LogFmt en Windows

1. ripgrep (rg) - filtro universal

Instalación:

# 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 y filtro logfmt-aware

humanlog es un binario Go que entiende logfmt (y JSON) de forma nativa: colorea niveles, alinea columnas, parsea timestamps y te permite filtrar con un mini-lenguaje de expresiones. Mucho más agradable que rg cuando estás leyendo logs, no solo grepeándolos.

Instalación:

# 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 (estilo tail -f)

Get-Content -Wait de PowerShell es el bloque de construcción para live tailing en Windows:

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

Ten en cuenta que Get-Content -Wait observa el handle de archivo original y no seguirá la rotación diaria/por tamaño de LoggerPro. Para técnicas avanzadas (bucles de re-tail, pipe del stdout del proceso, peculiaridades de encoding), ver el blog.

Fallback sin instalación: Select-String

Si no puedes instalar nada en una máquina de producción, Select-String viene integrado en toda instalación de 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

Graduándose más allá de las herramientas estilo grep

Una vez que tienes muchos archivos, múltiples hosts, o >GB/día de logs, deja de grepear y empieza a enviar:

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

    {app="myapp"} | logfmt | type="ERROR" | order_id="42"
    
  • Vector (un solo .exe, basado en config) - parsea con el codec logfmt, envía a Elastic, Clickhouse, Datadog, S3, etc.

  • Fluent Bit (un solo .exe) - similar, ligero.

LogFmt vs JSONL - cuándo elegir cada uno

LoggerPro también soporta JSONL (un objeto JSON por línea) vía TLoggerProJSONLFileAppender. Regla general:

  • LogFmt → máquinas de desarrollo, stdout de contenedores, logs de producción greppables, volumen bajo/medio, contexto plano.
  • JSONL → estructuras anidadas, pipelines de analytics, ingesta en Elastic/Datadog/OpenObserve, alto volumen, esquema estricto.

Ambos renderers comparten la misma API de contexto LogParam.S/I/F/B/D, así que puedes cambiar entre ellos sin cambiar el código de la aplicación.

Appender FileBySource

Novedad de la 2.1. Organiza los logs en subcarpetas por fuente - perfecto para aplicaciones multi-tenant donde cada cliente, dispositivo o cuenta obtiene su propio stream de logs. La clave de fuente se extrae del contexto 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 rotación es día + tamaño: se abre un nuevo archivo al cambiar el día, y cuando el archivo actual excede WithMaxFileSizeInKB. Los archivos más antiguos que WithRetainDays se eliminan automáticamente en el arranque y en cada cambio de día.

Visor HTML de Logs en Vivo

Novedad de la 2.1. Un archivo de log HTML autocontenido que puedes abrir en cualquier navegador - sin servidor, sin assets externos, un .html por rotación. Útil para entregar un artefacto compacto de troubleshooting a usuarios, QA o soporte.

uses LoggerPro, LoggerPro.Builder;

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

La página generada incluye:

  • Barra de filtros fija - checkboxes por nivel y caja de búsqueda de texto completo.
  • Coloreo de filas - las filas WARNING / ERROR / FATAL llevan un tinte de fondo suave para que las anomalías salten mientras se desplaza.
  • Renderizado de contexto - el contexto estructurado LogParam se muestra como pares key=value dentro de una fila secundaria, oculta o visible con los mismos controles de filtro.
  • Exportación CSV / JSON - descarga las filas actualmente visibles.
  • Live tail - mientras el archivo se sigue escribiendo, la página se auto-recarga cada 3 segundos y siempre hace scroll al final.
  • Conciencia LIVE / FINALIZED - la página sabe si el archivo de log sigue escribiéndose o se ha cerrado, y detiene la auto-recarga en el momento en que se finaliza.

Ejemplo: samples/230_html_file_appender. También expuesto a la configuración JSON como "type": "HTMLFile".

Salida UTF-8 en Consola (Docker / Windows)

Por defecto, el Writeln de Delphi convierte al encoding del locale del sistema, lo que distorsiona caracteres no ASCII en contenedores Docker (locale POSIX/C) y en consolas Windows (CP 437/1252). Habilita WithUTF8Output para escribir bytes UTF-8 directamente a stdout:

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

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

Esto es especialmente útil al ejecutar aplicaciones Delphi en contenedores Docker o al loguear texto Unicode (CJK, cirílico, emoji, etc.) en Windows.

Inicialización Segura desde DLL

LoggerPro 2.1 funciona correctamente dentro de DLLs cargadas vía LoadLibrary o P/Invoke. La inicialización del thread del logger detecta el contexto DLL y evita el deadlock del Windows Loader Lock que afectaba a versiones anteriores.

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: Llama GLog.Shutdown antes de descargar la DLL si necesitas garantizar que los mensajes encolados se vuelquen.

Logging Contextual

Las features de logging contextual de LoggerPro te permiten enriquecer cada llamada de log con pares clave-valor estructurados sin repetirte.

WithProperty (contexto 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 (contexto 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;

Contexto estructurado 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)
]);

Logging de Excepciones

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 de stack trace

Intégrate con JCL, madExcept, EurekaLog o cualquier librería de stack trace:

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

Filtrado por Nivel Mínimo

Filtra mensajes globalmente antes de que se encolen - cero overhead para mensajes filtrados:

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

Novedad de la 2.1: el gate es una propiedad de primera clase en ILogWriter, así que puedes cambiarlo en runtime sin ningún cast:

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

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

ElasticSearch con Autenticación

Novedad de la 2.1. El appender de ElasticSearch ahora soporta los tres mecanismos de autenticación comunes:

// 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;

Integración con ExeWatch (Observabilidad Cloud)

Qué es ExeWatch. ExeWatch es un servicio de observabilidad cloud para aplicaciones desktop y backend: recolecta logs, excepciones, breadcrumbs, identidad de usuario, info de dispositivo y métricas custom, y te da un dashboard para investigar incidentes en producción sin tener que mandar archivos de log de un lado a otro.

Por qué un appender dedicado. ExeWatch trae su propio SDK Delphi (ExeWatchSDKv1.pas). El puente de LoggerPro - la unit LoggerPro.ExeWatchAppender - convierte cada llamada Log.Info / Warn / Error / Fatal / LogException en la correspondiente llamada del SDK, así que conservas la API de LoggerPro y ganas de forma transparente el pipeline de ExeWatch. No forma parte del package runtime de LoggerPro, así que los proyectos que no usan ExeWatch no pagan nada.

Habilitando el puente. Añade la carpeta del SDK al search path de tu proyecto (el sample usa C:\dev\exewatchsamples\DelphiCommons) e incluye la unit del puente:

uses
  LoggerPro,
  LoggerPro.Builder,
  LoggerPro.ExeWatchAppender;

El SDK se inicializa automáticamente al hacer Setup del appender - NO necesitas llamar InitializeExeWatch tú mismo, y el appender no interferirá con un SDK ya inicializado por otro código.

Cuatro formas de cablearlo

1. Builder fluido - todo en código; vale cuando la API key, el customer ID y la versión son literales o vienen de variables globales simples. Encadena como cualquier appender integrado:

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. Cadena fluida sobre base JSON - combina un loggerpro.json con la configuración de ExeWatch lado código. El archivo base lleva el setup de consola/archivo/HTML; los secretos del SDK se quedan en código, desde donde pueden leerse de un vault, una variable de entorno 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 (mínima fricción cuando los valores vienen de objetos de configuración):

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

4. Configuración JSON pura (gracias al patrón de auto-registro, no se necesita una llamada de registro extra):

{
  "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');

Mapeo de niveles

TLogTypeSeveridad del SDK ExeWatch
DebugEW.Debug
InfoEW.Info
WarningEW.Warning
ErrorEW.Error
FatalEW.Fatal

El Tag del log se reenvía como el tag del SDK. El contexto estructurado LogParam se colapsa en el cuerpo del mensaje formateado - si quieres las features más ricas del SDK (breadcrumbs, timings, identidad de usuario, gauges), llama EW.AddBreadcrumb / EW.SetUser / EW.StartTiming directamente junto a LoggerPro. Las dos capas coexisten libremente.

Shutdown

Log.Shutdown drena la cola de LoggerPro y después llama EW.Flush, así que cualquier evento encolado del lado cliente se envía antes de que el proceso salga. La finalización propia del SDK se encarga del resto.

Ejemplo: samples/260_exewatch_appender.

UDP Syslog (RFC 5424) con Hora Local

Nueva opción WithUseLocalTime - RFC 5424 exige UTC, pero muchos servidores de syslog on-prem esperan hora local.

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

Obtener el Nombre del Archivo de Log Actual

Novedad de la 2.1. Útil para subir, enviar por email o adjuntar un archivo de log bajo demanda.

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;

Para TLoggerProFileAppender (un archivo por 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

Llama Shutdown en la finalización de tu aplicación para garantizar que todos los logs pendientes se escriban:

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

Comportamientos clave:

  • Idempotente: seguro de llamar múltiples veces.
  • Vuelca todos los mensajes pendientes.
  • Termina el thread del logger.
  • Tras el shutdown, las llamadas de log se ignoran silenciosamente (Release) o disparan un assert (Debug).

Appenders Integrados

LoggerPro 2.1 trae más de 20 appenders. Todos son asíncronos, thread-safe y configurables vía Builder.

Appenders de archivo

AppenderMétodo BuilderDescripción
FileAppenderWriteToFileUn archivo por tag con rotación por tamaño. Por defecto: 5 backups, máx 1 MB. Soporta rotación por tiempo.
SimpleFileAppenderWriteToFileTodos los logs en un único archivo (sin separación por tag). Mismas opciones de rotación.
JSONLFileAppenderWriteToJSONLFileUn objeto JSON por línea. Ideal para agregadores de logs.
TimeRotatingFileAppenderWriteToTimeRotatingFileNuevo archivo en cada intervalo de tiempo (cada hora/día/semana/mes).
FileByFolderAppender(directo)Organiza logs en subcarpetas diarias (Logs/20260418/app.00.log).
FileBySourceAppender (nuevo)WriteToFileBySourceSubcarpetas por fuente con rotación día+tamaño y retención por días.
HTMLFileAppender (nuevo)WriteToHTMLFile.html navegable autocontenido con barra de filtros, coloreo por nivel, exportación CSV/JSON y live tail.

Appenders de consola

AppenderMétodo BuilderDescripción
ConsoleAppenderWriteToConsoleMultiplataforma con colores (API de Windows / ANSI). Auto-crea consola para apps GUI en Windows. WithUTF8Output para Docker/Unicode.
SimpleConsoleAppenderWriteToSimpleConsoleWriteln plano, sin colores. Funciona en todos lados. WithUTF8Output disponible.

Appenders remotos / de red

AppenderMétodo BuilderDescripción
ExeWatchAppender (pluggable)WithExeWatch(builder)Observabilidad cloud de primera clase vía ExeWatch. Se auto-registra en JSON.
WebhookAppender (renombrado)WriteToWebhookHTTP POST a endpoints REST. Timeout, headers custom, autenticación API-key (header o query string).
ElasticSearchAppender (pluggable)WriteToElasticSearchEnvía logs a ElasticSearch 6.4+. Soporta Basic Auth, API Key, Bearer Token. Se auto-registra en JSON.
UDPSyslogAppenderWriteToUDPSyslogSyslog UDP RFC 5424. Hora local o UTC.
EMailAppender(directo)SMTP (vía Indy TIdSMTP).
NSQAppender(directo)Publica logs en la cola de mensajes distribuida NSQ.
RedisAppender(contrib)Almacena logs en listas Redis.

Appenders de UI

AppenderMétodo BuilderDescripción
StringsAppenderWriteToStringsAñade a cualquier TStrings (TMemo.Lines, TStringList). Multiplataforma.
VCLMemoAppenderWriteToVCLMemoTMemo VCL. Solo Windows.
VCLListBoxAppenderWriteToVCLListBoxTListBox VCL. Solo Windows.
VCLListViewAppenderWriteToVCLListViewTListView VCL multi-columna. Solo Windows.

Appenders de sistema / debug

AppenderMétodo BuilderDescripción
OutputDebugStringAppenderWriteToOutputDebugStringOutputDebugString de Windows.
WindowsEventLogAppender (pluggable)WriteToWindowsEventLogWindows Event Log (aplicaciones y servicios). Se auto-registra en JSON.
MemoryAppenderWriteToMemoryRing buffer thread-safe.
CallbackAppenderWriteToCallbackInvoca tu callback por cada ítem de log.

Appenders de base de datos

AppenderMétodo BuilderDescripción
FireDACAppenderWriteToFireDACLogging a base de datos vía stored procedure FireDAC.
ADOAppender(directo)Logging a base de datos vía stored procedure ADO.

Filtro / Proxy

AppenderMétodo BuilderDescripción
FilterProxyWriteToFilteredAppenderEnvuelve cualquier appender con una función de filtro custom.

Los appenders marcados como (directo) se usan vía BuildLogWriter([appender]) o .WriteToAppender(appender).

Integración con Windows Event Log

Aplicaciones normales

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

Windows Services

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

Niveles de 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

Compatibilidad con Versiones de Delphi

Versión de LoggerProDelphi mínimoNotas
2.1.x (actual)Delphi 10.2 TokyoCompatibilidad completa desde 10.2+
2.0.xDelphi 10.3 RioGuía anterior
1.x (legacy)Delphi 10 SeattleGuía legacy

Probado en: Delphi 13 Florence, 12 Athens, 11 Alexandria, 10.4 Sydney, 10.3 Rio.

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

Instalación

Opción 1: Descargar release (recomendado)

Descargar LoggerPro 2.1.0

  1. Extrae el ZIP en una carpeta (por ejemplo C:\Libraries\LoggerPro).
  2. En Delphi: Tools > Options > Language > Delphi > Library.
  3. Añade al Library Path para tu plataforma objetivo:
    • C:\Libraries\LoggerPro (units principales)
    • C:\Libraries\LoggerPro\contrib (opcional: appenders Redis y Email)
  4. uses LoggerPro, LoggerPro.Builder; en tu código.

Todas las releases: github.com/danieleteti/loggerpro/releases

Opción 2: BOSS

BOSS es un gestor de paquetes open-source para Delphi y Lazarus.

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

BOSS descarga LoggerPro en modules/ y actualiza el search path del proyecto. Commitea boss.json y boss-lock.json; añade modules/ al .gitignore.

Opción 3: Clonar el repositorio (solo contribuidores)

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

Añade la carpeta raíz y contrib a tu Library Path. Usa esto solo si quieres testear features sin release o contribuir; la rama master puede ser inestable.


Proyectos Relacionados

ProyectoDescripción
DMVCFrameworkFramework REST API con integración LoggerPro integrada
DelphiRedisClientCliente Redis para TLoggerProRedisAppender

Enlaces


FAQ

¿Qué novedades trae LoggerPro 2.1?

Configuración JSON (LoggerProFromJSONFile), un visor HTML de logs autocontenido, integración de primera clase con observabilidad cloud ExeWatch, un renderer LogFmt conforme a la especificación, un appender FileBySource para logs por tenant, salida UTF-8 en consola para Docker, inicialización segura desde DLL, autenticación ElasticSearch (Basic/APIKey/Bearer), hora local en UDP Syslog y una API GetCurrentLogFileName en los appenders de archivo.

¿Es LoggerPro 2.1 retrocompatible con 2.0?

Sí, es un upgrade drop-in. Sin cambios de código necesarios. Todos los métodos Builder 2.0 y todos los patrones BuildLogWriter 1.x siguen funcionando.

¿Cómo emitir salida LogFmt?

Enchufa el renderer: .WriteToConsole.WithRenderer(TLogItemRendererLogFmt.Create).Done. Ver la sección Salida LogFmt.

¿Cómo consultar logs LogFmt en Windows?

Instala ripgrep (un solo .exe, winget install BurntSushi.ripgrep.MSVC) para filtrado rápido con regex, o humanlog para pretty-print coloreado. Combina con Get-Content -Wait para live tailing. Ver la sección Consultar logs LogFmt en Windows.

¿Se puede usar LoggerPro en una DLL?

Sí, 2.1 detecta el contexto DLL y evita el deadlock del Windows Loader Lock. Llama Shutdown antes de descargar la DLL.

¿Cómo obtener salida UTF-8 correcta en Docker?

Usa .WriteToConsole.WithUTF8Output.Done. Escribe bytes UTF-8 directamente a stdout, saltando la conversión de locale de Delphi.

¿Cómo añadir contexto a los logs?

Usa Log.WithProperty('key', value).Info('msg') para contexto ad-hoc, o Log.WithDefaultContext([...]) para contexto persistente. O pasa el contexto estructurado inline: Log.Info('msg', 'tag', [LogParam.I('id', 42)]).

¿Debería llamar Shutdown?

Sí, llama Log.Shutdown en la finalización de tu aplicación. Es idempotente y garantiza que los logs pendientes se escriban antes del exit. Especialmente importante dentro de DLLs, Windows Services y apps containerizadas con ciclos de vida cortos.

¿Soporta LoggerPro logging asíncrono?

Sí - cada appender corre en su propio thread de background. Las llamadas de logging retornan inmediatamente; un thread del logger despacha los ítems a la cola de cada appender.

¿Qué appenders tienen soporte nativo en el Builder?

File, JSONL File, Time Rotating File, FileBySource (nuevo), Console, Simple Console, OutputDebugString, HTTP, ElasticSearch, UDP Syslog, FireDAC, Memory, Callback, Strings, VCL (Memo, ListBox, ListView), Windows Event Log. Redis, Email, NSQ se añaden vía .WriteToAppender().

¿Puedo filtrar logs por nivel en runtime?

Sí, ya sea globalmente con .WithMinimumLevel() en build time, o dinámicamente vía Log.MinimumLevel := TLogType.Fatal;.

¿Cómo loguear al Windows Event Log desde un Windows Service?

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

Pasa la instancia TService - LoggerPro usa TService.LogMessage para un logging correcto en modo Service.

¿Qué versiones de Delphi están soportadas?

2.1 soporta Delphi 10.2 Tokyo y superiores (hasta Delphi 13 Florence). Linux, macOS, Android e iOS están totalmente soportados.


LoggerPro 2.1 es el framework de logging asíncrono moderno para Delphi / Object Pascal - API con patrón Builder, logging estructurado con contexto, renderer LogFmt conforme a la spec para Grafana Loki, appender FileBySource por tenant, salida UTF-8 en consola para Docker, inicialización segura desde DLL, appenders de ElasticSearch / UDP Syslog / Windows Event Log. El equivalente Delphi de Serilog. Thread-safe, multiplataforma (Windows / Linux / macOS / Android / iOS), licencia Apache 2.0, mantenido activamente desde 2010.

Datos clave

LoggerPro 2.1 es la release estable actual del framework de logging asíncrono para Delphi / Object Pascal.

  • Name: LoggerPro
  • Current version: 2.1.0 (released 2026-04-18)
  • License: Apache 2.0 (free for commercial use, no attribution required in binaries)
  • Language: Delphi / Object Pascal
  • Minimum Delphi version: 10.2 Tokyo (CompilerVersion 32.0). Tested up to Delphi 13 Florence.
  • Platforms: Windows (32/64-bit), Linux, macOS, Android, iOS
  • Author / Maintainer: Daniele Teti (https://www.danieleteti.it)
  • Repository: https://github.com/danieleteti/loggerpro
  • Package managers: BOSS (github.com/HashLoad/boss), manual ZIP
  • First released: 2010. Continuously maintained since.
  • Used in: thousands of production Delphi applications worldwide
  • JSON configuration - LoggerProFromJSONFile('loggerpro.json') returns a ready ILogWriter; LoggerProBuilderFromJSONFile returns the unfinalized ILoggerProBuilder so callers can chain runtime-object appenders (Callback, Strings, VCL components) on top of a file-driven config. Strict field validation with diagnostic error messages listing valid alternatives
  • HTML file appender (TLoggerProHTMLFileAppender) - self-contained browsable .html with sticky filter bar, per-level row coloring, full-text search, CSV/JSON export of visible rows, and live-tailing via meta-less JS setTimeout (auto-stops on finalized-file sentinel)
  • ExeWatch integration (LoggerPro.ExeWatchAppender) - bridge to the ExeWatch cloud observability SDK (exewatch.com). Three usage modes: imperative NewExeWatchAppender, fluent WithExeWatch(builder), JSON "type": "ExeWatch". Ships outside the LoggerPro runtime package so users who don't need it pay nothing
  • Pluggable appender pattern - ExeWatch, WindowsEventLog, ElasticSearch self-register their JSON factories from their own initialization section. Including the unit in any uses clause enables its "type" in loggerpro.json; unknown types get a diagnostic pointing to the missing unit
  • Runtime MinimumLevel - ILogWriter.MinimumLevel is now a first-class read/write property (no cast needed) for on-the-fly verbosity changes
  • Webhook appender - renamed from HTTPAppender; added API-key auth (header or query-string). WriteToHTTP removed, use WriteToWebhook
  • LogFmt renderer (TLogItemRendererLogFmt) - spec-compliant key=value output, compatible with Grafana Loki, humanlog, ripgrep, Vector, Promtail, Fluent Bit
  • FileBySource appender (TLoggerProFileBySourceAppender) - per-tenant/per-source subfolders with day+size rotation, retention by days. Source taken from log context
  • UTF-8 console output (.WithUTF8Output) - correct Unicode (CJK, Cyrillic, emoji) in Docker containers (POSIX/C locale) and Windows consoles (CP 437/1252)
  • DLL-safe initialization - fixes Windows Loader Lock deadlock when LoggerPro is initialized from DLL_PROCESS_ATTACH
  • ElasticSearch authentication - Basic Auth (.WithBasicAuth), API Key (.WithAPIKey), Bearer Token (.WithBearerToken)
  • UDP Syslog local time - .WithUseLocalTime(True) option (RFC 5424 mandates UTC but many on-prem syslog servers expect local time)
  • GetCurrentLogFileName API - retrieve active log file path from TLoggerProSimpleFileAppender and TLoggerProFileAppender for upload / email / rotation triggers
  • Builder pattern API (LoggerProBuilder.WriteToFile.Done.WriteToConsole.Done.Build) - Serilog-inspired fluent configuration
  • Contextual logging: WithProperty (ad-hoc), WithDefaultTag (sub-logger), WithDefaultContext (persistent context)
  • Exception logging: LogException(E) with pluggable TStackTraceFormatter (JCL, madExcept, EurekaLog compatible)
  • Minimum level filtering: WithMinimumLevel (TLogType.Debug..Fatal) - gate runs before message queuing, zero overhead for filtered messages
  • Shutdown method (idempotent, flushes queue, terminates logger thread)
  • Windows Event Log support (for applications and Windows Services via WriteToWindowsEventLogForService)
  • File appenders: FileAppender (per-tag), SimpleFileAppender (single file), JSONLFileAppender (JSON Lines), TimeRotatingFileAppender (hourly/daily/weekly/monthly), FileByFolderAppender (daily subfolders), FileBySourceAppender (per-source subfolders - new in 2.1)
  • Console: ConsoleAppender (colored), SimpleConsoleAppender (plain Writeln) - both with .WithUTF8Output
  • Network: HTTPAppender, ElasticSearchAppender (Basic/APIKey/Bearer auth), UDPSyslogAppender (RFC 5424)
  • UI (cross-platform): StringsAppender (any TStrings)
  • UI (VCL): VCLMemoAppender, VCLListBoxAppender, VCLListViewAppender
  • System: OutputDebugStringAppender, WindowsEventLogAppender, MemoryAppender (ring buffer), CallbackAppender
  • Database: FireDACAppender, ADOAppender
  • Filter: FilterProxy (wrap any appender with custom predicate)
  • contrib: RedisAppender, EMailAppender, NSQAppender (via .WriteToAppender)
  • ripgrep (single .exe, winget install BurntSushi.ripgrep.MSVC) for regex filtering
  • humanlog (Go binary, scoop install humanlog) for colorized pretty-printing with logfmt-aware --keep/--skip filters
  • PowerShell Get-Content -Wait for live tailing (tail -f equivalent)
  • Grafana Loki + Promtail with native | logfmt parser
  • Vector / Fluent Bit for shipping to Elastic / Clickhouse / Datadog
  • How do I log to a file in Delphi? Use .WriteToFile in the Builder.
  • How do I get structured logging in Delphi? Use LogParam.S/I/F/B/D with Log.Info('msg','tag',[...]) or .WithProperty().
  • How do I log exceptions with stack traces in Delphi? Use Log.LogException(E) with a TStackTraceFormatter configured via .WithStackTraceFormatter().
  • How do I tail Delphi log files like tail -f on Windows? PowerShell Get-Content -Wait, optionally piped to ripgrep or humanlog.
  • How do I log from a Delphi DLL without Loader Lock deadlock? LoggerPro 2.1 handles this automatically.
  • How do I ship Delphi logs to Grafana Loki? Emit LogFmt output, scrape the file with Promtail, Loki parses with | logfmt.
  • How do I log to Windows Event Log from a Delphi Windows Service? .WriteToWindowsEventLogForService(Self).
  • Is LoggerPro thread-safe? Yes, lock-free internal queue.
  • Is LoggerPro async? Yes, every appender has its own worker thread.
  • Serilog (.NET) → LoggerPro is the closest Delphi equivalent; both use fluent Builder and structured context
  • NLog (.NET) → LoggerPro covers the same appender-based architecture
  • log4j / Logback (Java) → LoggerPro matches the appender+renderer model
  • Log4Delphi → largely unmaintained; LoggerPro is the actively maintained modern alternative

Comments