Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure Function failing to initialise Serilog Sink when using appsettings.json

I've created a simple Azure Function with the intension of using Serililog for logging to Azure Blob Storage.

When using inline configuration for the Serilog sink, that works perfectly fine, the sink is created and Serilog happily wirtes to Blob storage.

This works:

Log.Logger = new LoggerConfiguration()
   .WriteTo.AzureBlobStorage(
           "STORAGEACCOUNT CONNECTION STRING", // <-- inline config
           LogEventLevel.Information,
           null,
           "{yyyy}/{MM}/{dd}/MyLogFile.txt")
   .CreateLogger();

enter image description here

The problem is that I would like to configure this all via appsettings.json, but when I try this (both locally running in the emulator & in the cloud), it fails to bind the sink settings, and as a result its failing to log to to the Blog storage.

If I debug, I can see that the config values are being loaded as expected into the configuration object, but they are not being applied to the logging configuration.

This doesnt work:

Log.Logger = new LoggerConfiguration()
   .ReadFrom.Configuration(configuration)
   .CreateLogger();

appsettings.json in this snippet:

{

  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Information"
      }
    },
    "WriteTo": [{
        "Name": "AzureBlobStorage",
        "Args": {
          "connectionString": " --- REPLACE WITH STORAGEACCOUNT BLOB CONNECTION STRING --- ",
          "formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact",
          "storageFileName": "{yyyy}/{MM}/{dd}/MyLogFile.txt",
          "retainedFileCountLimit": 31
        }
      }

    ],
    "Properties": {
      "Application": "int-test-logging",
      "Environment": "int"
    }
  }

}

enter image description here

I'm not sure what I'm doing incorrectly but any help would be appreciated. The following github repo contains code to implement the above (both approaches), and reproduces this behaviour. https://github.com/oneiltomlinson/AzureFunctionsLogging

like image 780
O'Neil Tomlinson Avatar asked Mar 06 '19 13:03

O'Neil Tomlinson


3 Answers

Just add

    "Using": [ "Serilog.Sinks.AzureBlobStorage" ] //under Serilog Config

and it will work!

Working Config

{
    "Serilog": {
        "Using": [
            "Serilog.Sinks.AzureBlobStorage"
        ],
        "MinimumLevel": {
            "Default": "Information",
            "Override": {
                "Microsoft": "Information"
            }
        },
        "WriteTo": [
            {
                "Name": "AzureBlobStorage",
                "Args": {
                    "connectionString": " --- REPLACE WITH STORAGEACCOUNT BLOB CONNECTION STRING --- ",
                    "formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact",
                    "storageFileName": "{yyyy}/{MM}/{dd}/MyLogFile.txt",
                    "retainedFileCountLimit": 31
                }
            }
        ],
        "Properties": {
            "Application": "int-test-logging",
            "Environment": "int"
        }
    }
}
like image 112
Amit Chaudhary Avatar answered Nov 11 '22 05:11

Amit Chaudhary


I've the same issue and even with all the required "using" of the used sinks, nothing change. This is my configuration file (just about the Serilog part):

      "Serilog": {
    "Using": [
      "Serilog.Sinks.RollingFile",
      "Serilog.Sinks.AzureTableStorage"
    ],
    "MinimumLevel": "Information",
    "Override": {
      "Microsoft": "Warning",
      "Microsoft.EntityFrameworkCore": "Information"
    },
    "WriteTo": [
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "MinimumLevel": "Information",
            "WriteTo": [
              {
                "Name": "Console",
                "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [TID:{ThreadId}] - {Message:lj}{NewLine}{Exception}"
              },
              {
                "Name": "Debug",
                "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [TID:{ThreadId}] - {Message:lj}{NewLine}{Exception}"
              },
              {
                "Name": "AzureTableStorage",
                "Args": {
                  "storageTableName": "HeroFunctionsLogs",
                  "connectionString": "DefaultEndpointsProtocol=https;AccountName=herobugari;AccountKey=NYJcdoCg9mQxqbQaTUdIxOHYQGdcKAwMsuWwzDub29UweHR1c+wd6Sh3IDQNB+eCx3DAe/ccobxu67sJvqQB5g==",
                  "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [TID:{ThreadId}] - {Message:lj}{NewLine}{Exception}",
                  "restrictedToMinimumLevel": "Information",
                  "writeInBatches": true,
                  "batchPostingLimit": 100
                }
              },
              {
                "Name": "RollingFile",
                "Args": {
                  "pathFormat": "logs\\Bulgari.Hero.Functions.log",
                  "retainedFileCountLimit": 10,
                  "buffered": true,
                  "flushToDiskInterval": 5,
                  "outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] [{Level:u3}] [TID:{ThreadId}] - {Message:lj}{NewLine}{Exception}"
                }
              }
            ],
            "Filter": [
              {
                "Name": "ByExcludingOnly",
                "Args": {
                  "expression": "SourceContext like '%Microsoft.EntityFrameworkCore%'"
                }
              }
            ]
          }
        }
      }
    ]
  }

and this the Startup.cs code that reads and try to use it:

    var config = new ConfigurationBuilder()
            .SetBasePath(Environment.CurrentDirectory)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddEnvironmentVariables().Build();
    // Registering Serilog provider
    logger = new LoggerConfiguration()
        //.WriteTo.Console()
        //.WriteTo.File("logs\\herofunctions.log", rollingInterval: RollingInterval.Day)
        .ReadFrom.Configuration(config)
        .CreateLogger();
    builder.Services.AddLogging(lb => lb.AddSerilog(logger));

The logger object has no "sinks" registered as it happens in the question.

like image 34
Andrea Ramacciotti Avatar answered Nov 11 '22 07:11

Andrea Ramacciotti


I have solved exactly the same issue here by adding entries in local.settings.json.

"Serilog:Using:0": "Serilog.Sinks.Console",
"Serilog:MinimumLevel": "Information",
"Serilog:Override:Microsoft": "Warning",
"Serilog:Override:System": "Warning",
"Serilog:WriteTo:Console:Name": "Console"

then in StartUp.cs:

var provider = builder.Services.BuildServiceProvider();
var config = provider.GetRequiredService<IConfiguration>();
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(config).CreateLogger();

then the function:

public class TestFunction
{
    private readonly ILogger _logger;
    public TestFunction()
    {
        _logger = Log.Logger;
    }

    [FunctionName("TestFunction")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
    {
        _logger.Information("Hello");
        return new OkResult();
    }
}

}

I can see the config entries registered and entries are logged!

like image 1
user1793938 Avatar answered Nov 11 '22 05:11

user1793938