When Serilog works locally, but not on Azure App Service
Tags: azure, serilog, dotnet
Published: 2019-07-13 13:50:18

This really threw me, and I've spent lots of time trying to understand something that was really simple and logical. Don't you just hate those issues?

An app I'm developing is using [Serilog](https://serilog.com). Serilog is awesome. The app is running ASP.NET Core 2.2 and hosted on Azure App Service. 

Getting Serilog to work locally was easy peasy, just install it with Nuget, add the Sinks needed and configure it in ``Program.cs``

```csharp
public static void Main(string[] args) {
    // Create the Logger configuration
    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Debug()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
        .WriteTo.Console()
        .CreateLogger();
    // ...
    try
    {
        Log.Debug("Application Starting at {date} ({EnvironmentName}).", DateTime.Now, EnvironmentName);
        CreateWebHostBuilder(args)
            .Build()
            .Run();
    }
    catch (Exception ex)
    {
        Log.Fatal(ex, "Application died");
    }
    finally
    {
        Log.CloseAndFlush();
    }
}
```


Then just add ``.UseSerilog()`` the ``IWebHostBuilder`` method ``CreateWebHostBuilder`` (assuming you are using standard dotnet CLI initialised, or Visual Studio crated project).

However, I wanted Serilog to read from my application settings and environment variables in order to configure things using the Azure portal. Adding the ``Serilog.Settings.Configuration`` package takes care of that and a simple ``ReadFrom.Configuration()`` is added just before ``CreateLogger()``

Again, this is FINE on my local dev environment. However, when building and publishing to Azure, nothing was being logged.

Oddly enough, it seems Azure doesn't pickup environment variables and/or configuration before the ``CreateWebHostBuild``method is called. This is troubling if you want to be able to log anything that might happen when the app STARTS (like, in the actual ``CreateWebHostBuilder``, or even before that.

Here's an easy way to solve it; Configure the logger with a hard coded file path that is accessible on Azure (``D:\home\LogFiles\Application\`` for instance) and _re-configure_ it in Startup.cs (``ConfigureServices``).

```csharp
public void ConfigureServices(IServiceCollection services)
{
    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Debug()
        .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
        .ReadFrom.Configuration(Configuration) // << THIS!!
        .Enrich.FromLogContext()
        .CreateLogger();
    // All other goodies 
}
```

Now, running this on a mac, or Windows without a D:\ would introduce new problems. I solved that part by checking for an environment variable that I _know_ Azure sets: *WEBSITE_SITE_NAME*

Here's the updated ``Program.cs`` Main function:

```csharp
public static void Main(string[] args)
{
    // Check if app is running on Azure, the WEBSITE_SITE_NAME environment variable will be set if it is.
    if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME")))
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .Enrich.FromLogContext()
            .WriteTo.File(path: @"D:\home\LogFiles\Application\log.txt", fileSizeLimitBytes: 1_000_000,
                flushToDiskInterval: TimeSpan.FromSeconds(5), shared: true,
                restrictedToMinimumLevel: LogEventLevel.Debug)
            .CreateLogger();
    }
    else
    {
        // Not Azure, just log to Console, no need to persist
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .WriteTo.Console()
            .CreateLogger();
    }

    try
    {
        Log.Debug("Application Starting at {date} ({EnvironmentName}).", DateTime.Now, EnvironmentName);
        CreateWebHostBuilder(args)
            .Build()
            .Run();
    }
    catch (Exception ex)
    {
        Log.Fatal(ex, "Application died 💀");
    }
    finally
    {
        Log.CloseAndFlush();
    }
}
```