question

BrettMcDonald-6135 avatar image
0 Votes"
BrettMcDonald-6135 asked TharinduGunawardhana-8832 edited

Azure Functions EF Core Logging

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.

azure-functionsdotnet-entity-framework-core
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I am looking into this question and will get back to you with an answer

0 Votes 0 ·
BrettMcDonald-6135 avatar image BrettMcDonald-6135 MughundhanRaveendran-MSFT ·

Any luck? Or direction to look into? Can't seem to find anything to help with this?

Is there a way to route Console output to the ILogger for the function? That would work too.

0 Votes 0 ·

I am hoping you have some suggestions. I am trying to find a solution to this one.

0 Votes 0 ·

Any thoughts? I was hoping you would be able to come up with at least a direction to look.

0 Votes 0 ·
sadomovalex avatar image
0 Votes"
sadomovalex answered BrettMcDonald-6135 commented

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

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

What I want is to write to the Injected ILogger from Azure for the Function. TraceWriter is the older method injected I believe.

The problem is getting the object passed down to the EF Core logic that is setup once at the functions startup in the Configure method.

0 Votes 0 ·
JaliyaUdagedara avatar image
0 Votes"
JaliyaUdagedara answered TharinduGunawardhana-8832 edited

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



image.png (275.5 KiB)
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Do you know a method to get a scoped MyDbContext instance back from the service collection while staying inside the Configure method?

For example, lets say I cant to run db initializer there.

0 Votes 0 ·