From c30a5a8a6c4b8a5e0d5fbefc9f639b0742c5297c Mon Sep 17 00:00:00 2001 From: Springcomp Date: Sun, 24 Nov 2024 13:59:40 +0100 Subject: [PATCH 01/12] [dotnet8] Documented prerequisites --- lessons/dotnet8/prerequisites/README.md | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lessons/dotnet8/prerequisites/README.md diff --git a/lessons/dotnet8/prerequisites/README.md b/lessons/dotnet8/prerequisites/README.md new file mode 100644 index 00000000..41c052a8 --- /dev/null +++ b/lessons/dotnet8/prerequisites/README.md @@ -0,0 +1,49 @@ +# Prerequisites (.NET 8) + +## Frameworks & Tooling 🧰 + +In order to complete the the lessons you need to install the following: + +|Prerequisite|Lessons|Description +|-|-|- +|[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0)|All|The .NET runtime and SDK. +|[VSCode](https://code.visualstudio.com/Download)|All|A great cross platform code editor. +|[VSCode AzureFunctions extension](https://github.com/Microsoft/vscode-azurefunctions)|All|Extension for VSCode to easily develop and manage Azure Functions. +|[Azure Functions Core Tools v4](https://github.com/Azure/azure-functions-core-tools)|All|Azure Functions runtime and CLI for local development. +|[RESTClient for VSCode](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) or [Postman](https://www.postman.com/)|All|An extension or application to make HTTP requests. +|[Azure Storage Explorer](https://azure.microsoft.com/features/storage-explorer/)|Blob, Queue, Table|Application to manage Azure Storage resources (both in the cloud and local emulated). +|[Azurite](https://docs.microsoft.com/azure/storage/common/storage-use-azurite)|Blob, Queue, Table|Cross platform Emulator for using Azure Storage services if you want to develop locally without connecting to a Storage Account in the cloud. Instead of an emulator you can also use a real [Azure Storage Account](https://docs.microsoft.com/azure/storage/common/storage-account-create?tabs=azure-portal) in the cloud. +|[Azure CLI](https://docs.microsoft.com/cli/azure/what-is-azure-cli)|Deployment, Configuration|Command line interface used to manage Azure resources. Can be run on your local dev environment, in a deployment pipeline or in the [Azure Cloud Shell](https://docs.microsoft.com/azure/cloud-shell/overview). + +## Creating your local workspace πŸ‘©β€πŸ’» + +We strongly suggest you create a new folder (local git repository) for each lesson and use this Azure Functions University repository for reference only (for when you're stuck). + +- Create a new folder to work in: + + ```cmd + C:\dev\mkdir azfuncuni + C:\dev\cd .\azfuncuni\ + ``` + +- Turn this into a git repository: + + ```cmd + C:\dev\azfuncuni\git init + ``` + +- Add subfolders for the source code and test files: + + ```cmd + C:\dev\azfuncuni\mkdir src + C:\dev\azfuncuni\mkdir tst + ``` + +You should be good to go now! + +## Feedback + +We love to hear from you! Was this section useful to you? Is anything missing? Let us know in a [Feedback discussion post](https://github.com/marcduiker/azure-functions-university/discussions/new?category=feedback&title=.NET6%20Prerequisites) here on GitHub. + +--- +[πŸ”Ό Lessons Index](../../README.md) From cdab028ff6ad448e84554f188061816ad2a736f4 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Sun, 24 Nov 2024 15:18:06 +0100 Subject: [PATCH 02/12] [dotnet8] New lesson for Logging and Application Insights --- lessons/dotnet8/logging/README.md | 399 +++++++++++++++++++++++++ lessons/dotnet8/logging/log_levels.png | Bin 0 -> 92248 bytes 2 files changed, 399 insertions(+) create mode 100644 lessons/dotnet8/logging/README.md create mode 100644 lessons/dotnet8/logging/log_levels.png diff --git a/lessons/dotnet8/logging/README.md b/lessons/dotnet8/logging/README.md new file mode 100644 index 00000000..28fc527c --- /dev/null +++ b/lessons/dotnet8/logging/README.md @@ -0,0 +1,399 @@ +# Logging + +## Goal 🎯 + +Logging is a critical part of any application and helps monitor and troubleshoot its behaviour in production. In this lesson you will learn how to log from your Function App. + +This lesson consists of the following exercises: + +|Nr|Exercise +|---|--- +|0|[Prerequisites](#0-prerequisites) +|1|[Creating a Function App](#1-creating-a-function-app) +|2|[Logging to Application Insights](#2-logging-to-application-insights) +|3|[Log levels and categories](#3-log-levels-and-categories) +|4|[Cleanup Azure resources](#4-cleanup-azure-resources) +|5|[More Info](#5-more-info) + +> πŸ“ **Tip** - If you're stuck at any point you can have a look at the [source code](../../../src/dotnet8/http/AzFuncUni.Logging) in this repository. + +> πŸ“ **Tip** - If you have questions or suggestions about this lesson, feel free to [create a Lesson Q&A discussion](https://github.com/marcduiker/azure-functions-university/discussions/categories/lesson-q-a) here on GitHub. + +--- + +## 0. Prerequisites + +| Prerequisite | Exercise +| - | - +| Azure Functions Core Tools | 1-6 +| VS Code with Azure Functions extension| 1-6 +| REST Client for VS Code or Postman | 1-6 +| Azure Subscription | 2-7 + +See [.NET 8 prerequisites](../prerequisites/README.md) for more details. + +## 1. Creating a Function App + +In this exercise, you'll be creating a Function App with the default HTTPTrigger to serve as a startup project for subsequent exercises. + +This exercise is a condensed version of the +[HTTP Trigger (.NET 6)](../../dotnet6/http/README.md) lesson, targetting .NET 8 instead. Please, refer to that lesson for more in-depth review of the generated files and code + +### Steps + +1. In VSCode, create the Function App by running `AzureFunctions: Create New Project` in the Command Palette (CTRL+SHIFT+P). +2. Browse to the location where you want to save the function app (e.g. *AzFuncUni.Logging*). +3. Select the language you'll be using to code the function, in this lesson that is using `C#`. +4. Select `.NET 8.0 Isolated LTS` as the runtime. + + If you don't see .NET 8.0, choose: + + - `Change Azure Functions version` + - Select `Azure Functions v4` + - Select `.NET 8.0 Isolated LTS` +> +5. Select `HTTPTrigger` as the template. +6. Give the function a name (e.g. `HelloWorldHttpTrigger`). +7. Enter a namespace for the function (e.g. `AzFuncUni.Logging`). +8. Select `Function` for the AccessRights. + + > πŸ”Ž **Observation** - Notice that a new project has been fully generated. + +9. Build the project (CTRL+SHIFT+B). +10. Run the Function App by pressing `F5`. + + > πŸ”Ž **Observation** - Eventually you should see a local HTTP endpoint in the output. + +11. Now call the function by making a GET request to the above endpoint using a REST client: + + ```http + GET http://localhost:7071/api/HelloWorldHttpTrigger + ``` + + > πŸ”Ž **Observation** - You should receive a `200 OK` success response. + + +## 2. Logging to Application Insights + +You may have noticed that some lines have been printed to the Console each time the HTTP function is triggered. Unfortunately, the Console log output is very limited and does not offer much details on the structure of logs. + +Most Azure Functions end up logging to Azure Monitor. In particular, _Application Insights_ is a comprehensive Application Performance Monitoring component of Azure Monitor that, amgonst other things, collects telemetry from a running application. Logs βˆ’ or traces βˆ’ are one of many signals of telemetry that _Application Insights_ collects. + +In this section, you will learn the basics of _Application Insights_ and its _Live Metrics_ dashboard. + +### Steps + +1. Navigate to the Azure Portal and create [a new resource group](https://portal.azure.com/#view/Microsoft_Azure_Marketplace/GalleryItemDetailsBladeNopdl/id/Microsoft.ResourceGroup) named `AzFuncUni`, for instance. + +2. Navigate to the newly created resource group and create [a new _Application Insights_](https://portal.azure.com/#view/Microsoft_Azure_Marketplace/GalleryItemDetailsBladeNopdl/id/Microsoft.AppInsights) resource. This may also create a _Log Analytics Workspace_ resource. + +3. Go to the newly created resource and notice the `Essentials` section, at the top of the center pane. Please take note of the `Instrumentation Key` and `Connection String` properties. + +4. Back to your local working folder, open the `local.settings.json` project file and add two corresponding properties in the `Values` section: + +```json +{ + "Values": { + … + "APPINSIGHTS_INSTRUMENTATIONKEY": "", + "APPLICATIONINSIGHTS_CONNECTION_STRING": "" + } +} +``` + +> πŸ“ **Tip** - The `APPINSIGHTS_INSTRUMENTATIONKEY` property is being deprecated. However, at the time of writing, it is still necessary to enable _Live Metrics_ on the Azure Portal when the application is run locally. + +5. Open the `host.json` file and replace its content with: + +```json +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetrics": true + }, + "logLevel": { + "default": "Trace" + } + } +} +``` + +Our changes enable integration with the _Live Metrics_ dashboard associated with the _Application Insights_ resource that we will refer to from now on as β€œApp Insights”, for short. We also have lowered the default _Log Level_ to `Trace` so that virtually every log emitted from the application goes out unfiltered. + +However, logging to App Insights is not enabled by default. + +Furthermore, in an effort to help manage your infrastructure costs efficiently, the App Insights SDK adds a default logging filter for capturing warnings and errors only. + +Logging to Application Insights using lower severity requires an explicit override. + +6. To fix this, install the [required packages](https://learn.microsoft.com/fr-fr/azure/azure-functions/dotnet-isolated-process-guide?tabs=hostbuilder%2Cwindows#install-packages) as follows: + + ```pwsh + dotnet add package Microsoft.ApplicationInsights.WorkerService + dotnet add package Microsoft.Azure.Functions.Worker.ApplicationInsights + ``` + + +7. Open the `Program.cs` and add some using directives at the top of the file: + + ```c# + using Microsoft.Azure.Functions.Worker; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + ``` + +8. Further down in `Program.cs`, uncomment the relevant portion of the code. + + *Replace* + + ```c# + // Application Insights isn't enabled by default. See https://aka.ms/AAt8mw4. + // builder.Services + // .AddApplicationInsightsTelemetryWorkerService() + // .ConfigureFunctionsApplicationInsights(); + ``` + + *With* + + ```c# + // Logging to Application Insights + + builder.Services + .AddApplicationInsightsTelemetryWorkerService() + .ConfigureFunctionsApplicationInsights() + .Configure(options => + { + // The Application Insights SDK adds a default logging filter that instructs ILogger to capture only Warning and more severe logs. Application Insights requires an explicit override. + // Log levels can also be configured using appsettings.json. For more information, see https://learn.microsoft.com/en-us/azure/azure-monitor/app/worker-service#ilogger-logs + LoggerFilterRule? toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName + == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider"); + + if (toRemove is not null) + { + options.Rules.Remove(toRemove); + } + }); + ``` + +9. Compile and run the application again. + +10. From the Azure Portal, navigate to App Insights and display the _Live Metrics_ dashboard. You can find `Live Metrics` as one of the options available on the left pane, under the `Investigate` topic. + +Wait a couple dozen of seconds for the web page to refresh and display the dashboard. + +> πŸ“ **Tip** - Some ad blockers are known to prevent the dashboard from displaying. If you have ΞΌBlockβ‚€, you may see a `Data is temporarily inaccessible` red banner, for instance. Make sure to disable your ad blocker for the _Live Metrics_ page to display properly. + +Once the dashboard displays, notice that your machine is listed as one of the servers currently connected to App Insights. + +11. On your local machine, call the HTTP-triggered function a couple of times. + + ```http + POST http://localhost:7071/api/HelloWorldHttpTrigger + ``` + + > πŸ”Ž **Observation** - You should notice some spikes of activity in the _Live Metrics_ dashboard and see a host of logs being recorded on the right `Sample telemetry` pane. + +From the right pane, locate and click on one of the recorded logs, with the following message text: `"C# HTTP trigger function processed a request"`. + +Details from the selected log are displayed on the lower right pane. In particular, notice the following two properties: + +- `Category`: `Function.HelloWorldHttpTrigger.User` +- `LogLevel`: `Information` + +Along with their messages, those are amongst the most important properties from the collected logs. +In the next section, you will dive into those properties in a bit more details. + +12. Hit Ctrl+C from the Console of the running application to stop its execution. + +## 3. Log levels and categories + +In this section, you will learn the basics of _Application Insights_ and its _traces_ log store. +You will also learn about _Log Categories_ and how to filter log output based upon _Log Levels_ and categories. + +### Overview + +> πŸ“ **Tip** - App Insights is a comprehensive Application Performance Monitoring (APM) solution. As such, it does a lot more than collecting traces from a running application. In this lesson, you will mostly focus on interacting with App Insights using .NET's [Microsoft.Extensions.Logging.ILogger](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging) abstraction. + +As you have seen on the previous section, each log is associated with a set of properties, two of which are its _Category_ and _Log Level_ properties. + +#### Log levels + +The log level is a measure of how critical or urgent an event reported by the application is. Using an appropriate log level, you can separate logs that simply convey useful information on how your application behaves from errors that are raised as part of its execution. + +More importantly, log levels offer a way to regulate the amount of data that is transmitted to your monitoring system. For App Insights, this is a good way to limit the charges incurred by the service. + +When troubleshooting is needed, additional insights can be gained by increasing the level of logs momentarily. This can be done dynamically without impacting the running application. + +When to use what level for logging falls outside the scope of this lesson. +However, you may like [this simple chart](https://stackoverflow.com/a/64806781) that I found online. + +![](log_levels.png) + +Credit: [Taco Jan Osinga](https://stackoverflow.com/users/3476764/taco-jan-osinga) (2020) - [When to use the different log levels](https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels) - [Stack Overflow](https://stackoverflow.com/). + +The [ILogger](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.loglevel) abstraction used within Azure Functions defines the following log levels: + +- `LogLevel.Trace` +- `LogLevel.Debug` +- `LogLevel.Information` +- `LogLevel.Warning` +- `LogLevel.Error` +- `LogLevel.Critical` +- `LogLevel.None` + +Using `LogLevel.None` effectively disables log output. + +In the previous exercise, you have seen how setting the default log level for the entire application to `"Trace"` in the `host.json` file dramatically increased the amount of traces emitted when running the application. Changing the default level is a crude way to limit the quantity of logs. Later in this exercise, you will learn to configure log levels for particular _categories_ of logs. + +### Categories + +Logs are divided into multiple _categories_, which form a set of hierachical namespaces. +Splitting logs into multiple categories allows you to associate appropriate log levels to each category. + +By default, each `ILogger` instance is associated with a category hierarchy based upon the full type name of its corresponding dotnet class. + +As a [rule of thumb](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging#log-category), each dotnet class has a full type name that represents a category hierarchy for the purpose of logging. However, functions in your Function App behave slightly differently. + +Before running the code from your functions, the Functions Runtime first runs the code associated with any trigger and input bindings associated with parameters to your functions. Likewise, after having executed your code, the Functions Runtime runs the code associated with return and output bindings that you may have specified. + +For this reason each function decorated using the [`FunctionAttribute`](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=hostbuilder%2Cwindows#methods-recognized-as-functions) class emits logs associated with the following category hierarchy: + +- `Functions.`: category associated with logs from triggers and bindings used by your function. +- `` category associated with logs from your code using the `ILogger` instance initialized in the constructor of your function class. + +In this exercise, you will discover log categories and learn how to filter log output based upon categories using appropriate log levels. + +### Steps + +1. Open the Azure Portal and navigate to App Insights. +2. On the left pane, click on `Logs` option under the `Monitoring` topic. +3. Close the `Welcome to Application Insights` screen. +4. On the `Queries` screen, uncheck the `Always show Queries` option and close the screen. + + > πŸ”Ž **Observation** - This is the main interface in App Insights. You will use this interface to write and execute queries on collected telemetry. This screen has a left panel that displays the App Insights tables, amongst which you should see one named `traces`. + + > πŸ“ **Tip** - Double-click on the `traces` table to start a new query and click the `▢️ Run` button. You should see a list of logs in the results pane at the bottom of your screen. + +5. Use a query to discover log categories emitted by your application: + + Replace the query with the following text: + + ```sql + traces + | summarize count(message) by tostring(customDimensions.Category) + | order by customDimensions_Category + ``` + + > πŸ“ **Tip** - App Insights uses a SQL-like query language named [Kusto Query Language](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/) (KQL). + + > πŸ”Ž **Observation** - The query breaks down the number of logs associated with each category. This is an easy way to get hold of the category associated with each log. You may want to use this method if you see spurious logs that you would like to filter in the future. + + Please, note that most log categories share only a handful of common "top-level" prefixes. In practice, the most common category hierarchies are: + + - `Azure` + - `Azure.Core` + - `Microsoft` + - `Microsoft.Azure` + - `Microsoft.Extensions` + - `Microsoft.AspNetCore` + - `Host` + - `Host.General` + - `Host.Startup` + - `Function` + - `Function.` + - `Function..User` + - `System` + + +6. Armed with this knowledge, filter the log output from your application. + + In the `host.json` file, update the `loglevel` section to look like: + + ```json + "logLevel": { + "default": "Warning", + "Functions.HelloWorldHttpTrigger": "Warning", + "AzFuncUni.Logging.HelloWorldHttpTrigger": "Information" + } + ``` + +7. Compile and run the application. +8. Call the HTTP-triggered function multiple times. + + ```http + POST http://localhost:7071/api/HelloWorldHttpTrigger + ``` + +9. In App Insights, change the `Time range` to `Last 30 minutes` and run the log category break down query again. + + ```sql + traces + | summarize count(message) by tostring(customDimensions.Category) + | order by customDimensions_Category + ``` + + > πŸ”Ž **Observation** - After a few minutes, you should see a dramatic reduction in the amount of categories under which your application logs. In fact, given enough time, only logs associated with the `AzFuncUni.Logging.HelloWorldHttpTrigger` category hierarchy should be emitted. + +10. Hit Ctrl+C from the Console of the running application to stop its execution. + +11. Update log levels while the application is running + + Once deployed to Azure, you Function App `host.json` file cannot easily be modified. To change the level associated with a given log category while the application is running, you can update the Function App’s _App Setttings_. + + Notice that in `host.json`, the full "path" to a particular log level directive looks like: + + `` logging / loglevel / `` + + When coming directly from the host, logs are anchored into an implicit `AzureFunctionsJobHost` top-level section. + + To represent this hiearchy in _App Settings_, use a `__` double-underscore separator and replace the `.` separator with a single `_` underscore character. + + On Azure, when _App Settings_ are changed, the Function App restarts. + + When run locally, _App Settings_ are specified in `local.settings.json`. + Update this file and add the following two properties: + + ```json + { + "Values": { + … + "AzureFunctionsJobHost__Logging__LogLevel__default": "Debug", + "AzureFunctionsJobHost__Logging__LogLevel__Function__HelloWorldHttpTrigger": "Trace", + "Logging__LogLevel__AzFuncUni__Logging__HelloWorldHttpTrigger": "Trace" + } + } + ``` + +12. Compile and run the application +13. Call the HTTP-triggered function a couple of times. + + > πŸ”Ž **Observation** - Head over to App Insights in Azure Portal and run a query from the _Logs_ authoring page. You can also display the _Live Metrics_ dashboard for more lively feedback. + + +In this lesson, you learned how to add logs to your application, and how to efficiently use categories and log levels to limit the quantity of logs emitted by the application at any one time – this helps reduce costs and helps support staff by preventing unwanted noise. + +You also learned how to update log levels for particular categories to help troubleshoot issues that may happen after the application is deployed to Azure. + + +## 4. Cleanup Azure resources + +In this exercise, you will cleanup Azure resources to prevent unwanted recurring charges. + +### Steps + +1. Navigate to the Azure Portal locate and delete the `AzFuncUni` resource group. This will automatically remove all resources that have been created as part of this lesson. For the record, you may need to remove: + +- The default _Log Analytics Workspace_ resource. +- The test _Application Insights_ resource. +- The resource group. + +2. Remove the _Function App_ resource you may have deployed when doing your homework. + +## 5. More info + +- [Log Levels Explained](https://betterstack.com/community/guides/logging/log-levels-explained/) diff --git a/lessons/dotnet8/logging/log_levels.png b/lessons/dotnet8/logging/log_levels.png new file mode 100644 index 0000000000000000000000000000000000000000..115aa8bad85d4a39fdefa06c4928b8d21ba4eccd GIT binary patch literal 92248 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

  • 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 Q0i_u{UHx3vIVCg!0D(*yG5`Po literal 0 HcmV?d00001 From c4fdc674d345285570b7f94d1fe0dcc0708cb729 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Sun, 24 Nov 2024 16:11:53 +0100 Subject: [PATCH 03/12] [dotnet8] Added supporting code for Logging lesson --- .../logging/AzFuncUni.Logging/.gitignore | 264 ++++++++++++++++++ .../AzFuncUni.Logging/.vscode/extensions.json | 6 + .../AzFuncUni.Logging/.vscode/launch.json | 11 + .../AzFuncUni.Logging/.vscode/settings.json | 7 + .../AzFuncUni.Logging/.vscode/tasks.json | 69 +++++ .../AzFuncUni.Logging.csproj | 30 ++ .../HelloWorldHttpTrigger.cs | 24 ++ .../logging/AzFuncUni.Logging/Program.cs | 29 ++ .../logging/AzFuncUni.Logging/host.json | 16 ++ .../AzFuncUni.Logging/local-tests.http | 1 + .../AzFuncUni.Logging/local.settings.json | 9 + 11 files changed, 466 insertions(+) create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/.gitignore create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/.vscode/extensions.json create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/.vscode/launch.json create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/.vscode/settings.json create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/.vscode/tasks.json create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/Program.cs create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/host.json create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/local-tests.http create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/local.settings.json diff --git a/src/dotnet8/logging/AzFuncUni.Logging/.gitignore b/src/dotnet8/logging/AzFuncUni.Logging/.gitignore new file mode 100644 index 00000000..ff5b00c5 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/.vscode/extensions.json b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/extensions.json new file mode 100644 index 00000000..bb763007 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-azuretools.vscode-azurefunctions", + "ms-dotnettools.csharp" + ] +} \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/.vscode/launch.json b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/launch.json new file mode 100644 index 00000000..9e716f90 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to .NET Functions", + "type": "coreclr", + "request": "attach", + "processId": "${command:azureFunctions.pickProcess}" + } + ] +} \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/.vscode/settings.json b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/settings.json new file mode 100644 index 00000000..71ee1ac6 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "azureFunctions.deploySubpath": "bin/Release/net8.0/publish", + "azureFunctions.projectLanguage": "C#", + "azureFunctions.projectRuntime": "~4", + "debug.internalConsoleOptions": "neverOpen", + "azureFunctions.preDeployTask": "publish (functions)" +} \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/.vscode/tasks.json b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/tasks.json new file mode 100644 index 00000000..51992590 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/.vscode/tasks.json @@ -0,0 +1,69 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "clean (functions)", + "command": "dotnet", + "args": [ + "clean", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile" + }, + { + "label": "build (functions)", + "command": "dotnet", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean (functions)", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$msCompile" + }, + { + "label": "clean release (functions)", + "command": "dotnet", + "args": [ + "clean", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "problemMatcher": "$msCompile" + }, + { + "label": "publish (functions)", + "command": "dotnet", + "args": [ + "publish", + "--configuration", + "Release", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "type": "process", + "dependsOn": "clean release (functions)", + "problemMatcher": "$msCompile" + }, + { + "type": "func", + "dependsOn": "build (functions)", + "options": { + "cwd": "${workspaceFolder}/bin/Debug/net8.0" + }, + "command": "host start", + "isBackground": true, + "problemMatcher": "$func-dotnet-watch" + } + ] +} \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj b/src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj new file mode 100644 index 00000000..fda9e457 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj @@ -0,0 +1,30 @@ +ο»Ώ + + net8.0 + v4 + Exe + enable + enable + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs b/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs new file mode 100644 index 00000000..bb8fced6 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace AzFuncUni.Logging +{ + public class HelloWorldHttpTrigger + { + private readonly ILogger _logger; + + public HelloWorldHttpTrigger(ILogger logger) + { + _logger = logger; + } + + [Function("HelloWorldHttpTrigger")] + public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + { + _logger.LogInformation("C# HTTP trigger function processed a request."); + return new OkObjectResult("Welcome to Azure Functions!"); + } + } +} diff --git a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs new file mode 100644 index 00000000..91bc63e1 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs @@ -0,0 +1,29 @@ +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +var builder = FunctionsApplication.CreateBuilder(args); + +builder.ConfigureFunctionsWebApplication(); + +// Logging to Application Insights + +builder.Services + .AddApplicationInsightsTelemetryWorkerService() + .ConfigureFunctionsApplicationInsights() + .Configure(options => + { + // The Application Insights SDK adds a default logging filter that instructs ILogger to capture only Warning and more severe logs. Application Insights requires an explicit override. + // Log levels can also be configured using appsettings.json. For more information, see https://learn.microsoft.com/en-us/azure/azure-monitor/app/worker-service#ilogger-logs + LoggerFilterRule? toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName + == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider"); + + if (toRemove is not null) + { + options.Rules.Remove(toRemove); + } + }); + +builder.Build().Run(); diff --git a/src/dotnet8/logging/AzFuncUni.Logging/host.json b/src/dotnet8/logging/AzFuncUni.Logging/host.json new file mode 100644 index 00000000..714a4d40 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/host.json @@ -0,0 +1,16 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetrics": true + }, + "logLevel": { + "default": "Warning", + "AzFuncUni.Logging.HelloWorldHttpTrigger": "Information" + } + } +} \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http b/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http new file mode 100644 index 00000000..98d8a27f --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http @@ -0,0 +1 @@ +GET http://localhost:7071/api/HelloWorldHttpTrigger \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json new file mode 100644 index 00000000..288198bf --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json @@ -0,0 +1,9 @@ +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "UseDevelopmentStorage=true;", + "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", + "APPINSIGHTS_INSTRUMENTATIONKEY": "00000000000000000000000000000000", + "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=00000000000000000000000000000000;IngestionEndpoint=https://francecentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://region.livediagnostics.monitor.azure.com/;ApplicationId=00000000000000000000000000000000" + } +} \ No newline at end of file From 2ebf9976e2e985cc5a9d66b9c48d621e24bd952e Mon Sep 17 00:00:00 2001 From: Springcomp Date: Sun, 24 Nov 2024 16:12:09 +0100 Subject: [PATCH 04/12] [dotnet8] Added workspace for Logging lesson --- .../02-logging-to-application-insights.tour | 70 +++++++++++++++++++ workspaces/dotnet8/logging.code-workspace | 26 +++++++ 2 files changed, 96 insertions(+) create mode 100644 .tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour create mode 100644 workspaces/dotnet8/logging.code-workspace diff --git a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour new file mode 100644 index 00000000..61fccc2b --- /dev/null +++ b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour @@ -0,0 +1,70 @@ +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "2 - Logging to Application Insights", + "steps": [ + { + "title": "Goal", + "description": "Logging is a critical part of any application and helps monitor and troubleshoot its behaviour in production. In this lesson you will learn how to log from your Function App.\r\n\r\nYou will learn how to add logs to your application, and how to efficiently use categories and log levels to limit the quantity of logs emitted by the application at any one time – this helps reduce costs and helps support staff by preventing unwanted noise.\r\n\r\nYou will also learn how to update log levels for particular categories to help troubleshoot issues that may happen after the application is deployed to Azure." + }, + { + "title": "Connecting to Application Insights", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/local.settings.json", + "description": "The `APPLICATIONINSIGHTS_CONNECTION_STRING` app setting selects the connection string used to connect to Azure Application Insights.\r\n\r\nYou can find the value for this setting by navigating to the Azure Portal, and locating the Application Insights resource under considration. There, notice `Essentials` section, at the top of the center pane.\r\nThat’s where you can find the `Instrumentation Key` and `Connection String` properties.", + "line": 7 + }, + { + "title": "Configuring the Functions Runtime host", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/host.json", + "description": "The Functions Runtime host is the compute infrastructure that runs your function app. It can be configured using the `host.json` file.\r\n\r\nThe `logging/applicationInsights/enableLiveMetrics` boolean property must be set to `true` to enable the \"Live Metrics\" console on the portal. That console displays real-time logs from your application, including when that application runs locally.", + "line": 9 + }, + { + "title": "Configuring the log levels", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/host.json", + "description": "The Functions Runtime host receives requests for logging from your function app worker process using gRPC.\r\n\r\nThe `logging/loglevel` section from the `host.json` file allows you to filter logs based on their categories.", + "line": 12 + }, + { + "title": "Installing Application Insights dependencies", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", + "description": "The `Microsoft.ApplicationInsights.WorkerService` package is the main SDK that is used by .NET console applications (referred to as _workers_) that need to interact with Application Insights.\r\nAs a worker process itself, the Function App depends on this package for logging to Application Insights.", + "line": 11 + }, + { + "title": "Installing Function App dependencies", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", + "description": "The `Microsoft.Azure.Functions.Worker.ApplicationInsights` package is required to enable logging to Application Insights from your Function App worker process.", + "line": 13 + }, + { + "title": "Using statements", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", + "description": "These _using_ statements at the top of the source file are required to enable logging to Application Insights.\r\n\r\nNote that most of those statements are generic-enough; that’s because most features are packaged using extension classes located in a limited number of well-known namespaces.", + "line": 5 + }, + { + "title": "Logging to Application Insights", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", + "description": "Those instructions enable logging to ApplicationInsights.\r\n\r\nThe `AddApplicationInsightsTelemetryWorkerService` method enables connection to Application Insights from _worker_ processes such as non-HTTP workloads, background tasks and console applications and is not specific to Function Apps.\r\n\r\nThe `ConfigureFunctionsApplicationInsights` method is a simple method provided by the Azure Functions .NET Worker SDK to properly setup the Function App for logging to Application Insights.", + "line": 15 + }, + { + "title": "Remove logging constraints for debugging purposes", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", + "description": "In order to help reduce cost of your cloud infrastructure, the Application Insights SDK adds a default logging filter that instructs `ILogger` to capture logs with a severity of `Warning` or more.\r\n\r\nIn this lesson, that rule is removed so that logging using lower levels, such as `Information` can be sent and recorded into Application Insights.", + "line": 27 + }, + { + "title": "Selecting a category for logging", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs", + "description": "Most of the work so far involved installing NuGet dependencies and configuring them appropriately upon startup of the worker process.\r\n\r\nIn the program, a developer can use the `ILogger` abstraction to focus on logging – what, and how – without worrying about specific details related to where those logs are sent.\r\n\r\nThe specific instance of that logger for the class is specified as a generic parameter to the `ILogger` interface. Here, this ties the logger to a _Category_ that is the fully qualified name of the class, _i.e_ `AzFuncUni.Logging.HelloWordHttpTrigger`.", + "line": 10 + }, + { + "title": "Selecting a log level for logging", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs", + "description": "Using builtin helper methods from `ILogger` – like `LogInformation` or `LogError` – a developer can select the appropriate log level for logging.", + "line": 20 + } + ] +} \ No newline at end of file diff --git a/workspaces/dotnet8/logging.code-workspace b/workspaces/dotnet8/logging.code-workspace new file mode 100644 index 00000000..b2306973 --- /dev/null +++ b/workspaces/dotnet8/logging.code-workspace @@ -0,0 +1,26 @@ +{ + "folders": [ + { + "path": "../../lessons/dotnet8/logging", + "name" : "Logging to Application Insights" + }, + { + "path": "../../src/dotnet8/logging/AzFuncUni.Logging", + "name" : "Logging Source Code" + }, + { + "path": "../../.tours/dotnet8/logging", + "name" : "(Code Tour files)" + } + ], + "settings": { + "debug.internalConsoleOptions": "neverOpen" + }, + "extensions": { + "recommendations": [ + "ms-azuretools.vscode-azurefunctions", + "ms-dotnettools.csharp", + "vsls-contrib.codetour" + ] + } +} From 24ac4a1498f03e7032c24209d7417d4c71cd521e Mon Sep 17 00:00:00 2001 From: Springcomp Date: Sun, 24 Nov 2024 17:43:04 +0100 Subject: [PATCH 05/12] Added reference to dotnet8 lessons --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 070fcd79..3dbf5884 100644 --- a/README.md +++ b/README.md @@ -35,20 +35,21 @@ Azure Functions is an event-driven serverless compute platform in the Azure clou ## Lessons -Lesson|.NET Core|.NET 6|Typescript|PowerShell|Python|Contributions by -|-|-|-|-|-|-|- -|Prerequisites|[βœ”](lessons/dotnetcore31/prerequisites/README.md)|[βœ”](lessons/dotnet6/prerequisites/README.md)|[βœ”](lessons/typescript/prerequisites/README.md)|[βœ”](lessons/PowerShell/prerequisites/README.md)|[βœ”](lessons/python/prerequisites/README.md)|Marc, Gwyneth, Barbara, Christian, Dana -|HTTP Trigger|[βœ”](lessons/dotnetcore31/http/README.md)|[βœ”](lessons/dotnet6/http/README.md)|[βœ”](lessons/typescript/http/README.md)|[βœ” (VS Code)](lessons/PowerShell/http/README.md),
    [βœ” (Portal)](lessons/PowerShell/http/http-lesson-powershell-portal.md)|[βœ”](lessons/python/http/README.md)|Marc, Gwyneth, Barbara, Caroline, Christian, Dana -|Calling 3rd party REST APIs with Refit|-|[βœ”](lessons/dotnet6/http-refit/README.md)|-|-|-|Maxime, Marc -|Advanced scenarios with Refit|-|[βœ”](lessons/dotnet6/http-refit-auth/README.md)|-|-|-|Maxime -|Blob Trigger & Bindings|[βœ”](lessons/dotnetcore31/blob/README.md)|-|[βœ”](lessons/typescript/blob/README.md)|-|-|Marc, Gwyneth, Christian -|Queue Trigger & Bindings|[βœ”](lessons/dotnetcore31/queue/README.md)|-|-|-|-|Marc -|Table Bindings|[βœ”](lessons/dotnetcore31/table/README.md)|-|-|-|-|Marc -|Deployment to Azure|[βœ”](lessons/dotnetcore31/deployment/README.md)|[βœ”](lessons/dotnet6/deployment/README.md)|-|-|[βœ”](lessons/python/http/http-lesson-deploy.md)|Marc, Dana -|Cosmos DB Trigger & Bindings|[βœ”](lessons/dotnetcore31/cosmosdb/README.md)|-|-|-|-|Gabriela, Marc -|Durable Functions I |-|-|[βœ”](lessons/typescript/durable-functions/chaining/README.md)|-|-|Christian, Marc -|Durable Functions II |-|-|[βœ”](lessons/typescript/durable-functions/advanced/README.md)|-|-|Christian, Marc -|Configuration|[βœ”](lessons/dotnetcore31/configuration/README.md)|-|-|-|-|Stacy, Marc +Lesson|.NET Core|.NET 6|.NET 8|Typescript|PowerShell|Python|Contributions by +|-|-|-|-|-|-|-|- +|Prerequisites|[βœ”](lessons/dotnetcore31/prerequisites/README.md)|[βœ”](lessons/dotnet6/prerequisites/README.md)|[βœ”](lessons/dotnet8/prerequisites/README.md)|[βœ”](lessons/typescript/prerequisites/README.md)|[βœ”](lessons/PowerShell/prerequisites/README.md)|[βœ”](lessons/python/prerequisites/README.md)|Marc, Gwyneth, Barbara, Christian, Dana +|HTTP Trigger|[βœ”](lessons/dotnetcore31/http/README.md)|[βœ”](lessons/dotnet6/http/README.md)|-|[βœ”](lessons/typescript/http/README.md)|[βœ” (VS Code)](lessons/PowerShell/http/README.md),
    [βœ” (Portal)](lessons/PowerShell/http/http-lesson-powershell-portal.md)|[βœ”](lessons/python/http/README.md)|Marc, Gwyneth, Barbara, Caroline, Christian, Dana +|Calling 3rd party REST APIs with Refit|-|[βœ”](lessons/dotnet6/http-refit/README.md)|-|-|-|-|Maxime, Marc +|Advanced scenarios with Refit|-|[βœ”](lessons/dotnet6/http-refit-auth/README.md)||-|-|-|Maxime +|Blob Trigger & Bindings|[βœ”](lessons/dotnetcore31/blob/README.md)|-|-|[βœ”](lessons/typescript/blob/README.md)|-|-|Marc, Gwyneth, Christian +|Queue Trigger & Bindings|[βœ”](lessons/dotnetcore31/queue/README.md)|-|-|-|-|-|Marc +|Table Bindings|[βœ”](lessons/dotnetcore31/table/README.md)|-|-|-|-|-|Marc +|Deployment to Azure|[βœ”](lessons/dotnetcore31/deployment/README.md)|[βœ”](lessons/dotnet6/deployment/README.md)|-|-|-|[βœ”](lessons/python/http/http-lesson-deploy.md)|Marc, Dana +|Cosmos DB Trigger & Bindings|[βœ”](lessons/dotnetcore31/cosmosdb/README.md)|-|-|-|-|-|Gabriela, Marc +|Durable Functions I |-|-|-|[βœ”](lessons/typescript/durable-functions/chaining/README.md)|-|-|-|Christian, Marc +|Durable Functions II |-|-|-|[βœ”](lessons/typescript/durable-functions/advanced/README.md)|-|-|-|Christian, Marc +|Configuration|[βœ”](lessons/dotnetcore31/configuration/README.md)|-|-|-|-|-|Stacy, Marc +|Logging|-|-|[βœ”](lessons/dotnet8/logging/README.md)|-|-|-|Maxime, Marc ## Contribute From c7ff83e8eb31c2d73455f0f31585c9f9ee89a557 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Sun, 24 Nov 2024 17:50:59 +0100 Subject: [PATCH 06/12] FIX: link --- lessons/dotnet8/logging/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/dotnet8/logging/README.md b/lessons/dotnet8/logging/README.md index 28fc527c..dc2e07dd 100644 --- a/lessons/dotnet8/logging/README.md +++ b/lessons/dotnet8/logging/README.md @@ -15,7 +15,7 @@ This lesson consists of the following exercises: |4|[Cleanup Azure resources](#4-cleanup-azure-resources) |5|[More Info](#5-more-info) -> πŸ“ **Tip** - If you're stuck at any point you can have a look at the [source code](../../../src/dotnet8/http/AzFuncUni.Logging) in this repository. +> πŸ“ **Tip** - If you're stuck at any point you can have a look at the [source code](../../../src/dotnet8/logging/AzFuncUni.Logging) in this repository. > πŸ“ **Tip** - If you have questions or suggestions about this lesson, feel free to [create a Lesson Q&A discussion](https://github.com/marcduiker/azure-functions-university/discussions/categories/lesson-q-a) here on GitHub. From ad774fc8798e1888471a6b154e3d553a4daab106 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Tue, 26 Nov 2024 17:28:05 +0100 Subject: [PATCH 07/12] [lesson] proof-reading --- lessons/dotnet8/logging/README.md | 79 +++++++++++++----- .../logging/isolated-worker-process.png | Bin 0 -> 30850 bytes 2 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 lessons/dotnet8/logging/isolated-worker-process.png diff --git a/lessons/dotnet8/logging/README.md b/lessons/dotnet8/logging/README.md index dc2e07dd..4814a218 100644 --- a/lessons/dotnet8/logging/README.md +++ b/lessons/dotnet8/logging/README.md @@ -25,10 +25,10 @@ This lesson consists of the following exercises: | Prerequisite | Exercise | - | - -| Azure Functions Core Tools | 1-6 -| VS Code with Azure Functions extension| 1-6 -| REST Client for VS Code or Postman | 1-6 -| Azure Subscription | 2-7 +| Azure Functions Core Tools | 1-5 +| VS Code with Azure Functions extension| 1-5 +| REST Client for VS Code or Postman | 1-5 +| Azure Subscription | 2-5 See [.NET 8 prerequisites](../prerequisites/README.md) for more details. @@ -77,9 +77,33 @@ This exercise is a condensed version of the You may have noticed that some lines have been printed to the Console each time the HTTP function is triggered. Unfortunately, the Console log output is very limited and does not offer much details on the structure of logs. -Most Azure Functions end up logging to Azure Monitor. In particular, _Application Insights_ is a comprehensive Application Performance Monitoring component of Azure Monitor that, amgonst other things, collects telemetry from a running application. Logs βˆ’ or traces βˆ’ are one of many signals of telemetry that _Application Insights_ collects. +Most Azure Functions end up logging to Azure Monitor. In particular, _Application Insights_ is a comprehensive Application Performance Monitoring component of Azure Monitor that, amongst other things, collects telemetry from a running application. Logs βˆ’ or traces βˆ’ are one of many signals of telemetry that _Application Insights_ collects. -In this section, you will learn the basics of _Application Insights_ and its _Live Metrics_ dashboard. +### Overview + +Before diving into the code for this exercise, it is critical to understand how your Function App works as it directly drives the configuration for logging to _Application Insights_ successfully. + +Azure Functions is a compute infrastructure that runs your _functions-as-a-service_ workload +through the _Functions Runtime Host_ process. + +The Function App itself is a .NET Console application that runs as a separate process referred to as the _Worker_ process. +By linking to the `Microsoft.Azure.Functions.Worker` NuGet package, the program starts a remote-process server and waits for the +communication from the host using the [gRPC](https://grpc.io/) protocol. + +![](./isolated-worker-process.png) + +You may already be familiar with the `host.json` file that is used to configure the host. + +By default, a Function App running as an isolated worker process does not use a separate configuration +file and relies entirely on environment variables and application settings in Azure. As you will see later +in this lesson, however, it is often desirable to use a separate file for the log configuration. + +As your isolated worker process runs – as its name suggests – in a separate process from the host, +it needs its own file to store its own settings and configurations for logging. In this lesson, the +program will load the log (a subset of) the configuration from the `host.json` file, +making it a shared file for both the host and the worker process itself. + +In the following section, you will learn the basics of _Application Insights_ and its _Live Metrics_ dashboard. ### Steps @@ -87,7 +111,7 @@ In this section, you will learn the basics of _Application Insights_ and its _Li 2. Navigate to the newly created resource group and create [a new _Application Insights_](https://portal.azure.com/#view/Microsoft_Azure_Marketplace/GalleryItemDetailsBladeNopdl/id/Microsoft.AppInsights) resource. This may also create a _Log Analytics Workspace_ resource. -3. Go to the newly created resource and notice the `Essentials` section, at the top of the center pane. Please take note of the `Instrumentation Key` and `Connection String` properties. +3. Go to the newly created resource and notice the `Essentials` section, at the top of the center pane. Please take note of the and `Connection String` property. 4. Back to your local working folder, open the `local.settings.json` project file and add two corresponding properties in the `Values` section: @@ -95,14 +119,11 @@ In this section, you will learn the basics of _Application Insights_ and its _Li { "Values": { … - "APPINSIGHTS_INSTRUMENTATIONKEY": "", "APPLICATIONINSIGHTS_CONNECTION_STRING": "" } } ``` -> πŸ“ **Tip** - The `APPINSIGHTS_INSTRUMENTATIONKEY` property is being deprecated. However, at the time of writing, it is still necessary to enable _Live Metrics_ on the Azure Portal when the application is run locally. - 5. Open the `host.json` file and replace its content with: ```json @@ -111,7 +132,7 @@ In this section, you will learn the basics of _Application Insights_ and its _Li "logging": { "applicationInsights": { "samplingSettings": { - "isEnabled": true, + "isEnabled": false, "excludedTypes": "Request" }, "enableLiveMetrics": true @@ -138,16 +159,20 @@ Logging to Application Insights using lower severity requires an explicit overri dotnet add package Microsoft.Azure.Functions.Worker.ApplicationInsights ``` + > πŸ“ **Tip** - The `Microsoft.ApplicationInsights.WorkerService` adjusts logging behavior of the worker (_i.e_ your Function App) to no longer emit logs through the host application (_i.e_ the Functions Runtime host controlling your Function App). Once installed, logs are sent directly to application insights from the worker process instead. 7. Open the `Program.cs` and add some using directives at the top of the file: ```c# using Microsoft.Azure.Functions.Worker; + using Microsoft.Azure.Functions.Worker.Builder; + using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; ``` -8. Further down in `Program.cs`, uncomment the relevant portion of the code. +8. Further down in `Program.cs`, replace the commented code with the relevant portion of the code. *Replace* @@ -161,6 +186,15 @@ Logging to Application Insights using lower severity requires an explicit overri *With* ```c# + // Reading and configuring log levels and categories + + var hostJsonLoggingSection = new ConfigurationBuilder() + .AddJsonFile("host.json") + .Build() + .GetSection("logging"); + + builder.Logging.AddConfiguration(hostJsonLoggingSection); + // Logging to Application Insights builder.Services @@ -200,13 +234,11 @@ Once the dashboard displays, notice that your machine is listed as one of the se From the right pane, locate and click on one of the recorded logs, with the following message text: `"C# HTTP trigger function processed a request"`. -Details from the selected log are displayed on the lower right pane. In particular, notice the following two properties: +Details from the selected log are displayed on the lower right pane. In particular, notice the following property: -- `Category`: `Function.HelloWorldHttpTrigger.User` -- `LogLevel`: `Information` +- `CategoryName`: `AzFuncUni.Logging.HelloWorldHttpTrigger` -Along with their messages, those are amongst the most important properties from the collected logs. -In the next section, you will dive into those properties in a bit more details. +Along with their messages, the _Severity Level_ and log _Category_ are amongst the most important properties from the collected logs. In the next section, you will dive into those properties in a bit more details. 12. Hit Ctrl+C from the Console of the running application to stop its execution. @@ -219,7 +251,7 @@ You will also learn about _Log Categories_ and how to filter log output based up > πŸ“ **Tip** - App Insights is a comprehensive Application Performance Monitoring (APM) solution. As such, it does a lot more than collecting traces from a running application. In this lesson, you will mostly focus on interacting with App Insights using .NET's [Microsoft.Extensions.Logging.ILogger](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging) abstraction. -As you have seen on the previous section, each log is associated with a set of properties, two of which are its _Category_ and _Log Level_ properties. +As you have seen on the previous section, each log is associated with a set of properties, two of which are its _CategoryName_ and _Severity Level_ properties. #### Log levels @@ -248,6 +280,8 @@ The [ILogger](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions. Using `LogLevel.None` effectively disables log output. +> πŸ“ **Tip** - The .NET `ILogger` abstraction defines the various log levels listed above. However, in App Insights, this translates to the concept of _Severity Level_. There is a one-to-one correspondance between the .NET `LogLevel` and App Insights’ _Severity Levels_. + In the previous exercise, you have seen how setting the default log level for the entire application to `"Trace"` in the `host.json` file dramatically increased the amount of traces emitted when running the application. Changing the default level is a crude way to limit the quantity of logs. Later in this exercise, you will learn to configure log levels for particular _categories_ of logs. ### Categories @@ -285,8 +319,8 @@ In this exercise, you will discover log categories and learn how to filter log o ```sql traces - | summarize count(message) by tostring(customDimensions.Category) - | order by customDimensions_Category + | summarize count(message) by tostring(customDimensions.CategoryName) + | order by customDimensions_CategoryName ``` > πŸ“ **Tip** - App Insights uses a SQL-like query language named [Kusto Query Language](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/) (KQL). @@ -333,8 +367,8 @@ In this exercise, you will discover log categories and learn how to filter log o ```sql traces - | summarize count(message) by tostring(customDimensions.Category) - | order by customDimensions_Category + | summarize count(message) by tostring(customDimensions.CategoryName) + | order by customDimensions_CategoryName ``` > πŸ”Ž **Observation** - After a few minutes, you should see a dramatic reduction in the amount of categories under which your application logs. In fact, given enough time, only logs associated with the `AzFuncUni.Logging.HelloWorldHttpTrigger` category hierarchy should be emitted. @@ -364,6 +398,7 @@ In this exercise, you will discover log categories and learn how to filter log o … "AzureFunctionsJobHost__Logging__LogLevel__default": "Debug", "AzureFunctionsJobHost__Logging__LogLevel__Function__HelloWorldHttpTrigger": "Trace", + "Logging__LogLevel__Default": "Warning", "Logging__LogLevel__AzFuncUni__Logging__HelloWorldHttpTrigger": "Trace" } } diff --git a/lessons/dotnet8/logging/isolated-worker-process.png b/lessons/dotnet8/logging/isolated-worker-process.png new file mode 100644 index 0000000000000000000000000000000000000000..5da5c76ad181de9cf2ee21b7ee438627c720c167 GIT binary patch literal 30850 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 Date: Tue, 26 Nov 2024 17:33:08 +0100 Subject: [PATCH 08/12] [src] adjust code --- src/dotnet8/logging/AzFuncUni.Logging/Program.cs | 13 ++++++++++++- src/dotnet8/logging/AzFuncUni.Logging/host.json | 2 +- .../logging/AzFuncUni.Logging/local.settings.json | 1 - 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs index 91bc63e1..57b3788e 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs +++ b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs @@ -1,5 +1,6 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Builder; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -8,6 +9,15 @@ builder.ConfigureFunctionsWebApplication(); +// Reading and configuring log levels and categories + +var hostJsonLoggingSection = new ConfigurationBuilder() + .AddJsonFile("host.json") + .Build() + .GetSection("logging"); + +builder.Logging.AddConfiguration(hostJsonLoggingSection); + // Logging to Application Insights builder.Services @@ -24,6 +34,7 @@ { options.Rules.Remove(toRemove); } - }); + }) + ; builder.Build().Run(); diff --git a/src/dotnet8/logging/AzFuncUni.Logging/host.json b/src/dotnet8/logging/AzFuncUni.Logging/host.json index 714a4d40..7aba7482 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/host.json +++ b/src/dotnet8/logging/AzFuncUni.Logging/host.json @@ -3,7 +3,7 @@ "logging": { "applicationInsights": { "samplingSettings": { - "isEnabled": true, + "isEnabled": false, "excludedTypes": "Request" }, "enableLiveMetrics": true diff --git a/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json index 288198bf..e93b94d5 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json +++ b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json @@ -3,7 +3,6 @@ "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true;", "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", - "APPINSIGHTS_INSTRUMENTATIONKEY": "00000000000000000000000000000000", "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=00000000000000000000000000000000;IngestionEndpoint=https://francecentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://region.livediagnostics.monitor.azure.com/;ApplicationId=00000000000000000000000000000000" } } \ No newline at end of file From 9559aef9f91ec23c99d5d9d24eb3e4eb6a4e97e6 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Tue, 26 Nov 2024 17:45:01 +0100 Subject: [PATCH 09/12] [tour] adjust text and line numbers --- .../02-logging-to-application-insights.tour | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour index 61fccc2b..c1f2e18a 100644 --- a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour +++ b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour @@ -10,7 +10,7 @@ "title": "Connecting to Application Insights", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/local.settings.json", "description": "The `APPLICATIONINSIGHTS_CONNECTION_STRING` app setting selects the connection string used to connect to Azure Application Insights.\r\n\r\nYou can find the value for this setting by navigating to the Azure Portal, and locating the Application Insights resource under considration. There, notice `Essentials` section, at the top of the center pane.\r\nThat’s where you can find the `Instrumentation Key` and `Connection String` properties.", - "line": 7 + "line": 6 }, { "title": "Configuring the Functions Runtime host", @@ -21,7 +21,7 @@ { "title": "Configuring the log levels", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/host.json", - "description": "The Functions Runtime host receives requests for logging from your function app worker process using gRPC.\r\n\r\nThe `logging/loglevel` section from the `host.json` file allows you to filter logs based on their categories.", + "description": "The Functions Runtime host uses the `host.json` file to configure configure logging for its own activity, including the behaviour of your input bindings.\r\n\r\nIn this lesson, were are also sharing the `host.json` log configuration for the worker process itself. That’s where you define the log level associated with each category.", "line": 12 }, { @@ -40,24 +40,30 @@ "title": "Using statements", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "These _using_ statements at the top of the source file are required to enable logging to Application Insights.\r\n\r\nNote that most of those statements are generic-enough; that’s because most features are packaged using extension classes located in a limited number of well-known namespaces.", - "line": 5 + "line": 6 + }, + { + "title": "Reading and configuring log levels and categories", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", + "description": "Those instructions load the `logging` section from the `host.json` configuration file into a temporary variable.Then, passing this variable to `Logging.AddConfiguration()` configures log levels and categories accordingly.", + "line": 19 }, { "title": "Logging to Application Insights", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "Those instructions enable logging to ApplicationInsights.\r\n\r\nThe `AddApplicationInsightsTelemetryWorkerService` method enables connection to Application Insights from _worker_ processes such as non-HTTP workloads, background tasks and console applications and is not specific to Function Apps.\r\n\r\nThe `ConfigureFunctionsApplicationInsights` method is a simple method provided by the Azure Functions .NET Worker SDK to properly setup the Function App for logging to Application Insights.", - "line": 15 + "line": 25 }, { "title": "Remove logging constraints for debugging purposes", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "In order to help reduce cost of your cloud infrastructure, the Application Insights SDK adds a default logging filter that instructs `ILogger` to capture logs with a severity of `Warning` or more.\r\n\r\nIn this lesson, that rule is removed so that logging using lower levels, such as `Information` can be sent and recorded into Application Insights.", - "line": 27 + "line": 34 }, { "title": "Selecting a category for logging", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs", - "description": "Most of the work so far involved installing NuGet dependencies and configuring them appropriately upon startup of the worker process.\r\n\r\nIn the program, a developer can use the `ILogger` abstraction to focus on logging – what, and how – without worrying about specific details related to where those logs are sent.\r\n\r\nThe specific instance of that logger for the class is specified as a generic parameter to the `ILogger` interface. Here, this ties the logger to a _Category_ that is the fully qualified name of the class, _i.e_ `AzFuncUni.Logging.HelloWordHttpTrigger`.", + "description": "Most of the work so far involved installing NuGet dependencies and configuring them appropriately upon startup of the worker process.\r\n\r\nIn the program, a developer can use the `ILogger` abstraction to focus on logging – what, and how – without worrying about specific details related to where those logs are sent.\r\n\r\nThe specific instance of that logger for the class is specified as a generic parameter to the `ILogger` interface. Here, this ties the logger to a _CategoryName_ that is the fully qualified name of the class, _i.e_ `AzFuncUni.Logging.HelloWordHttpTrigger`.", "line": 10 }, { From 465cacfac57bb7a36965dc75f1c3130c241d0caa Mon Sep 17 00:00:00 2001 From: Springcomp Date: Wed, 27 Nov 2024 20:52:03 +0100 Subject: [PATCH 10/12] proof-proof reading again ! --- .../02-logging-to-application-insights.tour | 26 +++++--- lessons/dotnet8/logging/README.md | 63 ++++++++++++------ .../logging/isolated-worker-process.png | Bin 30850 -> 16897 bytes .../AzFuncUni.Logging.csproj | 3 + .../logging/AzFuncUni.Logging/Program.cs | 9 --- .../AzFuncUni.Logging/appsettings.json | 7 ++ .../logging/AzFuncUni.Logging/host.json | 3 +- 7 files changed, 68 insertions(+), 43 deletions(-) create mode 100644 src/dotnet8/logging/AzFuncUni.Logging/appsettings.json diff --git a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour index c1f2e18a..8b02bb7b 100644 --- a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour +++ b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour @@ -19,11 +19,23 @@ "line": 9 }, { - "title": "Configuring the log levels", + "title": "Configuring default logging levels for the Functions Runtime host", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/host.json", - "description": "The Functions Runtime host uses the `host.json` file to configure configure logging for its own activity, including the behaviour of your input bindings.\r\n\r\nIn this lesson, were are also sharing the `host.json` log configuration for the worker process itself. That’s where you define the log level associated with each category.", + "description": "The Functions Runtime host uses the `host.json` file to configure logging for its own activity, including the behaviour of your input bindings.", "line": 12 }, + { + "title": "Configuring default log levels for the Isolated Worker process", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/appsettings.json", + "description": "The Isolated Worker process uses is own – separate – `appsettings.json` configuration file to configure logging.\r\n\r\nThat’s where you define the log level associated with each category.", + "line": 4 + }, + { + "title": "Copying the `appsettings.json` to the output folder", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", + "description": "To register the `appsettings.json` as the source of configuration for the worker process, this file needs to be copied to the output folder alonside your compiled binaries for the worker process.", + "line": 21 + }, { "title": "Installing Application Insights dependencies", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", @@ -42,23 +54,17 @@ "description": "These _using_ statements at the top of the source file are required to enable logging to Application Insights.\r\n\r\nNote that most of those statements are generic-enough; that’s because most features are packaged using extension classes located in a limited number of well-known namespaces.", "line": 6 }, - { - "title": "Reading and configuring log levels and categories", - "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", - "description": "Those instructions load the `logging` section from the `host.json` configuration file into a temporary variable.Then, passing this variable to `Logging.AddConfiguration()` configures log levels and categories accordingly.", - "line": 19 - }, { "title": "Logging to Application Insights", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "Those instructions enable logging to ApplicationInsights.\r\n\r\nThe `AddApplicationInsightsTelemetryWorkerService` method enables connection to Application Insights from _worker_ processes such as non-HTTP workloads, background tasks and console applications and is not specific to Function Apps.\r\n\r\nThe `ConfigureFunctionsApplicationInsights` method is a simple method provided by the Azure Functions .NET Worker SDK to properly setup the Function App for logging to Application Insights.", - "line": 25 + "line": 17 }, { "title": "Remove logging constraints for debugging purposes", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "In order to help reduce cost of your cloud infrastructure, the Application Insights SDK adds a default logging filter that instructs `ILogger` to capture logs with a severity of `Warning` or more.\r\n\r\nIn this lesson, that rule is removed so that logging using lower levels, such as `Information` can be sent and recorded into Application Insights.", - "line": 34 + "line": 28 }, { "title": "Selecting a category for logging", diff --git a/lessons/dotnet8/logging/README.md b/lessons/dotnet8/logging/README.md index 4814a218..2910a2ab 100644 --- a/lessons/dotnet8/logging/README.md +++ b/lessons/dotnet8/logging/README.md @@ -99,9 +99,10 @@ file and relies entirely on environment variables and application settings in Az in this lesson, however, it is often desirable to use a separate file for the log configuration. As your isolated worker process runs – as its name suggests – in a separate process from the host, -it needs its own file to store its own settings and configurations for logging. In this lesson, the -program will load the log (a subset of) the configuration from the `host.json` file, -making it a shared file for both the host and the worker process itself. +it needs its own file to store its own settings and configurations for logging. By default, if +a file named `appsettings.json` is present in the output folder, it can automatically registered +as a source of configuration for the worker. Additionally, the log levels and categories +can be automatically configured from the `Logging/LogLevel` configuration section. In the following section, you will learn the basics of _Application Insights_ and its _Live Metrics_ dashboard. @@ -138,13 +139,40 @@ In the following section, you will learn the basics of _Application Insights_ an "enableLiveMetrics": true }, "logLevel": { - "default": "Trace" + "default": "Warning" } } } ``` -Our changes enable integration with the _Live Metrics_ dashboard associated with the _Application Insights_ resource that we will refer to from now on as β€œApp Insights”, for short. We also have lowered the default _Log Level_ to `Trace` so that virtually every log emitted from the application goes out unfiltered. +Our changes enable integration with the _Live Metrics_ dashboard associated with the _Application Insights_ resource that we will refer to from now on as β€œApp Insights”, for short. + +6. At the root of your project, create a new file named `appsettings.json` with the following content: + +```json +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + } + } +} +``` + +> πŸ“ **Tip** - Please, make sure to name the file `appsettings.json` exactly. + +7. Open the `AzFuncUni.Logging.csproj` project file, locate the `` XML start element +somewhat towards the end of the file and add the following – mostly identical section for `appsettings.json` like so: + +```xml + + PreserveNewest + +``` + +> πŸ“ **Tip** - Please, note that this section is very similar to the one that copies the `host.json` file to the output folder. + +The `appsettings.json` configuration file defines the default level for logging to `Trace` which allows virtually all logs emitted from your worker process to be sent to App Insights. However, logging to App Insights is not enabled by default. @@ -152,7 +180,7 @@ Furthermore, in an effort to help manage your infrastructure costs efficiently, Logging to Application Insights using lower severity requires an explicit override. -6. To fix this, install the [required packages](https://learn.microsoft.com/fr-fr/azure/azure-functions/dotnet-isolated-process-guide?tabs=hostbuilder%2Cwindows#install-packages) as follows: +8. To fix this, install the [required packages](https://learn.microsoft.com/fr-fr/azure/azure-functions/dotnet-isolated-process-guide?tabs=hostbuilder%2Cwindows#install-packages) as follows: ```pwsh dotnet add package Microsoft.ApplicationInsights.WorkerService @@ -161,7 +189,7 @@ Logging to Application Insights using lower severity requires an explicit overri > πŸ“ **Tip** - The `Microsoft.ApplicationInsights.WorkerService` adjusts logging behavior of the worker (_i.e_ your Function App) to no longer emit logs through the host application (_i.e_ the Functions Runtime host controlling your Function App). Once installed, logs are sent directly to application insights from the worker process instead. -7. Open the `Program.cs` and add some using directives at the top of the file: +9. Open the `Program.cs` and add some using directives at the top of the file: ```c# using Microsoft.Azure.Functions.Worker; @@ -172,7 +200,7 @@ Logging to Application Insights using lower severity requires an explicit overri using Microsoft.Extensions.Logging; ``` -8. Further down in `Program.cs`, replace the commented code with the relevant portion of the code. +10. Further down in `Program.cs`, replace the commented code with the relevant portion of the code. *Replace* @@ -186,15 +214,6 @@ Logging to Application Insights using lower severity requires an explicit overri *With* ```c# - // Reading and configuring log levels and categories - - var hostJsonLoggingSection = new ConfigurationBuilder() - .AddJsonFile("host.json") - .Build() - .GetSection("logging"); - - builder.Logging.AddConfiguration(hostJsonLoggingSection); - // Logging to Application Insights builder.Services @@ -214,17 +233,17 @@ Logging to Application Insights using lower severity requires an explicit overri }); ``` -9. Compile and run the application again. +11. Compile and run the application again. -10. From the Azure Portal, navigate to App Insights and display the _Live Metrics_ dashboard. You can find `Live Metrics` as one of the options available on the left pane, under the `Investigate` topic. +12. From the Azure Portal, navigate to App Insights and display the _Live Metrics_ dashboard. You can find `Live Metrics` as one of the options available on the left pane, under the `Investigate` topic. -Wait a couple dozen of seconds for the web page to refresh and display the dashboard. +Wait for ten to twenty seconds for the web page to refresh and display the dashboard. > πŸ“ **Tip** - Some ad blockers are known to prevent the dashboard from displaying. If you have ΞΌBlockβ‚€, you may see a `Data is temporarily inaccessible` red banner, for instance. Make sure to disable your ad blocker for the _Live Metrics_ page to display properly. Once the dashboard displays, notice that your machine is listed as one of the servers currently connected to App Insights. -11. On your local machine, call the HTTP-triggered function a couple of times. +13. On your local machine, call the HTTP-triggered function a couple of times. ```http POST http://localhost:7071/api/HelloWorldHttpTrigger @@ -240,7 +259,7 @@ Details from the selected log are displayed on the lower right pane. In particul Along with their messages, the _Severity Level_ and log _Category_ are amongst the most important properties from the collected logs. In the next section, you will dive into those properties in a bit more details. -12. Hit Ctrl+C from the Console of the running application to stop its execution. +14. Hit Ctrl+C from the Console of the running application to stop its execution. ## 3. Log levels and categories diff --git a/lessons/dotnet8/logging/isolated-worker-process.png b/lessons/dotnet8/logging/isolated-worker-process.png index 5da5c76ad181de9cf2ee21b7ee438627c720c167..f903080eed8a8dc297703829aa862903f9a5d746 100644 GIT binary patch literal 16897 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 + + PreserveNewest + PreserveNewest diff --git a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs index 57b3788e..de624c9e 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs +++ b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs @@ -9,15 +9,6 @@ builder.ConfigureFunctionsWebApplication(); -// Reading and configuring log levels and categories - -var hostJsonLoggingSection = new ConfigurationBuilder() - .AddJsonFile("host.json") - .Build() - .GetSection("logging"); - -builder.Logging.AddConfiguration(hostJsonLoggingSection); - // Logging to Application Insights builder.Services diff --git a/src/dotnet8/logging/AzFuncUni.Logging/appsettings.json b/src/dotnet8/logging/AzFuncUni.Logging/appsettings.json new file mode 100644 index 00000000..85482794 --- /dev/null +++ b/src/dotnet8/logging/AzFuncUni.Logging/appsettings.json @@ -0,0 +1,7 @@ +{ + "logging": { + "logLevel": { + "default": "Trace" + } + } +} \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/host.json b/src/dotnet8/logging/AzFuncUni.Logging/host.json index 7aba7482..3afcb572 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/host.json +++ b/src/dotnet8/logging/AzFuncUni.Logging/host.json @@ -9,8 +9,7 @@ "enableLiveMetrics": true }, "logLevel": { - "default": "Warning", - "AzFuncUni.Logging.HelloWorldHttpTrigger": "Information" + "default": "Warning" } } } \ No newline at end of file From a7130d14d9332fd8159046ff4e5a283acd180059 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Tue, 3 Dec 2024 14:53:54 +0000 Subject: [PATCH 11/12] [gh] Added GitHub workflow for .NET 8 samples. --- .github/workflows/dotnet8.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/dotnet8.yml diff --git a/.github/workflows/dotnet8.yml b/.github/workflows/dotnet8.yml new file mode 100644 index 00000000..ea61d065 --- /dev/null +++ b/.github/workflows/dotnet8.yml @@ -0,0 +1,28 @@ +name: '.NET 8 builds' +on: + pull_request: + types: [opened, edited, synchronize, reopened] + paths: + - 'src/dotnet8/**' + - '.github/workflows/dotnet8.yml' + workflow_dispatch: + +env: + DOTNET_VERSION: '8.0.x' + +jobs: + Application: + runs-on: ubuntu-latest + steps: + - name: 'Checkout GitHub Action' + uses: actions/checkout@v4 + - name: Setup .NET ${{ env.DOTNET_VERSION }} Environment + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: 'Build Logging Function' + shell: bash + run: | + pushd './src/dotnet8/logging/AzFuncUni.Logging' + dotnet build --configuration Release --output ./output + popd \ No newline at end of file From 1f74ef551403eb150f4d390216eb83d6ccc8cce3 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Wed, 4 Dec 2024 09:17:27 +0000 Subject: [PATCH 12/12] refactored to work both on Linux and Windows app service plans. --- .../02-logging-to-application-insights.tour | 34 ++++++----- lessons/dotnet8/logging/README.md | 57 ++++++++++++++----- .../HelloWorldHttpTrigger.cs | 14 ++--- .../logging/AzFuncUni.Logging/Program.cs | 15 +++++ .../logging/AzFuncUni.Logging/host.json | 4 +- .../AzFuncUni.Logging/local-tests.http | 2 +- .../AzFuncUni.Logging/local.settings.json | 2 +- 7 files changed, 90 insertions(+), 38 deletions(-) diff --git a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour index 8b02bb7b..a46633a9 100644 --- a/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour +++ b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour @@ -21,8 +21,8 @@ { "title": "Configuring default logging levels for the Functions Runtime host", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/host.json", - "description": "The Functions Runtime host uses the `host.json` file to configure logging for its own activity, including the behaviour of your input bindings.", - "line": 12 + "description": "The Functions Runtime host uses the `host.json` file to configure logging for its own activity, including the behaviour of your input bindings.\r\n\r\nTo minimize the noise, it is recommended to set the default log level to `Warning`. However, it is important to keep `Function` and `Host.Results` logs to `Information` to enable monitoring the function execution on the **Application Insights** and **Functions Monitor** tabs when hosted on Azure.", + "line": 14 }, { "title": "Configuring default log levels for the Isolated Worker process", @@ -30,12 +30,6 @@ "description": "The Isolated Worker process uses is own – separate – `appsettings.json` configuration file to configure logging.\r\n\r\nThat’s where you define the log level associated with each category.", "line": 4 }, - { - "title": "Copying the `appsettings.json` to the output folder", - "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", - "description": "To register the `appsettings.json` as the source of configuration for the worker process, this file needs to be copied to the output folder alonside your compiled binaries for the worker process.", - "line": 21 - }, { "title": "Installing Application Insights dependencies", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", @@ -48,35 +42,47 @@ "description": "The `Microsoft.Azure.Functions.Worker.ApplicationInsights` package is required to enable logging to Application Insights from your Function App worker process.", "line": 13 }, + { + "title": "Copying the `appsettings.json` to the output folder", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj", + "description": "To register the `appsettings.json` as the source of configuration for the worker process, this file needs to be copied to the output folder alonside your compiled binaries for the worker process.", + "line": 21 + }, { "title": "Using statements", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "These _using_ statements at the top of the source file are required to enable logging to Application Insights.\r\n\r\nNote that most of those statements are generic-enough; that’s because most features are packaged using extension classes located in a limited number of well-known namespaces.", - "line": 6 + "line": 7 + }, + { + "title": "Configure log levels and categories", + "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", + "description": "For maximum flexibility, you can register the `appsettings.json` file as a source for configuration. There you will setup sensible defaults for your log levels and categories.\r\n\r\nThe `AddEnvironmentVariables()` method also registers environment variables as a source for configuration. Overriding log levels for specific categories helps troubleshoot an application at runtime.", + "line": 25 }, { "title": "Logging to Application Insights", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "Those instructions enable logging to ApplicationInsights.\r\n\r\nThe `AddApplicationInsightsTelemetryWorkerService` method enables connection to Application Insights from _worker_ processes such as non-HTTP workloads, background tasks and console applications and is not specific to Function Apps.\r\n\r\nThe `ConfigureFunctionsApplicationInsights` method is a simple method provided by the Azure Functions .NET Worker SDK to properly setup the Function App for logging to Application Insights.", - "line": 17 + "line": 31 }, { "title": "Remove logging constraints for debugging purposes", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/Program.cs", "description": "In order to help reduce cost of your cloud infrastructure, the Application Insights SDK adds a default logging filter that instructs `ILogger` to capture logs with a severity of `Warning` or more.\r\n\r\nIn this lesson, that rule is removed so that logging using lower levels, such as `Information` can be sent and recorded into Application Insights.", - "line": 28 + "line": 43 }, { "title": "Selecting a category for logging", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs", - "description": "Most of the work so far involved installing NuGet dependencies and configuring them appropriately upon startup of the worker process.\r\n\r\nIn the program, a developer can use the `ILogger` abstraction to focus on logging – what, and how – without worrying about specific details related to where those logs are sent.\r\n\r\nThe specific instance of that logger for the class is specified as a generic parameter to the `ILogger` interface. Here, this ties the logger to a _CategoryName_ that is the fully qualified name of the class, _i.e_ `AzFuncUni.Logging.HelloWordHttpTrigger`.", - "line": 10 + "description": "Most of the work so far involved installing NuGet dependencies and configuring them appropriately upon startup of the worker process.\r\n\r\nIn the program, a developer can use the `ILogger` abstraction to focus on logging – what, and how – without worrying about specific details related to where those logs are sent.\r\n\r\nInstances of `ILogger` [can be obtained](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=hostbuilder%2Cwindows#logging) from the constructor of the class using dependency injection, or from each function’s `FunctionContext` parameter.\r\n\r\nHere, an instance is obtained from the `FunctionContext` parameter and lets us select the log category to the name of the class, _i.e_ `\"HelloWorldHttpTrigger\"`.\r\n\r\nLog categories can be any arbitrary string. However, use caution when using category names that contain a `.` (period) character, as this is not supported when running on Linux App Service plans.", + "line": 16 }, { "title": "Selecting a log level for logging", "file": "../../../src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs", "description": "Using builtin helper methods from `ILogger` – like `LogInformation` or `LogError` – a developer can select the appropriate log level for logging.", - "line": 20 + "line": 18 } ] } \ No newline at end of file diff --git a/lessons/dotnet8/logging/README.md b/lessons/dotnet8/logging/README.md index 2910a2ab..46974d8a 100644 --- a/lessons/dotnet8/logging/README.md +++ b/lessons/dotnet8/logging/README.md @@ -139,13 +139,16 @@ In the following section, you will learn the basics of _Application Insights_ an "enableLiveMetrics": true }, "logLevel": { - "default": "Warning" + "default": "Warning", + "Function": "Information", + "Host.Results": "Information" } } } ``` Our changes enable integration with the _Live Metrics_ dashboard associated with the _Application Insights_ resource that we will refer to from now on as β€œApp Insights”, for short. +It also enables [monitoring the function execution](https://learn.microsoft.com/en-us/azure/azure-functions/configure-monitoring?tabs=v2#configure-log-levels) when hosted on Azure through the **Application Insights** and **Funcion Monitors** tabs. 6. At the root of your project, create a new file named `appsettings.json` with the following content: @@ -161,8 +164,7 @@ Our changes enable integration with the _Live Metrics_ dashboard associated with > πŸ“ **Tip** - Please, make sure to name the file `appsettings.json` exactly. -7. Open the `AzFuncUni.Logging.csproj` project file, locate the `` XML start element -somewhat towards the end of the file and add the following – mostly identical section for `appsettings.json` like so: +7. Open the `AzFuncUni.Logging.csproj` project file, locate the `` XML start element somewhat towards the end of the file, and add the following – mostly identical section for `appsettings.json` like so: ```xml @@ -192,6 +194,7 @@ Logging to Application Insights using lower severity requires an explicit overri 9. Open the `Program.cs` and add some using directives at the top of the file: ```c# + using System.Reflection; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Builder; using Microsoft.Extensions.Configuration; @@ -200,7 +203,27 @@ Logging to Application Insights using lower severity requires an explicit overri using Microsoft.Extensions.Logging; ``` -10. Further down in `Program.cs`, replace the commented code with the relevant portion of the code. +10. In `Program.cs` load the configuration file and configure log levels and categories. + + Add the following code immediately after the call to + `builder.ConfigureFunctionsWebApplication()`. + + ```c# + // Register log levels and categories + + var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + var appSettingsLoggingSection = new ConfigurationBuilder() + .SetBasePath(basePath!) // required on Linux + .AddJsonFile("appsettings.json") // first read configuration file + .AddEnvironmentVariables() // then override using app settings + .Build() + .GetSection("Logging") + ; + + ``` + +11. Further down in `Program.cs`, enabled logging to App Insights by replacing the commented code with the relevant portion of the code. *Replace* @@ -233,9 +256,17 @@ Logging to Application Insights using lower severity requires an explicit overri }); ``` -11. Compile and run the application again. +12. Open the `HelloWorldHttpTrigger.cs` file and update its contents. + + Replace the full contents of the file with the following code: + + ```c# + + ``` + +13. Compile and run the application again. -12. From the Azure Portal, navigate to App Insights and display the _Live Metrics_ dashboard. You can find `Live Metrics` as one of the options available on the left pane, under the `Investigate` topic. +14. From the Azure Portal, navigate to App Insights and display the _Live Metrics_ dashboard. You can find `Live Metrics` as one of the options available on the left pane, under the `Investigate` topic. Wait for ten to twenty seconds for the web page to refresh and display the dashboard. @@ -243,7 +274,7 @@ Wait for ten to twenty seconds for the web page to refresh and display the dashb Once the dashboard displays, notice that your machine is listed as one of the servers currently connected to App Insights. -13. On your local machine, call the HTTP-triggered function a couple of times. +15. On your local machine, call the HTTP-triggered function a couple of times. ```http POST http://localhost:7071/api/HelloWorldHttpTrigger @@ -255,11 +286,11 @@ From the right pane, locate and click on one of the recorded logs, with the foll Details from the selected log are displayed on the lower right pane. In particular, notice the following property: -- `CategoryName`: `AzFuncUni.Logging.HelloWorldHttpTrigger` +- `CategoryName`: `HelloWorldHttpTrigger` Along with their messages, the _Severity Level_ and log _Category_ are amongst the most important properties from the collected logs. In the next section, you will dive into those properties in a bit more details. -14. Hit Ctrl+C from the Console of the running application to stop its execution. +16. Hit Ctrl+C from the Console of the running application to stop its execution. ## 3. Log levels and categories @@ -317,7 +348,7 @@ Before running the code from your functions, the Functions Runtime first runs th For this reason each function decorated using the [`FunctionAttribute`](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=hostbuilder%2Cwindows#methods-recognized-as-functions) class emits logs associated with the following category hierarchy: - `Functions.`: category associated with logs from triggers and bindings used by your function. -- `` category associated with logs from your code using the `ILogger` instance initialized in the constructor of your function class. +- `` category associated with logs from your code using the `ILogger` instance obtained from your function method’s `FunctionContext` parameter. In this exercise, you will discover log categories and learn how to filter log output based upon categories using appropriate log levels. @@ -371,7 +402,7 @@ In this exercise, you will discover log categories and learn how to filter log o "logLevel": { "default": "Warning", "Functions.HelloWorldHttpTrigger": "Warning", - "AzFuncUni.Logging.HelloWorldHttpTrigger": "Information" + "HelloWorldHttpTrigger": "Information" } ``` @@ -390,7 +421,7 @@ In this exercise, you will discover log categories and learn how to filter log o | order by customDimensions_CategoryName ``` - > πŸ”Ž **Observation** - After a few minutes, you should see a dramatic reduction in the amount of categories under which your application logs. In fact, given enough time, only logs associated with the `AzFuncUni.Logging.HelloWorldHttpTrigger` category hierarchy should be emitted. + > πŸ”Ž **Observation** - After a few minutes, you should see a dramatic reduction in the amount of categories under which your application logs. In fact, given enough time, only logs associated with the `HelloWorldHttpTrigger` category should be emitted. 10. Hit Ctrl+C from the Console of the running application to stop its execution. @@ -418,7 +449,7 @@ In this exercise, you will discover log categories and learn how to filter log o "AzureFunctionsJobHost__Logging__LogLevel__default": "Debug", "AzureFunctionsJobHost__Logging__LogLevel__Function__HelloWorldHttpTrigger": "Trace", "Logging__LogLevel__Default": "Warning", - "Logging__LogLevel__AzFuncUni__Logging__HelloWorldHttpTrigger": "Trace" + "Logging__LogLevel__HelloWorldHttpTrigger": "Trace" } } ``` diff --git a/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs b/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs index bb8fced6..1501f7bc 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs +++ b/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs @@ -7,16 +7,14 @@ namespace AzFuncUni.Logging { public class HelloWorldHttpTrigger { - private readonly ILogger _logger; - - public HelloWorldHttpTrigger(ILogger logger) - { - _logger = logger; - } - [Function("HelloWorldHttpTrigger")] - public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + public IActionResult Run( + [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req, + FunctionContext context + ) { + ILogger _logger = context.GetLogger(nameof(HelloWorldHttpTrigger)); + _logger.LogInformation("C# HTTP trigger function processed a request."); return new OkObjectResult("Welcome to Azure Functions!"); } diff --git a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs index de624c9e..f9af832b 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/Program.cs +++ b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs @@ -1,3 +1,4 @@ +using System.Reflection; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Builder; using Microsoft.Extensions.Configuration; @@ -9,6 +10,20 @@ builder.ConfigureFunctionsWebApplication(); +// Register log levels and categories + +var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + +var appSettingsLoggingSection = new ConfigurationBuilder() + .SetBasePath(basePath!) // required on Linux + .AddJsonFile("appsettings.json") // first read configuration file + .AddEnvironmentVariables() // then override using app settings + .Build() + .GetSection("Logging") + ; + +builder.Configuration.AddConfiguration(appSettingsLoggingSection); + // Logging to Application Insights builder.Services diff --git a/src/dotnet8/logging/AzFuncUni.Logging/host.json b/src/dotnet8/logging/AzFuncUni.Logging/host.json index 3afcb572..03bbd15c 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/host.json +++ b/src/dotnet8/logging/AzFuncUni.Logging/host.json @@ -9,7 +9,9 @@ "enableLiveMetrics": true }, "logLevel": { - "default": "Warning" + "default": "Warning", + "Host.Results": "Information", + "Function": "Information" } } } \ No newline at end of file diff --git a/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http b/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http index 98d8a27f..d1fd8f9f 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http +++ b/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http @@ -1 +1 @@ -GET http://localhost:7071/api/HelloWorldHttpTrigger \ No newline at end of file +GET http://localhost:7071/api/HelloWorldHttpTrigger diff --git a/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json index e93b94d5..fbd2d914 100644 --- a/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json +++ b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json @@ -4,5 +4,5 @@ "AzureWebJobsStorage": "UseDevelopmentStorage=true;", "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=00000000000000000000000000000000;IngestionEndpoint=https://francecentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://region.livediagnostics.monitor.azure.com/;ApplicationId=00000000000000000000000000000000" - } + } } \ No newline at end of file