9

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

Steve Land
  • 4,852
  • 2
  • 17
  • 36
O'Neil Tomlinson
  • 702
  • 1
  • 6
  • 28

4 Answers4

9

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"
        }
    }
}
  • Thanks this saved me a lot! Here is a small piece of code where I used it: https://github.com/chriswill/serilog-sinks-azureblobstorage/issues/27#issuecomment-1491553968 – LockTar Mar 31 '23 at 08:52
1

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.

1

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!

user1793938
  • 41
  • 1
  • 5
0

To write to SQL Server I had to add:

"Using": [
  "Serilog.Sinks.MSSqlServer"
],
IAmCoder
  • 3,179
  • 2
  • 27
  • 49