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
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..a46633a9
--- /dev/null
+++ b/.tours/dotnet8/logging/.tours/02-logging-to-application-insights.tour
@@ -0,0 +1,88 @@
+{
+ "$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": 6
+ },
+ {
+ "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 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.\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",
+ "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": "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": "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": 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": 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": 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\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": 18
+ }
+ ]
+}
\ No newline at end of file
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
diff --git a/lessons/dotnet8/logging/README.md b/lessons/dotnet8/logging/README.md
new file mode 100644
index 00000000..46974d8a
--- /dev/null
+++ b/lessons/dotnet8/logging/README.md
@@ -0,0 +1,484 @@
+# 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/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.
+
+---
+
+## 0. Prerequisites
+
+| Prerequisite | Exercise
+| - | -
+| 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.
+
+## 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, amongst other things, collects telemetry from a running application. Logs − or traces − are one of many signals of telemetry that _Application Insights_ collects.
+
+### 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.
+
+
+
+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. 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.
+
+### 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 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:
+
+```json
+{
+ "Values": {
+ …
+ "APPLICATIONINSIGHTS_CONNECTION_STRING": ""
+ }
+}
+```
+
+5. Open the `host.json` file and replace its content with:
+
+```json
+{
+ "version": "2.0",
+ "logging": {
+ "applicationInsights": {
+ "samplingSettings": {
+ "isEnabled": false,
+ "excludedTypes": "Request"
+ },
+ "enableLiveMetrics": true
+ },
+ "logLevel": {
+ "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:
+
+```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.
+
+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.
+
+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
+ 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.
+
+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;
+ using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.Extensions.Hosting;
+ using Microsoft.Extensions.Logging;
+ ```
+
+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*
+
+ ```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);
+ }
+ });
+ ```
+
+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.
+
+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.
+
+> 📝 **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.
+
+15. 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 property:
+
+- `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.
+
+16. 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 _CategoryName_ and _Severity 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.
+
+
+
+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.
+
+> 📝 **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
+
+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 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.
+
+### 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.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).
+
+ > 🔎 **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",
+ "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.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 `HelloWorldHttpTrigger` category 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__Default": "Warning",
+ "Logging__LogLevel__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/isolated-worker-process.png b/lessons/dotnet8/logging/isolated-worker-process.png
new file mode 100644
index 00000000..f903080e
Binary files /dev/null and b/lessons/dotnet8/logging/isolated-worker-process.png differ
diff --git a/lessons/dotnet8/logging/log_levels.png b/lessons/dotnet8/logging/log_levels.png
new file mode 100644
index 00000000..115aa8ba
Binary files /dev/null and b/lessons/dotnet8/logging/log_levels.png differ
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)
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..29f88036
--- /dev/null
+++ b/src/dotnet8/logging/AzFuncUni.Logging/AzFuncUni.Logging.csproj
@@ -0,0 +1,33 @@
+
+
+ net8.0
+ v4
+ Exe
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ 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..1501f7bc
--- /dev/null
+++ b/src/dotnet8/logging/AzFuncUni.Logging/HelloWorldHttpTrigger.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Extensions.Logging;
+
+namespace AzFuncUni.Logging
+{
+ public class HelloWorldHttpTrigger
+ {
+ [Function("HelloWorldHttpTrigger")]
+ 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
new file mode 100644
index 00000000..f9af832b
--- /dev/null
+++ b/src/dotnet8/logging/AzFuncUni.Logging/Program.cs
@@ -0,0 +1,46 @@
+using System.Reflection;
+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;
+
+var builder = FunctionsApplication.CreateBuilder(args);
+
+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
+ .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/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
new file mode 100644
index 00000000..03bbd15c
--- /dev/null
+++ b/src/dotnet8/logging/AzFuncUni.Logging/host.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0",
+ "logging": {
+ "applicationInsights": {
+ "samplingSettings": {
+ "isEnabled": false,
+ "excludedTypes": "Request"
+ },
+ "enableLiveMetrics": true
+ },
+ "logLevel": {
+ "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
new file mode 100644
index 00000000..d1fd8f9f
--- /dev/null
+++ b/src/dotnet8/logging/AzFuncUni.Logging/local-tests.http
@@ -0,0 +1 @@
+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
new file mode 100644
index 00000000..fbd2d914
--- /dev/null
+++ b/src/dotnet8/logging/AzFuncUni.Logging/local.settings.json
@@ -0,0 +1,8 @@
+{
+ "IsEncrypted": false,
+ "Values": {
+ "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
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"
+ ]
+ }
+}