I am adding Serilog to our logging infrastructure and am confused by the following:
public class OzCpWriteEntryExInput : OzCpAppServiceInputBase
{
private readonly ILogger _Logger;
/// <summary>
/// Class constructor
/// </summary>
public OzCpWriteEntryExInput(ILogger aLogger)
{
//Save params supplied
_Logger = aLogger;
//Create resources required
Entry = new OzCpLogEntryContextInput();
}
public OzCpLogEntryContextInput Entry { get; set; }
public ILogger Logger => _Logger;
}
public class OzCpLoggingService : OzCruisingPlatformAppServiceBase, IOzCpLoggingService
{
private const string MESSAGE_TEMPLATE =
"{LogVersion} {DateTimeUtc:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] [{LevelRange}] [{ApplicationHostName}] [{ApplicationName}] [{ApplicationVersion}] [{Location}] {Message}{NewLine}{Exception}{NewLine}{StackTrace}{NewLine}{UserDataKind}{@UserData}";
public OzCpBuildLoggerOutput BuildLogger(OzCpBuildLoggerInput aParams)
{
OzCpBuildLoggerOutput result = new OzCpBuildLoggerOutput();
//#TODO (DE) Convert logger hard coded values into settings
bool logToUdp = true;
//By default logging will include all events
LoggerConfiguration loggerConfiguration = new LoggerConfiguration()
.Enrich.WithProperty("LogVersion", "01.00")
.MinimumLevel.Verbose();
if (logToUdp)
{
loggerConfiguration.WriteTo.Udp(IPAddress.Loopback, 11000, 0, LogEventLevel.Verbose, MESSAGE_TEMPLATE);
}
//Finally we can build the logger
result.Logger = loggerConfiguration.CreateLogger();
return result;
}
/// <summary>
/// Writes an entry to the supplied logger and associated log sinks.
/// </summary>
/// <param name="aParams">Parameters defining the entry to be written.</param>
/// <returns>Returns whether the entry was written to the logger.</returns>
public OzCpWriteEntryExOutput WriteEntryEx(OzCpWriteEntryExInput aParams)
{
OzCpWriteEntryExOutput result = new OzCpWriteEntryExOutput();
//These variable values are only the ones out of the entry as the logger "enriches" the other values based on
//what has been passed in when it was configured
object[] messageTemplateVariableValues =
{
"***", //Log Version is actually an enriched property!!!!
aParams.Entry.DateTimeUtc,
aParams.Entry.LevelRange,
aParams.Entry.Location,
aParams.Entry.StackTrace,
aParams.Entry.UserDataKind,
aParams.Entry.UserData
};
switch (aParams.Entry.EntryKind)
{
case OzCpLoggingEntryKindEnum.Verbose:
aParams.Logger.Verbose(aParams.Entry.Exception, MESSAGE_TEMPLATE, messageTemplateVariableValues);
break;
}
return result;
}
}
Ultimately callers to WriteLogEx() can supply their own Serilog.ILogger. I won't go into the reasons as to why this is the case, just assume this is a requirement.
As an example I include BuildLogger() which sets up an ILogger to write to UDP with a custom message template and some additional properties via the enrichment configuration builder.
All pretty straight forward. However now when I go to write to the ILogger using ILogger.Verbose() I need to pass parameters for the tokens in the message template.
However this appears to be ordinal based so the first one goes into {LogVersion} which is supposed to be being completed via the enricher configuration previously set up for the logger.
if I don't LogVersion the formatted message template is off by one and naturally if I include it then I get:
*** 2016-04-14 14:53:57.677 +10:00 [Information]...
instead of what I want which is:
01.00 2016-04-14 14:53:57.677 +10:00 [Information]...
So how do I call a logging method off ILogger and pass the token values by name instead of position?