Search code examples
.net-corenlogpayload

NLog Info method is writing type of log. How can I display the actual data as json in file


I am working on a project and writing a logging framework. I encountered an issue with nlog when logging with Info method passing T as argument.

I installed nlog nuget. Below is 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" autoReload="true" internalLogLevel="info" internalLogFile="internalLog.txt">
    <extensions>
        <add assembly="NLog.Web.AspNetCore" />
    </extensions>
    <!-- the targets to write to -->
    <targets async ="true">
        <!-- write to file -->
        <target xsi:type="File"
                name="testlogging"
                fileName="C:\testfolder\logs\testdata.log"
                layout="${JsonLayout}" >
            <layout xsi:type="JsonLayout" includeAllProperties ="true" >
                <attribute name ="date" layout ="${longdate}"></attribute>
                <attribute name ="message" layout ="${message}"></attribute>

            </layout>

        </target>


    </targets>
    <!-- rules to map from logger name to target -->
    <rules>
        
        <logger name ="testlogging" minlevel="Info" writeTo="testlogging" />
    </rules>
</nlog>

Created NlogCustom class

public class NlogCustom : INlogCustom {

    private readonly NLog.ILogger _logger;

    public NlogCustom(NLog.ILogger logger)
    {
        _logger = logger;
    }

    public void WriteMessage(string message)
    {
        var tstlogentry = new TestLogEntry { Id = 1, Name = "Alexander" };
        _logger.Info(tstlogentry);
    }
}

public class TestLogEntry
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Then calling from default weatherforecastcontroller

namespace TestNlog.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class WeatherForecastController : ControllerBase
        {
            private static readonly string[] Summaries = new[]
            {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };
    
            private readonly ILogger<WeatherForecastController> _logger;
    
            private readonly INlogCustom _nloglogger;
    
            public WeatherForecastController(ILogger<WeatherForecastController> logger, 
                INlogCustom nlogger)
            {
                _logger = logger;
                _nloglogger = nlogger;
                
            }
    
            [HttpGet]
            public IEnumerable<WeatherForecast> Get()
            {
                _nloglogger.WriteMessage("Init the Get method");
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(index),
                    TemperatureC = Random.Shared.Next(-20, 55),
                    Summary = Summaries[Random.Shared.Next(Summaries.Length)]
                })
                .ToArray();
            }
        }
    }

But the log file shows

{ "date": "2024-01-23 13:17:30.8058", "message": "TestNlog.TestLogEntry" } { "date": "2024-01-23 13:17:57.7975", "message": "TestNlog.TestLogEntry" }

But what I was expecting is to see the data in TestLogEntry in Json format. I know this can be done with Nlog. Can anyone help me if there is something that I am missing in this process? In typical scenarios the TestLogEntry is some object that will have payload of request and response with different properties.


Solution

  • You have configured NLog JsonLayout to output LogEvent-properties, but not logging any properties.

    If you want NLog to dump all object-properties using object-reflection, then you can use structured-logging:

        public void WriteMessage(string message)
        {
            var tstlogentry = new TestLogEntry { Id = 1, Name = "Alexander" };
            _logger.Info("{LogEntry}", tstlogentry);
        }
    

    You can consider to override TestLogEntry.ToString()-method to control the output of ${message}.