diff --git a/config/_default/menus/main.en.yaml b/config/_default/menus/main.en.yaml index 93dad896719..060e9ba5050 100644 --- a/config/_default/menus/main.en.yaml +++ b/config/_default/menus/main.en.yaml @@ -3692,6 +3692,11 @@ menu: parent: serverless_azure identifier: serverless_azure_functions weight: 6 + - name: .NET APM Extension + url: serverless/azure_functions/dotnet_extension + parent: serverless_azure_functions + identifier: serverless_azure_functions_dotnet_extension + weight: 601 - name: Azure Logic Apps url: serverless/logic_apps parent: serverless_azure diff --git a/content/en/serverless/azure_app_service/_index.md b/content/en/serverless/azure_app_service/_index.md index 7a4d3db1c5e..b32ba8666f9 100644 --- a/content/en/serverless/azure_app_service/_index.md +++ b/content/en/serverless/azure_app_service/_index.md @@ -35,7 +35,7 @@ In Datadog, use the [Serverless > Azure][4] page to troubleshoot all your Azure ### Azure metrics and logs -Install the [Azure integration][2] for [enriched metrics][3] and resource metadata for Azure App Service. +Install the [Azure integration][2] for [enriched metrics][3] and resource metadata for Azure App Service. Set up [Azure log forwarding][6] to automatically collect and send Azure App Service resource and application logs to Datadog. @@ -70,4 +70,3 @@ Capabilities: [8]: /serverless/azure_app_service/linux_container [9]: /serverless/azure_app_service/windows_code [10]: /extend/dogstatsd/ - diff --git a/content/en/serverless/azure_app_service/windows_code.md b/content/en/serverless/azure_app_service/windows_code.md index f1d62e3c5de..80ffc13c46e 100644 --- a/content/en/serverless/azure_app_service/windows_code.md +++ b/content/en/serverless/azure_app_service/windows_code.md @@ -16,6 +16,9 @@ further_reading: - link: "https://www.datadoghq.com/blog/deploy-dotnet-core-azure-app-service/" tag: "Blog" text: "Deploy ASP.NET Core applications to Azure App Service" +- link: "/serverless/azure_functions/dotnet_extension/" + tag: "Documentation" + text: "Azure Functions .NET APM Extension" --- @@ -33,10 +36,10 @@ The Datadog extension for Azure App Service provides monitoring capabilities in The extension supports the following: -For all other Azure Functions configurations, you must use the Serverless Compatibility Layer. +For any non-.NET Azure Functions or .NET configurations on a non-Dedicated/Premium plan, you must use the Serverless Compatibility Layer. Interested in support for other App Service resource types or runtimes? Sign up to be notified when a Preview becomes available. @@ -192,6 +195,7 @@ The [Datadog Windows Web App module][2] only deploys the Web App resource and ex Update your existing Web App to include the necessary Datadog App Settings and extension, as follows: ```bicep +// Version: 1.0.0 @secure() param datadogApiKey string @@ -243,6 +247,7 @@ Update your existing Web App to include the necessary Datadog App Settings and s { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", + "metadata": { "version": "1.0.0" }, "parameters": { "webAppName": { "type": "string" @@ -432,6 +437,7 @@ Run `terraform apply`, and follow any prompts. Update your template to target a deployment slot instead of the main web app: ```bicep +// Version: 1.0.0 @secure() param datadogApiKey string @@ -489,6 +495,7 @@ Update your template to target a deployment slot instead of the main web app: { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", + "metadata": { "version": "1.0.0" }, "parameters": { "webAppName": { "type": "string" @@ -548,6 +555,8 @@ az deployment group create --resource-group --template-file Using Azure Functions? See Azure Functions .NET APM Extension for Function App-specific installation instructions, including guidance on avoiding file-lock failures during extension install. + ## Custom metrics The Azure App Service extension includes an instance of [DogStatsD][1], Datadog's metrics aggregation service. This enables you to submit custom metrics, service checks, and events directly to Datadog from Azure Web Apps and Functions with the extension. @@ -559,27 +568,7 @@ To submit custom metrics to Datadog from Azure App Service using the extension: {{< tabs >}} {{% tab ".NET" %}} -1. Add the [DogStatsD NuGet package](https://www.nuget.org/packages/DogStatsD-CSharp-Client) to your Visual Studio project. -2. Initialize DogStatsD and write custom metrics in your application. -3. Deploy your code to Azure App Service. -4. If you have not already, install the Datadog App Service extension. - -To send metrics, use this code: - -```csharp -// Configure your DogStatsd client and configure any tags -if (!DogStatsd.Configure(new StatsdConfig() { ConstantTags = new[] { "app:sample.mvc.aspnetcore" } })) -{ - // `Configure` returns false if the necessary environment variables are not present. - // These environment variables are present in Azure App Service, but - // need to be set in order to test your custom metrics: DD_API_KEY:{api_key}, DD_AGENT_HOST:localhost - // Ignore or log the error as it suits you - Console.WriteLine("Cannot initialize DogstatsD."); -} - -// Send a metric -DogStatsd.Increment("sample.startup"); -``` +{{% aas-custom-metrics-dotnet %}} {{% /tab %}} {{% tab "Java" %}} @@ -639,15 +628,7 @@ Learn more about [custom metrics][2]. {{< tabs >}} {{% tab ".NET" %}} -You can send logs from your application in Azure App Service to Datadog in one of the following ways: - -- Use the [installation steps](#installation) on this page to enable APM with the Datadog APM extension. Then [enable Agentless logging][1]. -- Use [Agentless logging with the Serilog sink][2]. - -Both methods allow trace ID injection, making it possible to connect logs and traces in Datadog. To enable trace ID injection with the extension, add the application setting `DD_LOGS_INJECTION:true`. - -[1]: /logs/log_collection/csharp/#agentless-logging-with-apm -[2]: /logs/log_collection/csharp/#agentless-logging-with-serilog-sink +{{% aas-logging-dotnet %}} {{% /tab %}} {{% tab "Java" %}} @@ -685,83 +666,7 @@ Configure these environment variables in your Azure App Service Application Sett {{< tabs >}} {{% tab ".NET" %}} -**Code Example: Microsoft Native Logging** - -An example of how to set up logging in a .NET application using Microsoft.Extensions.Logging: - -```csharp -using Microsoft.Extensions.Logging; - -public class WeatherForecastController : ControllerBase -{ - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet] - public IActionResult Get() - { - _logger.LogInformation("Processing weather forecast request"); - - // Your business logic here - var forecast = GetWeatherForecast(); - - _logger.LogInformation("Weather forecast retrieved for user: {UserId}", userId); - - return Ok(forecast); - } -} -``` - -**Program.cs configuration** - -```csharp -using Microsoft.Extensions.Logging; - -var builder = WebApplication.CreateBuilder(args); - -// Configure logging -builder.Logging.ClearProviders(); -builder.Logging.AddConsole(); -builder.Logging.AddDebug(); - -// Add structured logging with JSON format -builder.Logging.AddJsonConsole(options => -{ - options.JsonWriterOptions = new JsonWriterOptions - { - Indented = true - }; -}); - -var app = builder.Build(); -// ... rest of your application configuration -``` - -**appsettings.json configuration** - -```json -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - }, - "Console": { - "FormatterName": "json", - "FormatterOptions": { - "IncludeScopes": true, - "TimestampFormat": "yyyy-MM-dd HH:mm:ss " - } - } - } -} -``` - -This setup automatically includes trace correlation when `DD_LOGS_INJECTION=true` is set in your Azure App Service Application Settings. +{{% aas-logging-dotnet-code-example %}} {{% /tab %}} {{% tab "Java" %}} @@ -805,7 +710,7 @@ The install script adds the latest version of the extension to an Azure Web App 3. Run the following command, passing in required and optional arguments as needed. ``` - .\install-latest-extension.ps1 -Username -Password -SubscriptionId -ResourceGroup -SiteName -DDApiKey -DDSite -DDEnv -DDService -DDVersion + .\install-latest-extension.ps1 -Username -Password -SubscriptionId -ResourceGroup -SiteName -DDApiKey -DDSite -DDEnv -DDService -DDVersion [-SlotName ] ``` **Note**: The following arguments are required for the above command: @@ -819,6 +724,8 @@ The install script adds the latest version of the extension to an Azure Web App Also, set `DATADOG_SITE` to your [Datadog site][32]. `DATADOG_SITE` defaults to `datadoghq.com`. Your site is: {{< region-param key="dd_site" code="true" >}}. +To target a deployment slot instead of the main app, add `-SlotName `. On Azure Function Apps, this also automatically applies the `WEBSITE_PRIVATE_EXTENSIONS=0` sticky slot setting to prevent extension install failures. See [Azure Functions .NET APM Extension](/serverless/azure_functions/dotnet_extension/) for details. + [32]: /getting_started/site/ ### Updating the extension for a resource group {#powershell-resource-group} @@ -864,7 +771,7 @@ Replace `` with the version of the extension you wish to inst ### ARM template -Many organizations use [Azure Resource Management (ARM) templates](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview) to implement the practice of infrastructure-as-code. To build the App Service Extension into these templates, incorporate [Datadog's App Service Extension ARM template](https://github.com/DataDog/datadog-aas-extension/tree/master/ARM) into your deployments to add the extension and configure it alongside your App Service resources. +Many organizations use [Azure Resource Management (ARM) templates](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview) to implement the practice of infrastructure-as-code. To build the App Service Extension into these templates, incorporate [Datadog's App Service Extension install templates](https://github.com/DataDog/datadog-aas-extension/tree/master/install-templates) into your deployments to add the extension and configure it alongside your App Service resources. {{% /tab %}} {{% tab "Java" %}} diff --git a/content/en/serverless/azure_functions/_index.md b/content/en/serverless/azure_functions/_index.md index 6813d07cbea..07f6277c632 100644 --- a/content/en/serverless/azure_functions/_index.md +++ b/content/en/serverless/azure_functions/_index.md @@ -237,5 +237,5 @@ You can collect [debug logs][6] for troubleshooting. To configure debug logs, us [6]: /tracing/troubleshooting/tracer_debug_logs/#enable-debug-mode [7]: /getting_started/tagging/unified_service_tagging/ [8]: https://learn.microsoft.com/en-us/azure/azure-functions/flex-consumption-plan -[9]: /serverless/azure_app_service/windows_code/?tab=net +[9]: /serverless/azure_functions/dotnet_extension/ [10]: /profiler/ diff --git a/content/en/serverless/azure_functions/dotnet_extension.md b/content/en/serverless/azure_functions/dotnet_extension.md new file mode 100644 index 00000000000..4da5a338f47 --- /dev/null +++ b/content/en/serverless/azure_functions/dotnet_extension.md @@ -0,0 +1,414 @@ +--- +title: Azure Functions .NET APM Extension +--- + +## Overview + +The Datadog .NET APM Extension provides full APM tracing for .NET Azure Functions running on Windows with a Dedicated (App Service) or Premium plan. + +**Requirements:** +- .NET runtime +- Windows OS +- Dedicated (App Service) or Premium hosting plan +- A deployment slot (strongly recommended — required for reliable installs and upgrades) + +For all other Azure Functions configurations (different runtime, OS, or hosting plan), use the [Serverless Compatibility Layer][1]. + +If you haven't already, set up the [Datadog-Azure integration][2] first. + +## Installation + +
Both initial install and upgrades require the app to be fully stopped. If you are using a deployment slot, install on the slot, then swap to production. WEBSITE_PRIVATE_EXTENSIONS=0 is required on the slot to prevent MoveDirectory failures, but it also prevents the runtime from loading private extensions. The extension will become active after you swap the slot to production. Do not set WEBSITE_PRIVATE_EXTENSIONS=0 on production.
+ +{{< tabs >}} +{{% tab "Bicep" %}} + +Use the [Function App slot Bicep template](https://github.com/DataDog/datadog-aas-extension/tree/master/install-templates/install-function-app-slot.bicep): + +```bicep +// Version: 1.0.0 +// Description: Install Datadog APM extension on an Azure Function App deployment slot. + +@secure() +param datadogApiKey string + +param webAppName string +param slotName string + +@description('Names of app settings already marked slot-sticky on this Function App. Pass [] for a new app with no existing sticky settings. This template does a full replace of slotConfigNames — omitting an existing sticky setting name will de-sticky it.') +param existingStickyAppSettingNames array +param ddSite string = 'datadoghq.com' +param ddService string = '' +@description('Environment tag — set a distinct value for each slot') +param ddEnv string = 'staging' +param ddVersion string = '' + +resource webApp 'Microsoft.Web/sites@2025-03-01' existing = { + name: webAppName +} + +// WEBSITE_PRIVATE_EXTENSIONS=0 prevents the Functions runtime from holding file locks +// on C:\home\SiteExtensions\ so Kudu can complete the MoveDirectory step during install. +// Include all your existing slot app settings in this resource — ARM replaces the full set. +resource slot 'Microsoft.Web/sites/slots@2025-03-01' = { + parent: webApp + name: slotName + properties: { + siteConfig: { + appSettings: [ + // Add your existing slot app settings here (e.g. AzureWebJobsStorage, FUNCTIONS_WORKER_RUNTIME) + { name: 'WEBSITE_PRIVATE_EXTENSIONS', value: '0' } + { name: 'DD_API_KEY', value: datadogApiKey } + { name: 'DD_SITE', value: ddSite } + { name: 'DD_SERVICE', value: ddService } + { name: 'DD_ENV', value: ddEnv } + { name: 'DD_VERSION', value: ddVersion } + ] + } + } +} + +// Marks WEBSITE_PRIVATE_EXTENSIONS as slot-sticky. Replaces the full slotConfigNames list — +// existingStickyAppSettingNames must include any settings already marked sticky or they will be de-stickied. +resource stickySettings 'Microsoft.Web/sites/config@2025-03-01' = { + name: 'slotConfigNames' + parent: webApp + properties: { + appSettingNames: union(existingStickyAppSettingNames, ['WEBSITE_PRIVATE_EXTENSIONS']) + } + dependsOn: [slot] +} + +// Only .NET is supported for Azure Function Apps. +resource datadogExtension 'Microsoft.Web/sites/slots/siteextensions@2025-03-01' = { + parent: slot + name: 'Datadog.AzureAppServices.DotNet' + dependsOn: [stickySettings] +} +``` + +Deploy: + +```shell +az deployment group create --resource-group --template-file install-function-app-slot.bicep +``` + +**Note:** The `slotConfigNames` resource does a full replace of the sticky-settings list, so you need to include all existing slot app settings in the `appSettings` array. Pass your existing slot-sticky setting names in `existingStickyAppSettingNames` or pass `[]` for a new app. Any name omitted from `existingStickyAppSettingNames` will be de-stickied. + +After the deployment completes, swap the slot to production: + +```shell +az webapp deployment slot swap --resource-group --name --slot --target-slot production +``` + +**The extension only loads after the swap.** Because we set `WEBSITE_PRIVATE_EXTENSIONS=0`, the runtime does not load private extensions. Production must not have `WEBSITE_PRIVATE_EXTENSIONS=0`. Production will load the extension and send data as expected. + +{{% /tab %}} +{{% tab "ARM Template" %}} + +Use the [Function App slot ARM template](https://github.com/DataDog/datadog-aas-extension/tree/master/install-templates/install-function-app-slot.json): + +```jsonc +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Install Datadog APM extension on an Azure Function App deployment slot. Applies WEBSITE_PRIVATE_EXTENSIONS=0 as a sticky slot setting to prevent MoveDirectory file-lock failures.", + "version": "1.0.0" + }, + "parameters": { + "webAppName": { + "type": "string", + "metadata": { "description": "Name of the Azure Function App" } + }, + "slotName": { + "type": "string", + "metadata": { "description": "Name of the deployment slot (e.g. staging)" } + }, + "datadogApiKey": { + "type": "securestring", + "metadata": { "description": "Your Datadog API key" } + }, + "ddSite": { + "type": "string", + "defaultValue": "datadoghq.com", + "metadata": { "description": "Your Datadog site (e.g. datadoghq.com, datadoghq.eu)" } + }, + "ddService": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Service name for unified service tagging" } + }, + "ddEnv": { + "type": "string", + "defaultValue": "staging", + "metadata": { "description": "Environment tag — set a distinct value for each slot" } + }, + "ddVersion": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Version for unified service tagging" } + }, + "existingStickyAppSettingNames": { + "type": "array", + "metadata": { "description": "Names of app settings already marked slot-sticky on this Function App. Pass [] for a new app with no existing sticky settings. This template does a full replace of slotConfigNames — omitting an existing sticky setting name will de-sticky it." } + } + }, + "resources": [ + { + "type": "Microsoft.Web/sites/slots/config", + "apiVersion": "2025-03-01", + "name": "[concat(parameters('webAppName'), '/', parameters('slotName'), '/appsettings')]", + "properties": { + "WEBSITE_PRIVATE_EXTENSIONS": "0", + "DD_API_KEY": "[parameters('datadogApiKey')]", + "DD_SITE": "[parameters('ddSite')]", + "DD_SERVICE": "[parameters('ddService')]", + "DD_ENV": "[parameters('ddEnv')]", + "DD_VERSION": "[parameters('ddVersion')]" + } + }, + { + "type": "Microsoft.Web/sites/config", + "apiVersion": "2025-03-01", + "name": "[concat(parameters('webAppName'), '/slotConfigNames')]", + "properties": { + "appSettingNames": "[union(parameters('existingStickyAppSettingNames'), createArray('WEBSITE_PRIVATE_EXTENSIONS'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites/slots/config', parameters('webAppName'), parameters('slotName'), 'appsettings')]" + ] + }, + { + "type": "Microsoft.Web/sites/slots/siteextensions", + "apiVersion": "2025-03-01", + "name": "[concat(parameters('webAppName'), '/', parameters('slotName'), '/Datadog.AzureAppServices.DotNet')]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites/config', parameters('webAppName'), 'slotConfigNames')]", + "[resourceId('Microsoft.Web/sites/slots/config', parameters('webAppName'), parameters('slotName'), 'appsettings')]" + ] + } + ] +} +``` + +Deploy: + +```bash +az deployment group create --resource-group --template-file install-function-app-slot.json +``` + +**Note:** The `slotConfigNames` resource does a full replace of the sticky-settings list, so you need to include all existing slot app settings in the `appSettings` array. Pass your existing slot-sticky setting names in `existingStickyAppSettingNames` or pass `[]` for a new app. Any name omitted from `existingStickyAppSettingNames` will be de-stickied. + +After the deployment completes, swap the slot to production: + +```bash +az webapp deployment slot swap --resource-group --name --slot --target-slot production +``` + +**The extension only loads after the swap.** Because we set `WEBSITE_PRIVATE_EXTENSIONS=0`, the runtime does not load private extensions. Production must not have `WEBSITE_PRIVATE_EXTENSIONS=0`. Production will load the extension and send data as expected. + +{{% /tab %}} +{{% tab "Manual" %}} + +1. In the [Azure Portal][5], navigate to your Function App and open **Deployment slots**. Select your deployment slot. + +2. In the slot, open **Configuration** and add the following Application Settings: + + `WEBSITE_PRIVATE_EXTENSIONS` + : **Value**: `0`
+ Prevents the Functions runtime from holding file locks on `C:\home\SiteExtensions\` during extension install. Must be marked as a **Deployment slot setting** (sticky) in step 3.
+ + `DD_API_KEY` + : **Value**: Your [Datadog API key][6].
+ + `DD_SITE` + : **Value**: Your [Datadog site][7]. Defaults to `datadoghq.com`.
+ + `DD_SERVICE` + : **Value**: Your application's service name.
+ + `DD_ENV` + : **Value**: Your application's environment (for example, `staging`).
+ + `DD_VERSION` + : **Value**: Your application's version.
+ +3. Click **Save**. Then open **Configuration** → **General settings** → **Deployment slot settings** and mark `WEBSITE_PRIVATE_EXTENSIONS` as a slot setting. This ensures it stays on this slot after swaps and never propagates to production. + +4. **Stop the slot** by navigating to the slot's **Overview** page and clicking **Stop**. +
You must stop the slot before installing the extension.
+ +5. Navigate to **Extensions** and add the Datadog APM extension for your runtime. + +6. **Start the slot** by clicking **Start** on the slot's **Overview** page. + +7. **Swap the slot to production.** On the slot's **Overview** page, click **Swap** and select `production` as the target, or run: + + ```shell + az webapp deployment slot swap --resource-group --name --slot --target-slot production + ``` +**The extension only loads after the swap.** Because we set `WEBSITE_PRIVATE_EXTENSIONS=0`, the runtime does not load private extensions. Production must not have `WEBSITE_PRIVATE_EXTENSIONS=0`. Production will load the extension and send data as expected. + +[5]: https://portal.azure.com/ +[6]: /account_management/api-app-keys/ +[7]: /getting_started/site/ + +{{% /tab %}} +{{< /tabs >}} + +## Custom metrics + +The Azure App Service extension includes an instance of [DogStatsD][dogstatsd], Datadog's metrics aggregation service. This enables you to submit custom metrics, service checks, and events directly to Datadog from Azure Function Apps with the extension. + +{{% aas-custom-metrics-dotnet %}} + +**Note**: To send only custom metrics (while disabling tracing) set the following variables in your application's config: + - Set `DD_TRACE_ENABLED` to `false`. + - Set `DD_AAS_ENABLE_CUSTOM_METRICS` to `true`. + +Learn more about [custom metrics][5]. + +## Logging + +### Application logging + +{{% aas-logging-dotnet %}} + +### Environment variables for logging + +Configure these environment variables in your Azure App Service Application Settings for optimal log collection: + +| Variable | Description | Example | +|----------|-------------|---------| +| `DD_SERVICE` | Your application's service name | `my-function-app` | +| `DD_ENV` | Your application's environment | `production`, `staging`, `development` | +| `DD_LOGS_INJECTION` | Enable trace-log correlation | `true` | + +### Logging best practices + +- **Enable trace correlation**: Set `DD_LOGS_INJECTION=true` to correlate logs with traces +- **Set proper service names**: Use `DD_SERVICE` to ensure logs appear with the correct service name +- **Use structured logging**: Implement structured logging in your application for better log parsing + +**Note**: Trace ID injection occurs inside your application. Azure Resource logs are generated by Azure in the management plane, and therefore do not include the trace ID. + +{{% aas-logging-dotnet-code-example %}} + +## Programmatic management + +Datadog provides a PowerShell script for installing or updating the extension on a per-app basis. This script can handle configuration for variables such as `DD_SERVICE` and `DD_ENV`. When `-SlotName` is provided, the script automatically applies the `WEBSITE_PRIVATE_EXTENSIONS=0` sticky slot setting before stopping and installing. Scripted extension management enables you to [update extensions in bulk by resource group](#powershell-resource-group) and [designate the installation of specific versions of the site extension](#powershell-specific-version). You can also use scripts to programmatically add the extension in CI/CD pipelines, as well as discover and update extensions that are already installed. + +### Prerequisites + +- The [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) or [Azure Cloud Shell](https://docs.microsoft.com/en-us/azure/cloud-shell/overview). +- Azure App Service [user-scope credentials](https://docs.microsoft.com/en-us/azure/app-service/deploy-configure-credentials). + +### Installing the extension for the first time {#powershell-first-time} + +The install script adds the latest version of the extension to an Azure Web App or Azure Function App. This occurs on a per-app basis, rather than at a resource group level. + +1. Open the Azure CLI or Azure Cloud Shell. +2. Download the installation script using the following command: + + ``` + Invoke-WebRequest -Uri "https://raw.githubusercontent.com/DataDog/datadog-aas-extension/master/management-scripts/extension/install-latest-extension.ps1" -OutFile "install-latest-extension.ps1" + ``` + +3. Run the following command, passing in required and optional arguments as needed. + + ``` + .\install-latest-extension.ps1 -Username -Password -SubscriptionId -ResourceGroup -SiteName -DDApiKey -DDSite -DDEnv -DDService -DDVersion [-SlotName ] + ``` + +**Note**: The following arguments are required for the above command: + +- ``: Your Azure user scope username. +- ``: Your Azure user scope password. +- ``: Your Azure [subscription ID](https://docs.microsoft.com/en-us/azure/media-services/latest/setup-azure-subscription-how-to). +- ``: Your Azure resource group name. +- ``: The name of your app. +- ``: Your [Datadog API key](https://app.datadoghq.com/organization-settings/api-keys). + +Also, set `DATADOG_SITE` to your [Datadog site][32]. `DATADOG_SITE` defaults to `datadoghq.com`. Your site is: {{< region-param key="dd_site" code="true" >}}. + +To target a deployment slot instead of the main app, add `-SlotName `. On Azure Function Apps, this also automatically applies the `WEBSITE_PRIVATE_EXTENSIONS=0` sticky slot setting to prevent extension install failures. + +After the script completes, swap the slot to production: + +```shell +az webapp deployment slot swap --resource-group --name --slot --target-slot production +``` + +**The extension only loads after the swap.** Because we set `WEBSITE_PRIVATE_EXTENSIONS=0`, the runtime does not load private extensions. Production must not have `WEBSITE_PRIVATE_EXTENSIONS=0`. Production will load the extension and send data as expected. + +[32]: /getting_started/site/ + +### Updating the extension for a resource group {#powershell-resource-group} + +The update script applies to an entire resource group. This script updates every app that has the extension installed. Apps that do not have the Datadog extension installed are not affected. + +1. Open the Azure CLI or Azure Cloud Shell. +2. Download the update script using the following command: + + ``` + $baseUri="https://raw.githubusercontent.com/DataDog/datadog-aas-extension/master/management-scripts/extension"; Invoke-WebRequest -Uri "$baseUri/update-all-site-extensions.ps1" -OutFile "update-all-site-extensions.ps1"; Invoke-WebRequest -Uri "$baseUri/install-latest-extension.ps1" -OutFile "install-latest-extension.ps1" + ``` + +3. Run the following command. All arguments are required. + + ``` + .\update-all-site-extensions.ps1 -SubscriptionId -ResourceGroup -Username -Password + ``` + +### Install a specific version of the extension {#powershell-specific-version} + +The Azure App Service UI does not support the ability to install a specific version of an extension. You may do this with the install or update script. + +#### Install specific version on a single resource + +To install a specific version on a single instance, follow the [instructions for installing the extension for the first time](#powershell-first-time) and add the `-ExtensionVersion` parameter to the installation command. + +``` +.\install-latest-extension.ps1 -Username -Password -SubscriptionId -ResourceGroup -SiteName -DDApiKey -ExtensionVersion +``` + +Replace `` with the version of the extension you wish to install. For instance, `1.4.0`. + +#### Install specific version on an entire resource group + +To install a specific version for a resource group, follow the [instructions for updating the extension for a resource group](#powershell-resource-group) and add the `-ExtensionVersion` parameter to the installation command. + +``` +.\update-all-site-extensions.ps1 -SubscriptionId -ResourceGroup -Username -Password -ExtensionVersion +``` + +Replace `` with the version of the extension you wish to install. For instance, `1.4.0`. + +## Troubleshooting + +### Extension install fails with "Could not execute MoveDirectory" + +Azure Function Apps can fail with a "Could not execute MoveDirectory" error during extension install. This happens because the Functions runtime holds file locks on `C:\home\SiteExtensions\` after a code deployment, preventing Kudu from moving the staged extension into place. + +The fix is `WEBSITE_PRIVATE_EXTENSIONS=0` set as a **sticky slot setting** on the deploy slot. If you are using the PowerShell script with `-SlotName`, the workaround is applied automatically. If you are using ARM or Bicep, confirm the templates above are deployed before attempting the extension install, and that the `WEBSITE_PRIVATE_EXTENSIONS` setting is present and sticky on your slot. + +After installation, **swap the slot to production**. The extension will not load on the slot itself because `WEBSITE_PRIVATE_EXTENSIONS=0` prevents private extension loading — this is expected. Telemetry only begins after the swap, when production installs the extension. + +**Without a slot (production-direct installs):** Fully stop the Function App before installing, then start it after. Do not set `WEBSITE_PRIVATE_EXTENSIONS=0` on production — the extension loads normally after the app starts. + +### APM traces are not appearing + +1. Verify `DD_SITE` and `DD_API_KEY` are set correctly on the production app. +2. If you installed via a deployment slot, confirm you swapped the slot to production. +3. Do a full stop and start of the production app. +4. If not resolved, uninstall and reinstall the extension, then swap again. + +Still need help? Contact [Datadog support][4]. + +[1]: /serverless/azure_functions/ +[2]: /integrations/azure/ +[3]: /getting_started/site/ +[4]: /help +[5]: /metrics/custom_metrics/ +[dogstatsd]: /extend/dogstatsd/ diff --git a/layouts/shortcodes/aas-custom-metrics-dotnet.en.md b/layouts/shortcodes/aas-custom-metrics-dotnet.en.md new file mode 100644 index 00000000000..44c24ecb73a --- /dev/null +++ b/layouts/shortcodes/aas-custom-metrics-dotnet.en.md @@ -0,0 +1,21 @@ +1. Add the [DogStatsD NuGet package](https://www.nuget.org/packages/DogStatsD-CSharp-Client) to your Visual Studio project. +2. Initialize DogStatsD and write custom metrics in your application. +3. Deploy your code to Azure App Service. +4. If you have not already, install the Datadog App Service extension. + +To send metrics, use this code: + +```csharp +// Configure your DogStatsd client and configure any tags +if (!DogStatsd.Configure(new StatsdConfig() { ConstantTags = new[] { "app:sample.mvc.aspnetcore" } })) +{ + // `Configure` returns false if the necessary environment variables are not present. + // These environment variables are present in Azure App Service, but + // need to be set in order to test your custom metrics: DD_API_KEY:{api_key}, DD_AGENT_HOST:localhost + // Ignore or log the error as it suits you + Console.WriteLine("Cannot initialize DogstatsD."); +} + +// Send a metric +DogStatsd.Increment("sample.startup"); +``` diff --git a/layouts/shortcodes/aas-logging-dotnet-code-example.en.md b/layouts/shortcodes/aas-logging-dotnet-code-example.en.md new file mode 100644 index 00000000000..4e733d5e5fa --- /dev/null +++ b/layouts/shortcodes/aas-logging-dotnet-code-example.en.md @@ -0,0 +1,77 @@ +**Code Example: Microsoft Native Logging** + +An example of how to set up logging in a .NET application using Microsoft.Extensions.Logging: + +```csharp +using Microsoft.Extensions.Logging; + +public class WeatherForecastController : ControllerBase +{ + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet] + public IActionResult Get() + { + _logger.LogInformation("Processing weather forecast request"); + + // Your business logic here + var forecast = GetWeatherForecast(); + + _logger.LogInformation("Weather forecast retrieved for user: {UserId}", userId); + + return Ok(forecast); + } +} +``` + +**Program.cs configuration** + +```csharp +using Microsoft.Extensions.Logging; + +var builder = WebApplication.CreateBuilder(args); + +// Configure logging +builder.Logging.ClearProviders(); +builder.Logging.AddConsole(); +builder.Logging.AddDebug(); + +// Add structured logging with JSON format +builder.Logging.AddJsonConsole(options => +{ + options.JsonWriterOptions = new JsonWriterOptions + { + Indented = true + }; +}); + +var app = builder.Build(); +// ... rest of your application configuration +``` + +**appsettings.json configuration** + +```json +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + }, + "Console": { + "FormatterName": "json", + "FormatterOptions": { + "IncludeScopes": true, + "TimestampFormat": "yyyy-MM-dd HH:mm:ss " + } + } + } +} +``` + +This setup automatically includes trace correlation when `DD_LOGS_INJECTION=true` is set in your Azure App Service Application Settings. diff --git a/layouts/shortcodes/aas-logging-dotnet.en.md b/layouts/shortcodes/aas-logging-dotnet.en.md new file mode 100644 index 00000000000..27db5f01fcd --- /dev/null +++ b/layouts/shortcodes/aas-logging-dotnet.en.md @@ -0,0 +1,9 @@ +You can send logs from your application in Azure App Service to Datadog in one of the following ways: + +- Use the [installation steps](#installation) on this page to enable APM with the Datadog APM extension. Then [enable Agentless logging][aas-logging-dotnet-1]. +- Use [Agentless logging with the Serilog sink][aas-logging-dotnet-2]. + +Both methods allow trace ID injection, making it possible to connect logs and traces in Datadog. To enable trace ID injection with the extension, add the application setting `DD_LOGS_INJECTION:true`. + +[aas-logging-dotnet-1]: /logs/log_collection/csharp/#agentless-logging-with-apm +[aas-logging-dotnet-2]: /logs/log_collection/csharp/#agentless-logging-with-serilog-sink