diff --git a/.openpublishing.redirection.core.json b/.openpublishing.redirection.core.json index 55f81897ade37..59207dec33e56 100644 --- a/.openpublishing.redirection.core.json +++ b/.openpublishing.redirection.core.json @@ -757,6 +757,10 @@ "source_path_from_root": "/docs/core/dotnet-five.md", "redirect_url": "/dotnet/core/whats-new/dotnet-5" }, + { + "source_path_from_root": "/docs/core/enrichment/application-metadata.md", + "redirect_url": "/dotnet/core/diagnostics/ambient-metadata/application-metadata" + }, { "source_path_from_root": "/docs/core/extensions/artificial-intelligence.md", "redirect_url": "/dotnet/ai/microsoft-extensions-ai" diff --git a/docs/core/enrichment/application-metadata.md b/docs/core/diagnostics/ambient-metadata/application-metadata.md similarity index 97% rename from docs/core/enrichment/application-metadata.md rename to docs/core/diagnostics/ambient-metadata/application-metadata.md index 0bfd0f7a7480a..c4799b9bd7df2 100644 --- a/docs/core/enrichment/application-metadata.md +++ b/docs/core/diagnostics/ambient-metadata/application-metadata.md @@ -107,7 +107,7 @@ var buildVersion = metadataOptions.Value.BuildVersion; Your `appsettings.json` can have a section as follows: -:::code language="json" source="snippets/applicationlogenricher/appsettings.json" range="2-7"::: +:::code language="json" source="snippets/applicationmetadata/appsettings.json" range="2-7"::: ### Configure with IHostApplicationBuilder @@ -128,7 +128,7 @@ var buildVersion = metadataOptions.Value.BuildVersion; Your `appsettings.json` can have a section as follows: -:::code language="json" source="snippets/applicationlogenricher/appsettings.json" range="2-7"::: +:::code language="json" source="snippets/applicationmetadata/appsettings.json" range="2-7"::: ## Access application metadata diff --git a/docs/core/diagnostics/ambient-metadata/build-metadata.md b/docs/core/diagnostics/ambient-metadata/build-metadata.md new file mode 100644 index 0000000000000..6ecd1a85f1528 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/build-metadata.md @@ -0,0 +1,139 @@ +--- +title: Ambient metadata about build +description: Learn how to use ambient build metadata to capture and access CI/CD build information about your application at runtime in .NET. +ms.date: 01/16/2026 +ai-usage: ai-assisted +--- + +# Ambient metadata about build + +The [`Microsoft.Extensions.AmbientMetadata.Build`](https://www.nuget.org/packages/Microsoft.Extensions.AmbientMetadata.Build) NuGet package provides functionality to capture build-related information and access it at runtime. During the build process, source generation captures details from CI/CD pipelines (such as build IDs, commit information, and branch names) and embeds them into the compiled application, making them available for traceability, troubleshooting, and deployment tracking. + +## Why use build metadata + +Build metadata provides context about the specific build that produced your running application, which can be used in various scenarios, such as: + +- **Traceability**: Link runtime behavior directly to specific builds and source code commits. +- **Troubleshooting**: Identify which commit or build introduced issues in production. +- **Deployment tracking**: Know exactly what code version is running in each environment. +- **Audit and compliance**: Maintain detailed records of what code was deployed and when. +- **Telemetry enrichment**: Add build context to logs, metrics, and traces. + +## How build metadata works + +The build metadata component uses a source generator that captures build information during compilation. When you build your application, the generator reads MSBuild properties and generates code that embeds this information into your compiled assembly. + +### Automatic capture in CI/CD + +When building in supported CI/CD environments (Azure DevOps or GitHub Actions), environment variables are automatically captured through a transitive MSBuild props file. This file maps CI/CD environment variables to MSBuild properties that the source generator can read: + +**Azure DevOps environment variables:** + +- `BUILD_BUILDID` → `BuildMetadataAzureBuildId` +- `BUILD_BUILDNUMBER` → `BuildMetadataAzureBuildNumber` +- `BUILD_SOURCEBRANCHNAME` → `BuildMetadataAzureSourceBranchName` +- `BUILD_SOURCEVERSION` → `BuildMetadataAzureSourceVersion` +- `TF_BUILD` → `BuildMetadataIsAzureDevOps` (detection flag) + +**GitHub Actions environment variables:** + +- `GITHUB_RUN_ID` → `BuildMetadataGitHubRunId` +- `GITHUB_RUN_NUMBER` → `BuildMetadataGitHubRunNumber` +- `GITHUB_REF_NAME` → `BuildMetadataGitHubRefName` +- `GITHUB_SHA` → `BuildMetadataGitHubSha` + +The source generator detects which CI/CD platform is active and uses the appropriate set of properties to populate the class, which you can then inject as `IOptions` and use at runtime. + +### Manual configuration with MSBuild properties + +If you're building outside of a supported CI/CD environment or want to override the automatic values, you can set MSBuild properties directly in your project file or pass them as command-line arguments. + +## Install the package + +To get started, install the [📦 Microsoft.Extensions.AmbientMetadata.Build](https://www.nuget.org/packages/Microsoft.Extensions.AmbientMetadata.Build) NuGet package: + +### [.NET CLI](#tab/dotnet-cli) + +```dotnetcli +dotnet add package Microsoft.Extensions.AmbientMetadata.Build +``` + +Or, if you're using .NET 10+ SDK: + +```dotnetcli +dotnet package add Microsoft.Extensions.AmbientMetadata.Build +``` + +### [PackageReference](#tab/package-reference) + +```xml + +``` + +--- + +## Configure build metadata + +The source generator included in the `Microsoft.Extensions.AmbientMetadata.Build` package generates the `UseBuildMetadata()` extension method that simplifies configuration. During the build process, it captures build information from MSBuild properties and generates code to make this data available at runtime. + +### 1. Use UseBuildMetadata() method + +The simplest way to configure build metadata is to use the source-generated `UseBuildMetadata()` extension method: + +:::code language="csharp" source="snippets/buildmetadata-usebuildmetadata/Program.cs" range="4-9" highlight="3"::: + +The `UseBuildMetadata()` method: + +- Adds the build metadata configuration source (with values captured during the build process) +- Registers the type in dependency injection +- Uses the default configuration section `ambientmetadata:build` + +### 2. Use AddBuildMetadata() methods + +You can also configure build metadata using the `AddBuildMetadata()` extension methods. These methods do absolutely the same thing as `UseBuildMetadata()` above, but provide more flexibility if, for instance, you configure Host Configuration and Dependency Injection in different places of your source code. + +:::code language="csharp" source="snippets/buildmetadata-access/Program.cs" range="7-22" highlight="5-6"::: + +### 3. Configure with MSBuild properties + +You can set build metadata by defining MSBuild properties in your project file. This is useful when building outside of a CI/CD environment or when you want to provide custom values. + +:::code language="xml" source="snippets/buildmetadata-msbuild-azure/buildmetadata-msbuild-azure.csproj" range="3-12" highlight="6-10"::: + +> [!NOTE] +> The source generator uses `BuildMetadataIsAzureDevOps` to determine which set of properties to read (Azure DevOps or GitHub Actions). If you're manually setting properties, ensure you set this flag appropriately or use the GitHub properties if the flag is not set. + +## Access build metadata + +Once configured, you can inject and use the type: + +:::code language="csharp" source="snippets/buildmetadata-access/Program.cs" highlight="16"::: + +## Complete example + +Here's a complete example showing how to set up and use build metadata: + +**appsettings.json:** + +:::code language="json" source="snippets/buildmetadata/appsettings.json"::: + +**Program.cs:** + +:::code language="csharp" source="snippets/buildmetadata/Program.cs"::: + +> [!NOTE] +> This example uses `appsettings.json` to configure build metadata properties *manually*. This is for demonstration purposes; in a real CI/CD scenario, these values would be captured automatically from respective environment variables, and you don't need to have them in `appsettings.json`. + +### Output + +The output includes build metadata in the log messages: + +``` +info: ApplicationService[0] + Application started - Build: 1.0.0-ci.20260116.1, Branch: main, Commit: a1b2c3d +``` + +## Next steps + +- Learn about [application metadata](application-metadata.md) for capturing application-level information diff --git a/docs/core/diagnostics/ambient-metadata/snippets/applicationmetadata/appsettings.json b/docs/core/diagnostics/ambient-metadata/snippets/applicationmetadata/appsettings.json new file mode 100644 index 0000000000000..176577c415974 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/applicationmetadata/appsettings.json @@ -0,0 +1,8 @@ +{ + "AmbientMetadata": { + "Application": { + "DeploymentRing": "testring", + "BuildVersion": "1.2.3" + } + } +} diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/Program.cs b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/Program.cs new file mode 100644 index 0000000000000..af810d272b788 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/Program.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.AmbientMetadata; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; + +var builder = Host.CreateApplicationBuilder(args); +builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + +// Add build metadata to configuration and services +builder.Configuration.AddBuildMetadata(); +builder.Services.AddBuildMetadata(builder.Configuration.GetSection("ambientmetadata:build")); + +var host = builder.Build(); + +var metadata = host.Services.GetRequiredService>().Value; +Console.WriteLine($"Build ID: {metadata.BuildId}"); +Console.WriteLine($"Build Number: {metadata.BuildNumber}"); +Console.WriteLine($"Branch: {metadata.SourceBranchName}"); +Console.WriteLine($"Commit: {metadata.SourceVersion}"); + +await host.RunAsync(); diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/appsettings.json b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/appsettings.json new file mode 100644 index 0000000000000..b522b10a8aff2 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/appsettings.json @@ -0,0 +1,10 @@ +{ + "ambientmetadata": { + "build": { + "BuildId": "12345", + "BuildNumber": "1.0.0-ci.20260116.1", + "SourceBranchName": "main", + "SourceVersion": "a1b2c3d4e5f6789012345678901234567890abcd" + } + } +} diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/buildmetadata-access.csproj b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/buildmetadata-access.csproj new file mode 100644 index 0000000000000..aa743f68ed698 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-access/buildmetadata-access.csproj @@ -0,0 +1,21 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + + + + PreserveNewest + + + + diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-msbuild-azure/Program.cs b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-msbuild-azure/Program.cs new file mode 100644 index 0000000000000..e7e288ff45f14 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-msbuild-azure/Program.cs @@ -0,0 +1,11 @@ +using Microsoft.Extensions.AmbientMetadata; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +var builder = Host.CreateApplicationBuilder(args); + +builder.Configuration.AddBuildMetadata(); +builder.Services.AddBuildMetadata(builder.Configuration.GetSection("ambientmetadata:build")); + +var host = builder.Build(); +await host.RunAsync(); diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-msbuild-azure/buildmetadata-msbuild-azure.csproj b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-msbuild-azure/buildmetadata-msbuild-azure.csproj new file mode 100644 index 0000000000000..4760fdadff8ff --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-msbuild-azure/buildmetadata-msbuild-azure.csproj @@ -0,0 +1,20 @@ + + + + Exe + net10.0 + enable + enable + 12345 + 1.0.0-local.1 + feature/my-feature + a1b2c3d4e5f6789012345678901234567890abcd + true + + + + + + + + diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-usebuildmetadata/Program.cs b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-usebuildmetadata/Program.cs new file mode 100644 index 0000000000000..3a6ee126c6978 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-usebuildmetadata/Program.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.AmbientMetadata; + +var builder = Host.CreateApplicationBuilder(args); + +builder.UseBuildMetadata(); + +var host = builder.Build(); +await host.RunAsync(); diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-usebuildmetadata/buildmetadata-usebuildmetadata.csproj b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-usebuildmetadata/buildmetadata-usebuildmetadata.csproj new file mode 100644 index 0000000000000..3e8c16163c1f9 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata-usebuildmetadata/buildmetadata-usebuildmetadata.csproj @@ -0,0 +1,15 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + + diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/Program.cs b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/Program.cs new file mode 100644 index 0000000000000..8b80a2afac802 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/Program.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.AmbientMetadata; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +var builder = Host.CreateApplicationBuilder(args); + +// Add build metadata to configuration and services +builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); +builder.Services.AddBuildMetadata(builder.Configuration.GetSection("ambientmetadata:build")); + +// Register application service +builder.Services.AddSingleton(); + +var host = builder.Build(); + +// Use build metadata +var appService = host.Services.GetRequiredService(); +appService.Start(); + +await host.RunAsync(); + +public class ApplicationService( + ILogger logger, + IOptions buildMetadata) +{ + private readonly ILogger _logger = logger; + private readonly BuildMetadata _buildMetadata = buildMetadata.Value; + + public void Start() + { + _logger.LogInformation( + "Application started - Build: {BuildNumber}, Branch: {Branch}, Commit: {Commit}", + _buildMetadata.BuildNumber, + _buildMetadata.SourceBranchName, + _buildMetadata.SourceVersion?[..7]); + } +} diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/appsettings.json b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/appsettings.json new file mode 100644 index 0000000000000..60f611af3bed9 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information" + } + }, + "ambientmetadata": { + "build": { + "BuildId": "12345", + "BuildNumber": "1.0.0-ci.20260116.1", + "SourceBranchName": "main", + "SourceVersion": "a1b2c3d4e5f6789012345678901234567890abcd" + } + } +} diff --git a/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/buildmetadata.csproj b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/buildmetadata.csproj new file mode 100644 index 0000000000000..0a69fdc70f447 --- /dev/null +++ b/docs/core/diagnostics/ambient-metadata/snippets/buildmetadata/buildmetadata.csproj @@ -0,0 +1,22 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + + + + + PreserveNewest + + + + diff --git a/docs/core/enrichment/application-log-enricher.md b/docs/core/enrichment/application-log-enricher.md index 582b222622d30..b5b2b9a7d7801 100644 --- a/docs/core/enrichment/application-log-enricher.md +++ b/docs/core/enrichment/application-log-enricher.md @@ -12,7 +12,7 @@ You can register the enrichers in an IoC container, and all registered enrichers ## Prerequisites -To function properly, this enricher requires that [application metadata](application-metadata.md) is configured and available. The application metadata provides the foundational information that the enricher uses to populate telemetry dimensions. +To function properly, this enricher requires that [application metadata](../diagnostics/ambient-metadata/application-metadata.md) is configured and available. The application metadata provides the foundational information that the enricher uses to populate telemetry dimensions. ## Install the package @@ -45,7 +45,7 @@ Follow these steps to configure the application log enricher in your application ### 1. Configure application metadata -First, configure the [Application Metadata](application-metadata.md) by calling the methods: +First, configure the [Application Metadata](../diagnostics/ambient-metadata/application-metadata.md) by calling the methods: ```csharp var builder = Host.CreateApplicationBuilder(args); @@ -67,7 +67,7 @@ builder.Services.AddApplicationMetadata( ### 2. Provide additional configuration (optional) -You can provide additional configuration via `appsettings.json`. There are two properties in the [Application Metadata](application-metadata.md) that don't get values automatically: `BuildVersion` and `DeploymentRing`. If you want to use them, provide values manually: +You can provide additional configuration via `appsettings.json`. There are two properties in the [Application Metadata](../diagnostics/ambient-metadata/application-metadata.md) that don't get values automatically: `BuildVersion` and `DeploymentRing`. If you want to use them, provide values manually: :::code language="json" source="snippets/applicationlogenricher/appsettings.json" range="2-7"::: @@ -136,4 +136,4 @@ With the application log enricher configured, your log output includes service-s ## Next steps -- Learn about [application metadata configuration](application-metadata.md) +- Learn about [application metadata configuration](../diagnostics/ambient-metadata/application-metadata.md) diff --git a/docs/navigate/tools-diagnostics/toc.yml b/docs/navigate/tools-diagnostics/toc.yml index 612e7ce530ccc..cb89f696e5400 100644 --- a/docs/navigate/tools-diagnostics/toc.yml +++ b/docs/navigate/tools-diagnostics/toc.yml @@ -458,12 +458,16 @@ items: href: ../../core/diagnostics/distributed-tracing-collection-walkthroughs.md - name: Built-in activities href: ../../core/diagnostics/distributed-tracing-builtin-activities.md + - name: Ambient metadata + items: + - name: Application metadata + href: ../../core/diagnostics/ambient-metadata/application-metadata.md + - name: Ambient metadata about build + href: ../../core/diagnostics/ambient-metadata/build-metadata.md - name: Enrichment items: - name: Overview href: ../../core/enrichment/overview.md - - name: Application metadata - href: ../../core/enrichment/application-metadata.md - name: Application log enricher href: ../../core/enrichment/application-log-enricher.md - name: Process log enricher