Reputation: 69
NLog has methods such as logger.Fatal("Message", T object) and so on.
There are 2 questions in my mind -
What is the purpose of these methods apart from the type safe logger ?
Can we use this method to construct a dynamic message string at runtime based on the object properties ?
We want to construct a message at run time based on object properties, such that Nlog could reflect the type. Is this possible ?
Upvotes: 1
Views: 2725
Reputation: 27608
The generic logging signatures do allow for typesafe logging. So, you can have log statements like this (assuming logger
is your logging variable):
int a;
string b;
SomeOtherTypeOfObject c;
logger.Info(a);
logger.Info(b);
logger.Info(c);
logger.Info("a = {0}", a);
logger.Info("b = {0}", b);
logger.Info("c = {0}", c);
Internally, NLog uses string.Format to convert the passed-in format and object(s) to a string. In the case of the generic logging signatures that take only an object and not a format, internally NLog uses a format like this "{0}"
, so that the message formatting code farther down in NLog doesn't need to know if a format string was passed in or not.
NLog ultimately calls ToString
on the objects that are passed to NLog's logging functions, whether just the object as in the first 3 lines above or the format and the object as in the seconde 3 lines above.
One implication of this is that you could implement ToString on your types to give the string that you would like to use for logging.
So, let's say that you have a type as follows:
public class Person
{
public Person(string name, DateTime birthday)
{
Name = name;
Birthday = birthday;
}
public string Name { get; set; }
public DateTime Birthday { get; set; }
public int AgeInYears { get { return (DateTime.Now.Year - Birthday.Year); } }
public override string ToString()
{
return string.Format("Person [{0}] Age [{1}]", Name, AgeInYears);
}
}
Then you could log a Person like this:
Person p = new Person("Bob", new DateTime(1970, 1, 1));
logger.Info(p);
Or like this:
Person p = GetPersonFromDatabase("Bob");
logger.Info("Person from database is {0}", p);
In both cases, when the Person is ultimately evaluated by NLog, the ToString method is used, so you will get something like this to represent the Person:
Person [Bob] Age [41]
Alternatively, you should be able to make an object whose sole purpose is to generate a message, based on some kind of calculation:
public class MyLoggingParameters
{
public string override ToString()
{
var x = GetSomeInformationFromSomewhere();
return string.Format("MyLoggingParameters: [{0}], [{1}], [{2}]", x.Foo, x.Bar, x.Baz);
}
}
var x = new MyLoggingParameters();
logger.Info(x);
Also, don't forget that you can use the various context objects to give your more context to your logging messages:
NLog.GlobalDiagnosticContext["WhenDidMyApplicationStart"] = DateTime.Now;
NLog.ThreadDiagnosticContext["SomeThreadLocalValue"] = 1234;
Note that the context dictionaries are of type Dictionary<string, string>
, so you can't store an object in the dictionary and expect NLog to call ToString on the object when it is time to log it. If you want to store an object in the context dictionary, you are effectively storing a snapshot of the object.
Finally, if you have something specialized that you want to do, it is pretty easy to write your own LayoutRenderer object. A LayoutRenderer receives the LogEventData structure as input so you can base your output on the contents of that structure or you can base it on any other data that you know how to access.
See this question for more information on using NLog, including an example of a custom LayoutRenderer:
Most useful NLog configurations
Upvotes: 6