Skip to content

Merge to Live #35175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aspnetcore/blazor/fundamentals/signalr.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ An element with an `id` of `components-seconds-to-next-attempt` displays the num
<span id="components-seconds-to-next-attempt"></span>
```

The Blazor Web App project template includes a `ReconnectModal` component (`Components/Layout/ReconnectModal.razor`) with collocated stylesheet and JavaScript files (`ReconnectModal.razor.css`, `ReconnectModal.razor.js`) that can be customized as needed. These files can be examined in the ASP.NET Core reference source or by inspecting an app created from the Blazor Web App project template. The component is added to the project when the project is created in Visual Studio with **Interactive render mode** set to **Server** or **Auto** or created with the .NET CLI with the option `--interactivity server` (default) or `--interactivity auto`.
The Blazor Web App project template includes a `ReconnectModal` component (`Layout/ReconnectModal.razor`) with collocated stylesheet and JavaScript files (`ReconnectModal.razor.css`, `ReconnectModal.razor.js`) that can be customized as needed. These files can be examined in the ASP.NET Core reference source or by inspecting an app created from the Blazor Web App project template. The component is added to the project when the project is created in Visual Studio with **Interactive render mode** set to **Server** or **Auto** or created with the .NET CLI with the option `--interactivity server` (default) or `--interactivity auto`.

* [`ReconnectModal` component](https://github.com/dotnet/aspnetcore/blob/main/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Layout/ReconnectModal.razor)
* [Stylesheet file](https://github.com/dotnet/aspnetcore/blob/main/src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWeb-CSharp/Components/Layout/ReconnectModal.razor.css)
Expand Down
99 changes: 99 additions & 0 deletions aspnetcore/fundamentals/http-logging/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ HTTP logging ***can reduce the performance of an app***, especially when logging

> [!WARNING]
> HTTP logging can potentially log personally identifiable information (PII). Consider the risk and avoid logging sensitive information.
> For more information about redaction, check [redacting sensitive data](#redacting-sensitive-data)

## Enable HTTP logging

Expand Down Expand Up @@ -205,3 +206,101 @@ The following list shows the order of precedence for logging configuration:
:::moniker-end

[!INCLUDE[](~/fundamentals/http-logging/includes/index-6-7.md)]

:::moniker range=">= aspnetcore-10.0"

## Redacting sensitive data

Http logging with redaction can be enabled by calling `AddHttpLoggingRedaction`<!-- Microsoft.Extensions.DependencyInjection.HttpLoggingServiceCollectionExtensions.AddHttpLoggingRedaction> -->:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet7&highlight=9)]

For more information about .NET's data redaction library, see [Data redaction in .NET](/dotnet/core/extensions/data-redaction).

## Logging redaction options

To configure options for logging with redaction, call `AddHttpLoggingRedaction`<!-- Microsoft.Extensions.DependencyInjection.HttpLoggingServiceCollectionExtensions.AddHttpLoggingRedaction>--> in `Program.cs`, using the lambda to configure <!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions>--> `LoggingRedactionOptions`:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/MyTaxonomyClassifications.cs)]
[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=6)]

With the previous redaction configuration, the output is similar to the following:

```output
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[9]
Request and Response:
server.address: localhost:61361
Path: /
http.request.header.accept:
Protocol: HTTP/2
Method: GET
Scheme: https
http.response.header.content-type:
StatusCode: 200
Duration: 8.4684
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/2 GET https://localhost:61361/ - 200 - text/plain;+charset=utf-8 105.5334ms
```

***Note:*** Request path `/home` isn't logged because it is included in `ExcludePathStartsWith` property. `http.request.header.accept` and `http.response.header.content-type` were redacted by <!-- Microsoft.Extensions.Compliance.Redaction.ErasingRedactor> --> `Redaction.ErasingRedactor`.

### RequestPathLoggingMode

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.RequestPathLoggingMode>-->
`RequestPathLoggingMode` determines how the request path is logged, whether `Formatted` or `Structured`.

<!-- Microsoft.AspNetCore.Diagnostics.Logging.IncomingPathLoggingMode.Formatted> -->
* `Formatted` logs the request path without parameters.
<!-- Microsoft.AspNetCore.Diagnostics.Logging.IncomingPathLoggingMode.Structured> -->
* `Structured` logs the request path with parameters included.

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=9)]

### RequestPathParameterRedactionMode

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.RequestPathParameterRedactionMode> -->
`RequestPathParameterRedactionMode` specifies how route parameters in the request path should be redacted, whether `Strict` or `None`.

<!-- Microsoft.AspNetCore.Diagnostics.Logging.HttpRouteParameterRedactionMode.Strict>-->
* `Strict`: request route parameters are considered as sensitive and are redacted by default.
<!-- Microsoft.AspNetCore.Diagnostics.Logging.HttpRouteParameterRedactionMode.None>-->
* `None`: request route parameters are considered as non-sensitive and logged as-is by default.

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=8)]

### RequestHeadersDataClasses

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.RequestHeadersDataClasses>-->
`RequestHeadersDataClasses` maps request headers to their data classification, which determines how they are redacted:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=10)]

### ResponseHeadersDataClasses

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.ResponseHeadersDataClasses>-->
`ResponseHeadersDataClasses`, similar to <!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.RequestHeadersDataClasses>--> `RequestHeadersDataClasses`, but for response headers:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=11)]

### RouteParameterDataClasses

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.RouteParameterDataClasses>-->
`RouteParameterDataClasses` maps route parameters to their data classification:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=12,13,14,15)]

### ExcludePathStartsWith

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.ExcludePathStartsWith>-->
`ExcludePathStartsWith` specifies paths that should be excluded from logging entirely:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=16,17)]

### IncludeUnmatchedRoutes

<!-- Microsoft.AspNetCore.Diagnostics.Logging.LoggingRedactionOptions.IncludeUnmatchedRoutes>-->
`IncludeUnmatchedRoutes` allows reporting unmatched routes. If set to `true`, logs whole path of routes not identified by [Routing](xref:fundamentals/routing) instead of logging `Unknown` value for path attribute:

[!code-csharp[](~/fundamentals/http-logging/samples/8.x/Program.cs?name=snippet_redactionOptions&highlight=18)]

:::moniker-end
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.Middleware" Version="9.3.0" />
<PackageReference Include="Microsoft.Extensions.Compliance.Redaction" Version="9.3.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.Extensions.Compliance.Classification;

namespace HttpLoggingSample
{
public static class MyTaxonomyClassifications
{
public static string Name => "MyTaxonomy";

public static DataClassification Private => new(Name, nameof(Private));
public static DataClassification Public => new(Name, nameof(Public));
public static DataClassification Personal => new(Name, nameof(Personal));
}
}
54 changes: 50 additions & 4 deletions aspnetcore/fundamentals/http-logging/samples/8.x/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#define THIRD // FIRST SECOND THIRD
#define THIRD // FIRST SECOND THIRD FORTH
#if NEVER
#elif FIRST
// <snippet_Addservices>
Expand Down Expand Up @@ -26,7 +26,7 @@

app.UseStaticFiles();

app.UseHttpLogging();
app.UseHttpLogging();

app.Use(async (context, next) =>
{
Expand Down Expand Up @@ -60,11 +60,54 @@

app.Run();
// </snippet2>
#elif FORTH
using Microsoft.Extensions.Http.Diagnostics;
using Microsoft.AspNetCore.Diagnostics.Logging;
using Microsoft.Extensions.Compliance.Classification;
using HttpLoggingSample;
using Microsoft.Net.Http.Headers;

// <snippet_redactionOptions>
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpLogging(o => { });
builder.Services.AddRedaction();

builder.Services.AddHttpLoggingRedaction(op =>
{
op.RequestPathParameterRedactionMode = HttpRouteParameterRedactionMode.None;
op.RequestPathLoggingMode = IncomingPathLoggingMode.Formatted;
op.RequestHeadersDataClasses.Add(HeaderNames.Accept, MyTaxonomyClassifications.Public);
op.ResponseHeadersDataClasses.Add(HeaderNames.ContentType, MyTaxonomyClassifications.Private);
op.RouteParameterDataClasses = new Dictionary<string, DataClassification>
{
{ "one", MyTaxonomyClassifications.Personal },
};
// Add the paths that should be filtered, with a leading '/'.
op.ExcludePathStartsWith.Add("/home");
op.IncludeUnmatchedRoutes = true;
});

var app = builder.Build();

app.UseHttpLogging();

if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();

app.MapGet("/", () => "Logged!");
app.MapGet("/home", () => "Not logged!");

app.Run();
// </snippet_redactionOptions>
#elif THIRD
// <snippet3>
using HttpLoggingSample;
using Microsoft.AspNetCore.HttpLogging;

// <snippet7>
// <snippet4>
var builder = WebApplication.CreateBuilder(args);

Expand All @@ -74,6 +117,9 @@
});
builder.Services.AddHttpLoggingInterceptor<SampleHttpLoggingInterceptor>();
// </snippet4>
builder.Services.AddRedaction();
builder.Services.AddHttpLoggingRedaction(op => { });
// </snippet7>
var app = builder.Build();

if (!app.Environment.IsDevelopment())
Expand All @@ -83,7 +129,7 @@

app.UseStaticFiles();

app.UseHttpLogging();
app.UseHttpLogging();

app.Use(async (context, next) =>
{
Expand Down
Loading