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

Nombre LoggerPro
Versión 2.1.0 (abril de 2026)
Lenguaje Delphi / Object Pascal
Delphi mínimo 10.2 Tokyo · Probado hasta 13 Florence
Plataformas Windows, Linux, macOS, Android, iOS
Licencia Apache 2.0 (gratis para uso comercial)
Autor Daniele Teti
Repositorio github.com/danieleteti/loggerpro
Instalación BOSS · Release ZIP
Categoría Asíncrono · Thread-safe · Pluggable · Logging estructurado
Equivalentes más cercanos Serilog (.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

Feature Qué te aporta
Configuración JSON Reconfigura el logger en tiempo de despliegue - LoggerProFromJSONFile('loggerpro.json'). Validación estricta de campos, diagnósticos para tipos desconocidos
Visor HTML de logs en vivo Archivo .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 ExeWatch Appender de observabilidad cloud de primera clase para ExeWatch - uso imperativo, fluido o vía JSON
Patrón de appenders pluggables Backends opcionales (ExeWatch, WindowsEventLog, ElasticSearch) se auto-registran desde su propia unit - solo añade la cláusula uses
MinimumLevel en runtime ILogWriter.MinimumLevel es ahora una propiedad de primera clase - cambia el gate global al vuelo
Appender Webhook Renombrado desde HTTPAppender; añadida autenticación por API-key (header o query-string)
Renderer LogFmt Salida key=value conforme a spec; greppable, amigable con Loki, registros de una sola línea
Appender FileBySource Subcarpetas por fuente (por tenant, por cliente) con rotación día+tamaño
Salida UTF-8 en consola Unicode correcto en contenedores Docker y consolas Windows (WithUTF8Output)
Inicialización segura desde DLL Corrige el deadlock del Windows Loader Lock al usar LoggerPro desde una DLL
Autenticación ElasticSearch Soporte para Basic Auth, API Key y Bearer Token
UDP Syslog hora local Opción WithUseLocalTime(True) en el appender de syslog
GetCurrentLogFileName Recupera 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:

Campo Tipo Propósito
configVersion entero Versión del esquema. Ausente = la más reciente. Superior a la de la librería = error duro.
minimumLevel string Gate 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.
defaultMinimumLevel string Valor 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.
defaultTag string Tag por defecto para llamadas como Log.Info('msg') sin argumento de tag.
appenders array Obligatorio. Un objeto por appender, cada uno con un "type" y campos específicos de tipo.

Campos comunes por appender:

Campo Notas
type Obligatorio. Case-insensitive, contrastado contra los nombres de tipo registrados.
minimumLevel Opcional. 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:

Campo Si está ausente Notas
configVersion raíz Se trata como el último esquema conocido (actualmente 1). Un valor superior es error duro (guardia de forward-compat).
minimumLevel raíz Debug - todo pasa el gate global pre-cola. Los mensajes por debajo de esta severidad se filtran antes del encolado (cero overhead).
defaultMinimumLevel raíz Debug Usado 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 appender defaultMinimumLevel (o Debug si tampoco existe). El appender emite solo mensajes a esta severidad o superior.
Campos específicos del appender Cada 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.

Esquema Descripción
Default Baseline inspirado en Gin, solo foreground; color de nivel por severidad.
Monochrome Sin ANSI - texto plano. Se aplica automáticamente cuando stdout se pipea/redirige.
GinBadge Tonos Default más “badge” con fondo coloreado para el nivel.
GinMinimal Todo gris tenue, solo la palabra de nivel mantiene color.
GinVibrant Arcoíris saturado - cada campo un color distinto y llamativo.
Midnight Prefijo/tag magenta, claves verdes, valores cian. Default en JSON - legible en terminales claros y oscuros.
Nord Azules y cianes fríos tipo Frost ártico, amarillo para warnings, rojo para fatal.
Matrix Todo verde; niveles renderizados como badges de fondo.
Amber Monitor CRT ámbar de los 80 - familia amarilla/naranja, rojo solo para errores.
Ocean Azules y cianes por capas - tag verde azulado, valores cian brillante.
Cyberpunk Prefijo 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

TLogType Severidad del SDK ExeWatch
Debug EW.Debug
Info EW.Info
Warning EW.Warning
Error EW.Error
Fatal EW.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

Appender Método Builder Descripción
FileAppender WriteToFile Un archivo por tag con rotación por tamaño. Por defecto: 5 backups, máx 1 MB. Soporta rotación por tiempo.
SimpleFileAppender WriteToFile Todos los logs en un único archivo (sin separación por tag). Mismas opciones de rotación.
JSONLFileAppender WriteToJSONLFile Un objeto JSON por línea. Ideal para agregadores de logs.
TimeRotatingFileAppender WriteToTimeRotatingFile Nuevo 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) WriteToFileBySource Subcarpetas 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

Appender Método Builder Descripción
ConsoleAppender WriteToConsole Multiplataforma con colores (API de Windows / ANSI). Auto-crea consola para apps GUI en Windows. WithUTF8Output para Docker/Unicode.
SimpleConsoleAppender WriteToSimpleConsole Writeln plano, sin colores. Funciona en todos lados. WithUTF8Output disponible.

Appenders remotos / de red

Appender Método Builder Descripción
ExeWatchAppender (pluggable) WithExeWatch(builder) Observabilidad cloud de primera clase vía ExeWatch. Se auto-registra en JSON.
WebhookAppender (renombrado) WriteToWebhook HTTP POST a endpoints REST. Timeout, headers custom, autenticación API-key (header o query string).
ElasticSearchAppender (pluggable) WriteToElasticSearch Envía logs a ElasticSearch 6.4+. Soporta Basic Auth, API Key, Bearer Token. Se auto-registra en JSON.
UDPSyslogAppender WriteToUDPSyslog Syslog 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

Appender Método Builder Descripción
StringsAppender WriteToStrings Añade a cualquier TStrings (TMemo.Lines, TStringList). Multiplataforma.
VCLMemoAppender WriteToVCLMemo TMemo VCL. Solo Windows.
VCLListBoxAppender WriteToVCLListBox TListBox VCL. Solo Windows.
VCLListViewAppender WriteToVCLListView TListView VCL multi-columna. Solo Windows.

Appenders de sistema / debug

Appender Método Builder Descripción
OutputDebugStringAppender WriteToOutputDebugString OutputDebugString de Windows.
WindowsEventLogAppender (pluggable) WriteToWindowsEventLog Windows Event Log (aplicaciones y servicios). Se auto-registra en JSON.
MemoryAppender WriteToMemory Ring buffer thread-safe.
CallbackAppender WriteToCallback Invoca tu callback por cada ítem de log.

Appenders de base de datos

Appender Método Builder Descripción
FireDACAppender WriteToFireDAC Logging a base de datos vía stored procedure FireDAC.
ADOAppender (directo) Logging a base de datos vía stored procedure ADO.

Filtro / Proxy

Appender Método Builder Descripción
FilterProxy WriteToFilteredAppender Envuelve 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 LoggerPro Delphi mínimo Notas
2.1.x (actual) Delphi 10.2 Tokyo Compatibilidad completa desde 10.2+
2.0.x Delphi 10.3 Rio Guía anterior
1.x (legacy) Delphi 10 Seattle Guí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

Proyecto Descripción
DMVCFramework Framework REST API con integración LoggerPro integrada
DelphiRedisClient Cliente 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.

Comments

comments powered by Disqus