Azure Functions EF Core Logging

Brett McDonald 1 Reputation point
2022-03-23T20:59:36.32+00:00

In an Azure Function I would like to log EF Core Events to the ILogger Injected on the constructor when the Function is invoked. That way I can see the events in the log for the invocation of the Azure Function.

I am using DbContextOptionsBuilder's LogTo for example below:

Instead of writing to the Console. I want to write to the ILogger passed to the function. I am trying to figure out how to do that? Since the LogTo is setup once from Startup.cs in Configure method.

    builder.Services.AddDbContext<BfmGamesDbContext>(
        optionsBuilder => {
            optionsBuilder.LogTo(
                (eventId, level) => true, //!! eventId.Id == CoreEventId.ExecutionStrategyRetrying,
                (eventData) => {
                    Console.WriteLine($"Event EventIdCode: {eventData.EventIdCode} LogLevel: {eventData.LogLevel} EventId: {eventData.EventId}");

                    if (eventData is ExecutionStrategyEventData retryEventData) {
                        var exceptions = retryEventData.ExceptionsEncountered;
                        var exceptionsLast = exceptions[exceptions.Count - 1];
                        var sb = new StringBuilder();
                        sb.Append($"Retry #{exceptions.Count} with delay {retryEventData.Delay} due to error: HResult:{exceptionsLast.HResult} Message: {exceptionsLast.Message}");
                        if (exceptionsLast is SqlException sqlException) {
                            sb.Append($" SQL Error Number:{sqlException.Number} SQL Server State: {sqlException.State}");
                        }
                        Console.WriteLine(sb.ToString());
                    }
                });
            optionsBuilder.UseLoggerFactory(LogUtil.ConsoleLoggerFactory);
        }

I am trying to figure out how to replace Console.WriteLine(sb.ToString()); with an ILogger method. I have copy and pasted code to try to get to example.

Basically, I want to log events to ILogger.

Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
700 questions
Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
4,353 questions
{count} votes

2 answers

Sort by: Most helpful
  1. sadomovalex 3,626 Reputation points
    2022-03-29T15:01:00.457+00:00

    Console doesn't work with Azure functions - you have to write log messages to TraceWriter. Azure functions get TraceWriter as last parameter:

    [FunctionName("MyFunc")]
    public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
    ...
    }
    

    What you can do is to inject this TraceWriter instance to your ILogger somehow (e.g. implement new method ILogger.addTraceWriter() or something like that) at the beginning of function call. And of course change ILogger so it will also write data to injected TraceWriter


  2. Jaliya Udagedara 2,736 Reputation points MVP
    2022-04-06T06:07:47.467+00:00

    I just tried a quick sample.

    Can you try the following and let me know how it goes please.

    public override void Configure(IFunctionsHostBuilder builder)  
    {  
        builder.Services.AddDbContext<MyDbContext>(options =>  
            options  
                .UseSqlServer("<ConnectionString>"));  
      
    }  
    

    In your DbContext,

    public class MyDbContext : DbContext  
    {  
        private readonly ILogger<MyDbContext> _logger;  
      
        public MyDbContext(DbContextOptions options, ILogger<MyDbContext> logger) : base(options)  
        {  
            _logger = logger;  
        }  
      
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)  
        {  
            optionsBuilder  
                .LogTo(action =>  
                {  
                    _logger.LogInformation(action);  
                   // TODO: Use your implementation  
                });  
        }  
    }  
    

    And tried with a simple function.

    public class Function1  
    {  
        private readonly MyDbContext _myDbContext;  
      
        public Function1(MyDbContext myDbContext)  
        {  
            _myDbContext = myDbContext;  
        }  
      
        [FunctionName("Function1")]  
        public async Task<IActionResult> Run(  
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,  
            ILogger log)  
        {  
            _myDbContext.Database.EnsureCreated();  
              
            await _myDbContext.Employees.AddAsync(new Employee() { Name = "John Doe" });  
            await _myDbContext.SaveChangesAsync();  
      
            return new OkResult();  
        }  
    }  
    

    190368-image.png