Logging in Azure Functions

How to log from anywhere using ILogger and logLevel with .NET and Dependency Injection

Philipp Bauknecht
Published in
3 min readMar 21, 2023

--

When building Functions Apps I reach the point when I want to do Dependency Injection really fast. So typically I would start to create services and then register them in a startup class like:

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(LoggingDemo.Startup))]
namespace LoggingDemo;

class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<SampleService>();
}
}

To do this we also need to add Microsoft.Azure.Functions.Extensions from Nuget. Then in my SampleService I would expect to inject a ILogger to use for native logging, e.g.:

using Microsoft.Extensions.Logging;

namespace LoggingDemo;

public class SampleService
{
private ILogger<SampleService> _logger;

public SampleService(ILogger<SampleService> logger)
{
_logger = logger;
}

public void DoSomething()
{
_logger.LogInformation("I just did something.");
}
}

To use the service in a Function it’s important to make a function “non-static” and then inject the service:

namespace LoggingDemo;

public class HelloWorldWithDI
{
private readonly SampleService _sampleService;

public HelloWorldWithDI(SampleService sampleService)
{
_sampleService = sampleService;
}

[FunctionName("HelloWorldWithDI")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");

_sampleService.DoSomething();

return new OkResult();
}
}

Calling this function will only output the log of the function but not the log “I just did something.” from the service although the service is being called:

That’s because by default the runtime only outputs logs of a function. To change this let’s enable the log level “Information” as default in the host.json for all our code:

{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
},
"logLevel": {
"default": "Information"
}
}
}

Note: you may have to clean your solution in Visual Studio to have this in effect

With this enabled the output will be much more verbose and include the log of the sample service:

If this is just a bit too verbose it’s also possible to reduce this to just the log of specific classes. Therefore we need to change in a function for the generic Logger to ILogger of that class:

namespace LoggingDemo;

public class HelloWorldWithDI
{
private readonly SampleService _sampleService;
private readonly ILogger<HelloWorldWithDI> _logger;

public HelloWorldWithDI(SampleService sampleService, ILogger<HelloWorldWithDI> logger)
{
_sampleService = sampleService;
_logger = logger;
}

[FunctionName("HelloWorldWithDI")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");

_sampleService.DoSomething();

return new OkResult();
}
}

And then specify the classes we want to be logged out in the host.json:

{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
},
"logLevel": {
"default": "None",
"LoggingDemo.HelloWorldWithDI": "Information",
"LoggingDemo.SampleService": "Information"
}
}
}

This will result in a cleaner output:

--

--

Philipp Bauknecht

CEO @ medialesson. Microsoft Regional Director & MVP Windows Development. Father of identical twins. Passionate about great User Interfaces, NYC & Steaks