Plinth Utilities for Azure Functions
$ dotnet add package Plinth.AzureFunctionUtility framework and enhancements for Azure Function projects
Adds enhancements and facilities for Azure Function projects with HTTP triggers including logging using the Plinth framework and Application Insights integration. This parallels the Plinth.AspNetCore package.
host.json or a custom loaded funcsettings.json, this configuration must be supplied.LogLevel and the ApplicationInsights blocks.
:point_right: Log levels set for application insights are the most important. The top level LogLevel block only controls local console logging{
"Logging": {
"LogLevel": {
"Default": "Debug"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Warning",
"System": "Warning"
}
}
}
}
In Program.cs, if you choose to load a custom funcsettings.json, here is an example of doing that. This should be done first before any other host configuration.
var host = new HostBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
var context = hostingContext.HostingEnvironment;
config
.AddJsonFile(Path.Combine(context.ContentRootPath, "funcsettings.json"), optional: false, reloadOnChange: false)
.AddJsonFile(Path.Combine(context.ContentRootPath, $"funcsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
})
Next, this enables middleware to provide service logging and exception handling for http triggered functions
.ConfigureFunctionsWorkerDefaults((config, builder) =>
{
builder.UsePlinthServiceLogging();
})
You may pass an Action to this call to configure some logging parameters
MaxRequestBody - maximum amount of the request body to be logged (default 25000)MaxResponseBody - maximum amount of the response body to be logged (default 25000)RequestProcessors - a mapping of api prefixes to callbacks for processing the request body to be logged before it is logged, for sanitation or filtering.ResponseProcessors - a mapping of api prefixes to callbacks for processing the response body to be logged before it is logged, for sanitation or filtering.Next, this enables application insights integration with the function runtime and configures ILogger to send traces
.ConfigureServices((hostingContext, services) =>
{
services.AddPlinthAppInsightsTelemetry(hostingContext.Configuration);
})
:point_right: The connection string for Application Insights will be retrieved from the configuration variable "APPLICATIONINSIGHTS_CONNECTION_STRING"
:point_right: The Cloud Role Name for Application Insights will be retrieved from the configuration variable "WEBSITE_CLOUD_ROLENAME"
When running locally, these can be set in local.settings.json. They should be supplied in the Azure Portal when running on Azure.
Next, this ensures that your settings from host.json or a custom loaded funcsettings.json are applied to ILogger
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
})
Once your IHost is built, in order to include all logging done by Plinth components (such as Plinth.HttpApiClient), you must add Plinth logging to the host.
This can be done by calling .AddPlinthLogging() before running the host.
await host
.AddPlinthLogging()
.RunAsync();
Microsoft provides a nuget package Microsoft.Azure.Functions.Worker.Extensions.OpenApi for generating OpenAPI and Swagger documentation based on your Http Trigger functions. If you include this package in your project, you'll need to document your functions like below
[Function("Function1")]
[OpenApiOperation(operationId: "function1", tags: new[] { "Functions" }, Summary = "Function 1", Description = "This is the first Function")]
[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ResponseModel), Summary = "The response", Description = "This returns the response")]
public async Task<ActionResult> RunFunction1([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
:point_right: NOTE: Do not name your functions any of these names, as they conflict with the functions generated by the Microsoft package, and the logging in Plinth will not log them.
To configure, follow this pattern. Note that if using the dotnet-isolated model, you will have to add your endpoint manually as shown below.
s.AddSingleton<IOpenApiConfigurationOptions>(_ =>
{
var options = new OpenApiConfigurationOptions()
{
Info = new OpenApiInfo()
{
Version = "1.0.0",
Title = "Swagger Test",
Description = "This is a test",
},
// these two lines are needed if using dotnet-isolated
Servers = [ new OpenApiServer() { Url = "http://localhost:7296/api", Description = "Local Dev" } ],
ExcludeRequestingHost = true,
OpenApiVersion = OpenApiVersionType.V3,
};
return options;
});
var host = new HostBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
var context = hostingContext.HostingEnvironment;
config
.AddJsonFile(Path.Combine(context.ContentRootPath, "funcsettings.json"), optional: false, reloadOnChange: false)
.AddJsonFile(Path.Combine(context.ContentRootPath, $"funcsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
})
.ConfigureFunctionsWorkerDefaults((config, builder) =>
{
builder.UsePlinthServiceLogging();
})
.ConfigureServices((hostingContext, services) =>
{
services.AddPlinthAppInsightsTelemetry(hostingContext.Configuration);
// OpenAPI package config here if desired
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
})
.Build();
await host
.AddPlinthLogging()
.RunAsync();
[Function("MyFunction")]
public async Task<ActionResult> MyFunction([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req)
{
var data = await SomeDataThing.GetDataAsync();
return new OkObjectResult(data);
}