Banshee
Banshee

Reputation: 15827

NLog not printing object from properties?

I have the following class :

[DataContract]
public class CallInformation
{
    [DataMember]
    public string Address { get; set; }
    [DataMember]
    public Boolean IsEmpty { get; set; }
    [DataMember]
    public Boolean IsFaulted { get; set; }
    [DataMember]
    public string Action { get; set; }
    [DataMember]
    public CallOrder CallDirection { get; set; }
    [DataMember]
    public DateTime EventTime { get; set; }
    [DataMember]
    public TimeSpan Duration { get; set; }
    [DataMember]
    public Boolean IsCallback { get; set; }
    [DataMember]
    public string LogSource { get; set; } = "Unknown";

    [DataMember]
    public string Soap { get; set; }
    public string EventTimeDisplay
    {
        get { return EventTime.ToString("HH:mm:ss.fffffff"); }
        set { }
    }
}

This is filled with data about communication in a client server application and den sent to NLog :

public void LogCommunication(CallInformation callInfo)
        {
            var logEvent = new LogEventInfo(LogLevel.Trace, "CommunicationLogger", "CommunicationLogger is logging");
            logEvent.Properties["CallInformation"] = callInfo;
            _comLogger.Log(logEvent);
        }

If it correct to put it in the properties or should it be put in the Parameters?

I need NLog to log it to file in a way that it later can be picked up and searched by Filebeat, ElasticSearch and Kibana. I have tried this NLog config :

<logger name="CommunicationLogger" minlevel="Trace" writeto="f"></logger>

<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${event-properties:item=CallInformation} ${message}" />

But all it prints is CommunicationLogger is logging? I suspect that I need it to serialize the whole object in some way?

Regards

Edit 1 I have tried to change the layout like this :

<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${event-properties:item=CallInformation:jsonEncode=true} ${message}" />

This does still not work, but if I change this code it workes :

logEvent.Properties["CallInformation"] = "test"; //callInfo;

test is written to file as it should so there is probably a problem to pars the simple class CallInformation to file.

I have checked the internal-log for NLog but I can´t finde any errors there.

Edit 2

I tried to change the code like this :

//var logEvent = new LogEventInfo(LogLevel.Trace, "CommunicationLogger", "ComLog writing.");
            //logEvent.Properties["CallInformation"] = callInfo;
            _comLogger.Log(LogLevel.Trace, "Test to log {@CallInformation}", callInfo);

nlog.config

<target xsi:type="File" 
            name="communicationFileLog" 
            fileName="${basedir}/logs/${shortdate}.log"
            maxArchiveDays="5" 
            maxArchiveFiles="10"
            layout="${event-properties:item=CallInformation:format@} ${message}"  />

The result in the log file is this :

 Test to log {@CallInformation}
 Test to log {@CallInformation}
 Test to log {@CallInformation}
 Test to log {@CallInformation}
...

Upvotes: 1

Views: 3016

Answers (1)

Rolf Kristensen
Rolf Kristensen

Reputation: 19867

NLog needs to be told, that a LogEvent property is safe for reflection and serialization. The normal way of doing this is like this:

_compLogger.Trace("CommunicationLogger is logging {@CallInformation}", callInfo);

Then NLog will know that the LogEvent property "CallInformation" is safe to to serialize, because of @.

If you are in an exotic mood, and don't want the property included in the LogEvent message, then you can do like this:

var logEvent = new LogEventInfo(LogLevel.Trace, _comLogger.Name, "CommunicationLogger is logging");
logEvent.Properties["CallInformation"] = callInfo;
_comLogger.Log(logEvent);

And then specific the special attribute in the Format-option:

<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${event-properties:item=CallInformation:format=@}" />

See also: https://github.com/NLog/NLog/wiki/How-to-use-structured-logging#output-captured-properties

P.S. Instead of using @ (Activates NLog own serializer) then you could also just override ToString() for your callInfo-object and then perform custom serialization there. Yet another alternative is making the callInfo-object implement IFormattable and provide a custom IFormatProvider with the LogEventInfo.

Upvotes: 3

Related Questions