Search code examples
xamarinloggingmvvmcrossserilog

Using serilog´s ForContext in MvvmCross


I am using xamarin MvvmCross and configured serilog as the logger. I am trying to add custom variables to the template passing them in the context, but I cannot figure out how to do it.

This is my serilog configuration:

var local = Application.Context.GetExternalFilesDir("").AbsolutePath;
string path = Path.Combine(local, "my_log.txt");

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .WriteTo.File(path,
        rollingInterval: RollingInterval.Day,
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss zzz} {myCustomVar} [{Level:u3}] {Message:lj}")
    .CreateLogger();

And here in my ViewModel I am trying to log a message:

using (_logProvider.OpenMappedContext("myCustomVar","varValue"))
            {
                _log.Info("Good Morning");
            }

The line output to my_log.txt does not contain a value for "myCustomVar".

The only way I have found to make it work is bypass totally MvvmCross and write a custom logger that directly calls serilog like this:

    public interface ILogService
    {
        void LogMessage(string message);
    }

and the android implementation:

public class LogService : ILogService
    {
        public void LogMessage(string message)
        {
            Log.ForContext("myCustomVar", "varValue")
                        .Information(message);
        }
    }

There is a way to access the advanced features of serilog such as passing variables in the context using the MvvmCross/IMvx logging abstraction layer?


Solution

  • You need to connect Serilog and MvvmCross together for it to work, and you also need to enrich with properties from the log context because of the way that the MvvmCross integration was implemented (they don't call ForContext, and instead they call PushProperty).

    Override the GetDefaultLogProviderType in your platform project's Setup.cs:

    public override MvxLogProviderType GetDefaultLogProviderType() => MvxLogProviderType.Serilog;
    

    And create an IMvxLogProvider from the Serilog logger you create:

    protected override IMvxLogProvider CreateLogProvider()
    {
        var local = Application.Context.GetExternalFilesDir("").AbsolutePath;
        string path = Path.Combine(local, "my_log.txt");
    
        Log.Logger = new LoggerConfiguration()
          .MinimumLevel.Verbose()
          .Enrich.FromLogContext()
          .WriteTo.File(path,
              rollingInterval: RollingInterval.Day,
              outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss zzz} {myCustomVar} [{Level:u3}] {Message:lj}")
          .CreateLogger();
    
          return base.CreateLogProvider();
    }