LoggerPro 2.1 — Framework de Logging Asíncrono para Delphi
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 (
LoggerProFromJSONFileoLoggerProFromJSONString), 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) |
¿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:
WriteToHTTPse renombró aWriteToWebhook(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.Infoes Info,Log.Errores Error, y así. NiminimumLevelnidefaultMinimumLevella cambian; solo deciden quién ve qué. ElminimumLevelraíz es un filtro pre-cola (gratuito: elTLogItemni siquiera se construye para mensajes por debajo). ElminimumLevelpor appender es un gate de emisión (evaluado en el worker thread del appender, decide si ESTE appender escribe el mensaje). EldefaultMinimumLevelen 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:
- Carga la parte describible en JSON con
LoggerProBuilderFromJSONFile. - Encadena los extras sobre el builder devuelto.
- Llama
.Buildtú 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\tcomo 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/falsesin 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 codeclogfmt, 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
LogParamse 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.Shutdownantes 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)
- Extrae el ZIP en una carpeta (por ejemplo
C:\Libraries\LoggerPro). - En Delphi: Tools > Options > Language > Delphi > Library.
- Añade al Library Path para tu plataforma objetivo:
C:\Libraries\LoggerPro(units principales)C:\Libraries\LoggerPro\contrib(opcional: appenders Redis y Email)
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
- GitHub: github.com/danieleteti/loggerpro
- Documentación LoggerPro 2.0: /loggerpro_2_0/
- Guía legacy 1.x: /loggerpro_1_3/
- Soporte: Grupo de Facebook
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