Transición desde log4net
Es frecuente que, al desplegar aplicaciones .NET en servidores de producción, log4net deje de persistir trazas sin lanzar excepciones visibles. Tras intentar una actualización estándar mediante NuGet:
Install-Package log4net
si el comportamiento se mantiene, la ruta más estable consiste en sustituir el motor por NLog. Esta librería simplifica la definición de destinos y mejora la tolerancia a fallos de configuración.
Instalaicón y estructura base
Reemplace la implementación anterior agregando el núcleo y el esquema de configuración:
Install-Package NLog
Install-Package NLog.Config
Para aplicaciones de escritorio, asegúrese de que el archivo NLog.config tenga la propiedad "Copy to Output Directory" establecida. El siguiente esquema redirige la información a archivos segmentados por fecha y a la consola del sistema:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true" internalLogLevel="Warn">
<targets>
<target name="registroArchivos" xsi:type="File"
fileName="${basedir}/bitacora/${shortdate}.log"
layout="${longdate} [${level}] ${message}" />
<target name="pantalla" xsi:type="ColoredConsole" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="registroArchivos" />
<logger name="*" minlevel="Warn" writeTo="pantalla" />
</rules>
</nlog>
Invocación desde código
La instancia del registrador se obtiene automáticamente desde la clase actual. La sintaxis soporta interpolación y niveles jerárquicos:
var gestorTrazas = LogManager.GetCurrentClassLogger();
gestorTrazas.Debug("Módulo de inicialización cargado");
gestorTrazas.Info("Fecha de arranque del servicio: {0}", DateTime.UtcNow);
gestorTrazas.Warn("Umbral de memoria próximo al límite");
gestorTrazas.Error("Fallo en la conexión con el servicio externo");
gestorTrazas.Fatal("Terminación abrupta del hilo principal");
Persistencia en SQL Server para aplicaciones web
Para entornos ASP.NET que requieran almacenar logs en una base de datos relacional, instale el complemento oficial:
Install-Package NLog.Web
Defina el destino de base de datos utilizando procedimientos almacenados para optimizar la inserción masiva:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true" internalLogLevel="Off">
<targets>
<target name="almacenRelacional"
xsi:type="Database"
connectionStringName="CadenaSQLServer"
commandType="StoredProcedure"
commandText="[dbo].[sp_InsertarLogSistema]">
<parameter name="@nombreHost" layout="${machinename}" />
<parameter name="@nombreSitio" layout="${iis-site-name}" />
<parameter name="@marcaTiempo" layout="${date}" />
<parameter name="@severidad" layout="${level}" />
<parameter name="@usuarioActual" layout="${aspnet-user-identity}" />
<parameter name="@detalle" layout="${message}" />
<parameter name="@claseOrigen" layout="${logger}" />
<parameter name="@contextoExtra" layout="${all-event-properties:separator=|}" />
<parameter name="@rutaSolicitud" layout="${aspnet-request:serverVariable=HTTP_URL}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="almacenRelacional" />
</rules>
</nlog>
Vincule la cadena de conexión en el Web.config de la aplicación:
<configuration>
<connectionStrings>
<add name="CadenaSQLServer" connectionString="Server=localhost;Database=LogDB;User Id=admin;Password=clave123;" providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
Integración con Oracle Database
Para entornos corporativos con Oracle, configure el proveedro de datos adecuado. La versión legacy requiere System.Data.OracleClient, mientras que las implementaciones modernas utilizan Oracle.DataAccess.Client o el proveedor administrado.
<targets>
<target name="oracleDirecto" type="Database"
dbProvider="Oracle.DataAccess.Client.OracleConnection,Oracle.DataAccess"
connectionString="Data Source=ORCL_PROD;User ID=log_user;Password=secure_pass;">
<commandText>
INSERT INTO BITACORA_APLICACION (equipo, nivel, fecha_creacion, descripcion)
VALUES(:equipo, :nivel, :fecha, :descripcion)
</commandText>
<parameter name=":equipo" layout="${machinename}" />
<parameter name=":nivel" layout="${level}" />
<parameter name=":fecha" layout="${date}" />
<parameter name=":descripcion" layout="${message}" />
</target>
</targets>
<rules>
<logger name="LogicoOracle" minlevel="Error" writeTo="oracleDirecto" />
</rules>
Ejemplo de consumo específico:
var loggerOracle = LogManager.GetLogger("LogicoOracle");
loggerOracle.Fatal(new InvalidOperationException("Timeout en consulta pesada"), "Operación de exportación fallida");
Soporte para MySQL
Añada la referencia al conector oficial:
Install-Package MySql.Data
La configuración apunta a una tabla dedicada, utilizando parámetros nombrados compatibles con el driver de MySQL:
<targets>
<target name="motorMySQL" type="Database"
dbProvider="MySql.Data.MySqlClient.MySqlConnection,MySql.Data"
connectionString="Server=10.0.0.5;Uid=root;Pwd=dev;Database=logs;">
<commandText>
INSERT INTO registro_sistema (host, grado, instante, contenido)
VALUES(@host, @grado, @instante, @contenido)
</commandText>
<parameter name="@host" layout="${machinename}" />
<parameter name="@grado" layout="${level}" />
<parameter name="@instante" layout="${date}" />
<parameter name="@contenido" layout="${message}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="motorMySQL" />
</rules>
Formato avanzado de excepciones en archivos
Para garantizar que las trazas de pila se almacenen correctamente junto al mensaje, utilice un renderizador específico en la propiedad layout:
<target name="registroDetallado" xsi:type="File"
fileName="${basedir}/errores/${shortdate}.txt"
layout="${longdate} | ${level} | ${logger} | ${message} | ${exception:format=tostring}" />
Almacenamiento en MongoDB
Para arquitecturas NoSQL, instale la extensión comunitaria:
Install-Package NLog.Mongo
Registre la extensión en la cabecera del archivo y defina el documento BSON. Se recomienda limitar el crecimianto de la colección mediante un capped collection para evitar saturación de disco:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<extensions>
<add assembly="NLog.Mongo"/>
</extensions>
<targets>
<target xsi:type="Mongo" name="coleccionNoSQL"
connectionString="mongodb://192.168.1.10:27017/BitacoraSistema"
collectionName="EventosEjecucion"
cappedCollectionSize="31457280">
<property name="IdHilo" layout="${threadid}" bsonType="Int32" />
<property name="IdProceso" layout="${processid}" bsonType="Int32" />
<property name="RutaEjecutable" layout="${processname:fullName=true}" />
<property name="CuentaWindows" layout="${windows-identity}" />
<property name="MensajeSistema" layout="${message}" />
</target>
</targets>
<rules>
<logger name="*" level="Info" writeTo="coleccionNoSQL" />
</rules>
</nlog>