Search code examples
databasepostgresqlnlognpgsql

NLog DB Configration Problem For PostgreSql


I'm using nlog it's working well for log file but I want to add log info in db too. But it's not working for me. I couldn't find my problem. I'm using postgresql as database. I'm using .NET5 NLog 4.7.10

nlog.config:

<?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">
  
  <targets>
    <target name="allfile" xsi:type="File"
            fileName="D:\BEBKA.JobTracking.logs\${shortdate}.log"/>
    
    <target xsi:type="Database" name="db" dbProvider="Npgsql.NpgsqlConnection, Npgsql" connectionstring="Server=127.0.0.1;Port=5432;Database=BEBKAJobTracking;User Id=postgres;Password=123;">
      <commandText>
        INSERT INTO public."Logs"("Type", "Method", "StatusCode", "StackTrace", "MethodName", "Message", "RequestData", "ResponseData", "Ip", "CreatedDate", "CreatedId")
        VALUES (@Type, @Method, @StatusCode, @StackTrace, @MethodName, @Message, @RequestData, @ResponseData, @Ip, @CreatedDate, @CreatedId);
      </commandText>
      <parameter name="@Type" layout="${type}"/>
      <parameter name="@Method" layout="${method}"/>
      <parameter name="@StatusCode" layout="${statusCode}"/>
      <parameter name="@StackTrace" layout="${stackTrace}"/>
      <parameter name="@MethodName" layout="${methodName}"/>
      <parameter name="@Message" layout="${message}"/>
      <parameter name="@RequestData" layout="${requestData}"/>
      <parameter name="@ResponseData" layout="${responseData}"/>
      <parameter name="@Ip" layout="${ip}"/>
      <parameter name="@CreatedDate" layout="${createdDate}"/>
      <parameter name="@CreatedId" layout="${createdId}"/>
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Trace" writeTo="allfile" />
    <logger name="db" minlevel="Trace" writeTo="db" />
  </rules>
</nlog> 

My logger service

using BEBKA.Infrastructure.Abstractions.Core;
using BEBKA.Infrastructure.Abstractions.Loggger.Interfaces;
using NLog;

namespace BEBKA.Infrastructure.Services
{
    public class LoggerService : ILoggerService
    {
        private static readonly ILogger logger = LogManager.GetCurrentClassLogger();

        public void LogDebug(ILog log)
        {
            logger.Debug(log.Message);
        }

        public void LogDebug(string message)
        {
            logger.Debug(message);
        }

        public void LogError(ILog log)
        {
            logger.Error(log.Message);
        }

        public void LogError(string message)
        {
            logger.Error(message);
        }

        public void LogInfo(ILog log)
        {
            //TODO: Need Bugfix
            LogEventInfo theEvent = new(LogLevel.Info, "db", log.Message);
            SetLogEventInfo(theEvent, log);
            logger.Log(theEvent);

            //logger.Info("{message}",log.Message);   
        }

        public void LogInfo(string message)
        {
            logger.Info(message);
        }

        public void LogWarn(ILog log)
        {
            logger.Warn(log.Message);
        }

        public void LogWarn(string message)
        {

            logger.Warn(message);
        }
        private static void SetLogEventInfo(LogEventInfo theEvent, ILog
    data)
        {
            theEvent.Properties["Type"] = data.Type;
            theEvent.Properties["Method"] = data.Method;
            theEvent.Properties["StatusCode"] = data.StatusCode;
            theEvent.Properties["StackTrace"] = data.StackTrace;
            theEvent.Properties["MethodName"] = data.MethodName;
            theEvent.Properties["Message"] = data.Message;
            theEvent.Properties["RequestData"] = data.RequestData;
            theEvent.Properties["ResponseData"] = data.ResponseData;
            theEvent.Properties["Ip"] = data.Ip;
            theEvent.Properties["CreatedDate"] = data.CreatedDate;
            theEvent.Properties["CreatedId"] = data.CreatedId;
        }
    }
}

..................................................................................................................................................................................................................................................................


Solution

  • You have several issues going on:

    1. Event-Properties must be rendered with help from ${event-properties}
          <parameter name="@Type" layout="${event-properties:type}"/>
          <parameter name="@Method" layout="${event-properties:method}"/>
          <parameter name="@StatusCode" layout="${event-properties:statusCode}"/>
          <parameter name="@StackTrace" layout="${event-properties:stackTrace}"/>
          <parameter name="@MethodName" layout="${event-properties:methodName}"/>
          <parameter name="@Message" layout="${event-properties:message}"/>
          <parameter name="@RequestData" layout="${event-properties:requestData}"/>
          <parameter name="@ResponseData" layout="${event-properties:responseData}"/>
          <parameter name="@Ip" layout="${event-properties:ip}"/>
          <parameter name="@CreatedDate" layout="${event-properties:createdDate}"/>
          <parameter name="@CreatedId" layout="${event-properties:createdId}"/>
    
    1. Logger-Name should never be assigned, but must be null for filtering to work
        public class LoggerService : ILoggerService
        {
            private static readonly ILogger logger = LogManager.GetCurrentClassLogger();
            private static readonly ILogger Dblogger = LogManager.GetLogger("db");
    
            public void LogInfo(ILog log)
            {
                LogEventInfo theEvent = new(LogLevel.Info, null, log.Message);
                SetLogEventInfo(theEvent, log);
                Dblogger.Log(theEvent); // DbLogger matches <logger name="db" minlevel="Trace" writeTo="db" />
            }
    

    It is a little confusing that all LogEventInfo-constructors takes Logger-name as input-parameter, but it should never be assigned. Tried to improve on this, but my pull-request was rejected: https://github.com/NLog/NLog/issues/4086

    Notice that one could also log ILog as single object like Dblogger.Info("{payload}", data) and extract individual properties like this: ${eventproperties:payload:objectpath=CreatedId}