Journalisation HTTP dans ASP.NET Core
Remarque
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.
Avertissement
Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.
Important
Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.
Pour la version actuelle, consultez la version .NET 9 de cet article.
La journalisation HTTP est un intergiciel qui journalise des informations sur les requêtes HTTP entrantes et les réponses HTTP. La journalisation HTTP fournit les journaux suivants :
- Informations sur les requêtes HTTP
- Propriétés communes
- En-têtes
- Corps
- Informations de réponse HTTP
La journalisation HTTP peut :
- Journaliser toutes les requêtes et les réponses ou uniquement les requêtes et réponses qui répondent à certains critères.
- Sélectionner les parties de la requête et de la réponse qui sont journalisées.
- Vous autoriser à rédiger des informations sensibles à partir des journaux d’activité.
La journalisation HTTP peut réduire les performances d’une application, en particulier lors de la journalisation des corps de requête et de réponse. Tenez compte de l’impact sur les performances lorsque vous sélectionnez les champs à journaliser. Testez l’impact des propriétés de journalisation sélectionnées sur les performances.
Avertissement
La journalisation HTTP peut potentiellement journaliser des informations d’identification personnelle. Tenez compte des risques, et évitez de journaliser des informations sensibles.
Activer la journalisation HTTP
La journalisation HTTP est activée en appelant AddHttpLogging et UseHttpLogging, comme illustré dans l’exemple suivant :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(o => { });
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.Run();
L’expression lambda vide dans l’exemple précédent d’appel AddHttpLogging
ajoute l’intergiciel avec la configuration par défaut. Par défaut, la journalisation HTTP journalise les propriétés courantes telles que le chemin d’accès, le code d’état et les en-têtes des requêtes et des réponses.
Ajoutez la ligne suivante au fichier appsettings.Development.json
au niveau "LogLevel": {
afin que les journaux HTTP soient affichés :
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
Avec la configuration par défaut, une requête et une réponse sont enregistrées sous la forme d’une paire de messages similaire à l’exemple suivant :
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
Request:
Protocol: HTTP/2
Method: GET
Scheme: https
PathBase:
Path: /
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Host: localhost:52941
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: [Redacted]
sec-ch-ua: [Redacted]
sec-ch-ua-mobile: [Redacted]
sec-ch-ua-platform: [Redacted]
sec-fetch-site: [Redacted]
sec-fetch-mode: [Redacted]
sec-fetch-user: [Redacted]
sec-fetch-dest: [Redacted]
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
StatusCode: 200
Content-Type: text/plain; charset=utf-8
Date: Tue, 24 Oct 2023 02:03:53 GMT
Server: Kestrel
Options de journalisation HTTP
Pour configurer des options globales pour l’intergiciel de journalisation HTTP, appelez-AddHttpLogging dans Program.cs
à l’aide de l’expression lambda pour configurer HttpLoggingOptions.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Remarque
Dans l’exemple précédent et les exemples suivants, UseHttpLogging
est appelé après UseStaticFiles
, la journalisation HTTP n’est donc pas activée pour le fichier statique. Pour activer la journalisation HTTP de fichier statique, appelez UseHttpLogging
avant UseStaticFiles
.
LoggingFields
HttpLoggingOptions.LoggingFields
est un indicateur d’énumération qui configure certaines parties de la requête et de la réponse à journaliser. HttpLoggingOptions.LoggingFields
a la valeur par défaut RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
et ResponseHeaders
RequestHeaders et ResponseHeaders sont des ensembles d’en-têtes HTTP journalisés. Les valeurs d’en-tête sont journalisées uniquement pour les noms d’en-tête qui se trouvent dans ces collections. Le code suivant ajoute sec-ch-ua
à RequestHeaders, de sorte que la valeur de l’en-tête sec-ch-ua
est journalisée. Et il ajoute MyResponseHeader
à ResponseHeaders, de sorte que la valeur de l’en-tête MyResponseHeader
est journalisée. Si ces lignes sont supprimées, les valeurs de ces en-têtes sont [Redacted]
.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
MediaTypeOptions
MediaTypeOptions fournit la configuration permettant de sélectionner l’encodage à utiliser pour un type de média spécifique.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Cette approche peut également être utilisée pour activer la journalisation des données qui ne sont pas journalisées par défaut (par exemple, les données de formulaire, qui peuvent avoir un type de média tel que application/x-www-form-urlencoded
ou multipart/form-data
).
Méthodes MediaTypeOptions
RequestBodyLogLimit
et ResponseBodyLogLimit
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
CombineLogs
Définir CombineLogs sur true
configure l’intergiciel pour consolider tous ses journaux activés pour une requête et une réponse dans un journal à la fin. Cela inclut la requête, le corps de la requête, la réponse, le corps de la réponse et la durée.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
logging.CombineLogs = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Configuration spécifique au point de terminaison
Pour une configuration spécifique au point de terminaison dans des applications API minimales, une méthode d’extension WithHttpLogging est disponible. L’exemple suivant montre comment configurer la journalisation HTTP pour un point de terminaison :
app.MapGet("/response", () => "Hello World! (logging response)")
.WithHttpLogging(HttpLoggingFields.ResponsePropertiesAndHeaders);
Pour la configuration spécifique au point de terminaison dans les applications qui utilisent des contrôleurs, l’attribut [HttpLogging]
est disponible. L’attribut peut également être utilisé dans des applications API minimales, comme illustré dans l’exemple suivant :
app.MapGet("/duration", [HttpLogging(loggingFields: HttpLoggingFields.Duration)]
() => "Hello World! (logging duration)");
IHttpLoggingInterceptor
IHttpLoggingInterceptor est l’interface d’un service qui peut être implémenté pour gérer les rappels par requête et par réponse pour personnaliser les détails enregistrés. Tous les paramètres de journal spécifiques au point de terminaison sont appliqués en premier et peuvent ensuite être remplacés dans ces rappels. Une implémentation peut :
- Inspecter une requête ou une réponse.
- Activer ou désactiver un HttpLoggingFields quelconque.
- Ajuster la quantité du corps de la requête ou de la réponse journalisée.
- Ajouter des champs personnalisés aux journaux.
Inscrire une implémentation IHttpLoggingInterceptor
en appelant AddHttpLoggingInterceptor<T>
dans Program.cs
. Si plusieurs instances IHttpLoggingInterceptor
sont inscrites, elles sont exécutées dans l’ordre dans lequel elles ont été enregistrées.
L'exemple suivant montre comment enregistrer une implémentation IHttpLoggingInterceptor
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.Duration;
});
builder.Services.AddHttpLoggingInterceptor<SampleHttpLoggingInterceptor>();
L'exemple suivant est une implémentation IHttpLoggingInterceptor
qui :
- Inspecte la méthode de requête et désactive la journalisation des requêtes POST.
- Pour les requêtes non POST :
- Rédige le chemin de requête, les en-têtes de requête et les en-têtes de réponse.
- Ajoute des champs personnalisés et des valeurs de champ aux journaux de requête et de réponse.
using Microsoft.AspNetCore.HttpLogging;
namespace HttpLoggingSample;
internal sealed class SampleHttpLoggingInterceptor : IHttpLoggingInterceptor
{
public ValueTask OnRequestAsync(HttpLoggingInterceptorContext logContext)
{
if (logContext.HttpContext.Request.Method == "POST")
{
// Don't log anything if the request is a POST.
logContext.LoggingFields = HttpLoggingFields.None;
}
// Don't enrich if we're not going to log any part of the request.
if (!logContext.IsAnyEnabled(HttpLoggingFields.Request))
{
return default;
}
if (logContext.TryDisable(HttpLoggingFields.RequestPath))
{
RedactPath(logContext);
}
if (logContext.TryDisable(HttpLoggingFields.RequestHeaders))
{
RedactRequestHeaders(logContext);
}
EnrichRequest(logContext);
return default;
}
public ValueTask OnResponseAsync(HttpLoggingInterceptorContext logContext)
{
// Don't enrich if we're not going to log any part of the response
if (!logContext.IsAnyEnabled(HttpLoggingFields.Response))
{
return default;
}
if (logContext.TryDisable(HttpLoggingFields.ResponseHeaders))
{
RedactResponseHeaders(logContext);
}
EnrichResponse(logContext);
return default;
}
private void RedactPath(HttpLoggingInterceptorContext logContext)
{
logContext.AddParameter(nameof(logContext.HttpContext.Request.Path), "RedactedPath");
}
private void RedactRequestHeaders(HttpLoggingInterceptorContext logContext)
{
foreach (var header in logContext.HttpContext.Request.Headers)
{
logContext.AddParameter(header.Key, "RedactedHeader");
}
}
private void EnrichRequest(HttpLoggingInterceptorContext logContext)
{
logContext.AddParameter("RequestEnrichment", "Stuff");
}
private void RedactResponseHeaders(HttpLoggingInterceptorContext logContext)
{
foreach (var header in logContext.HttpContext.Response.Headers)
{
logContext.AddParameter(header.Key, "RedactedHeader");
}
}
private void EnrichResponse(HttpLoggingInterceptorContext logContext)
{
logContext.AddParameter("ResponseEnrichment", "Stuff");
}
}
Avec cet intercepteur, une requête POST ne génère aucun journal même si la journalisation HTTP est configurée pour journaliser HttpLoggingFields.All
. Une requête GET génère des journaux similaires à l’exemple suivant :
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1]
Request:
Path: RedactedPath
Accept: RedactedHeader
Host: RedactedHeader
User-Agent: RedactedHeader
Accept-Encoding: RedactedHeader
Accept-Language: RedactedHeader
Upgrade-Insecure-Requests: RedactedHeader
sec-ch-ua: RedactedHeader
sec-ch-ua-mobile: RedactedHeader
sec-ch-ua-platform: RedactedHeader
sec-fetch-site: RedactedHeader
sec-fetch-mode: RedactedHeader
sec-fetch-user: RedactedHeader
sec-fetch-dest: RedactedHeader
RequestEnrichment: Stuff
Protocol: HTTP/2
Method: GET
Scheme: https
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
Response:
Content-Type: RedactedHeader
MyResponseHeader: RedactedHeader
ResponseEnrichment: Stuff
StatusCode: 200
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[4]
ResponseBody: Hello World!
info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[8]
Duration: 2.2778ms
Ordre de priorité de la configuration de journalisation
La liste suivante montre l’ordre de priorité pour la configuration de la journalisation :
- Configuration globale à partir de HttpLoggingOptions, définie en appelant AddHttpLogging.
- La configuration spécifique au point de terminaison à partir de l’attribut
[HttpLogging]
ou de la méthode d’extension WithHttpLogging remplace la configuration globale. IHttpLoggingInterceptor
est appelé avec les résultats et peut modifier davantage la configuration par requête.
La journalisation HTTP est un middleware qui journalise des informations sur les requêtes HTTP entrantes et les réponses HTTP. La journalisation HTTP fournit les journaux suivants :
- Informations sur les requêtes HTTP
- Propriétés communes
- En-têtes
- Corps
- Informations de réponse HTTP
La journalisation HTTP est utile dans plusieurs scénarios :
- Enregistrer des informations sur les requêtes entrantes et les réponses.
- Filtrer les parties des requêtes et des réponses à journaliser.
- Filtrage des en-têtes à journaliser.
La journalisation HTTP peut réduire les performances d’une application, en particulier lors de la journalisation des corps de requête et de réponse. Tenez compte de l’impact sur les performances lorsque vous sélectionnez les champs à journaliser. Testez l’impact des propriétés de journalisation sélectionnées sur les performances.
Avertissement
La journalisation HTTP peut potentiellement journaliser des informations d’identification personnelle. Tenez compte des risques, et évitez de journaliser des informations sensibles.
Activation de la journalisation HTTP
La journalisation HTTP est activée avec UseHttpLogging, qui ajoute un middleware de journalisation HTTP.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpLogging();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.MapGet("/", () => "Hello World!");
app.Run();
Par défaut, la journalisation HTTP journalise les propriétés courantes telles que le chemin, le code d’état et les en-têtes des requêtes et des réponses. Ajoutez la ligne suivante au fichier appsettings.Development.json
au niveau "LogLevel": {
afin que les journaux HTTP soient affichés :
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
La sortie est journalisée en tant que message unique au niveau LogLevel.Information
.
Options de journalisation HTTP
Pour configurer le middleware de journalisation HTTP, appelez AddHttpLogging dans Program.cs
.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Remarque
Dans l’exemple précédent et les exemples suivants, UseHttpLogging
est appelé après UseStaticFiles
, la journalisation HTTP n’est donc pas activée pour le fichier statique. Pour activer la journalisation HTTP de fichier statique, appelez UseHttpLogging
avant UseStaticFiles
.
LoggingFields
HttpLoggingOptions.LoggingFields
est un indicateur d’énumération qui configure certaines parties de la requête et de la réponse à journaliser. HttpLoggingOptions.LoggingFields
a la valeur par défaut RequestPropertiesAndHeaders | ResponsePropertiesAndHeaders.
RequestHeaders
Headers sont un ensemble d’en-têtes de requête HTTP autorisés à être journalisés. Les valeurs d’en-tête sont journalisées uniquement pour les noms d’en-tête qui se trouvent dans cette collection. Le code suivant journalise l’en-tête de requête "sec-ch-ua"
. Si logging.RequestHeaders.Add("sec-ch-ua");
est supprimé, la valeur de l’en-tête de requête "sec-ch-ua"
sera supprimée. Le code mis en évidence ci-dessous appelle HttpLoggingOptions.RequestHeaders
et HttpLoggingOptions.ResponseHeaders
:
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
MediaTypeOptions
MediaTypeOptions fournit la configuration permettant de sélectionner l’encodage à utiliser pour un type de média spécifique.
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();
Cette approche peut également être utilisée pour activer la journalisation des données qui ne sont pas journalisées par défaut. Par exemple, les données de formulaire, qui peuvent avoir un type de média tel que application/x-www-form-urlencoded
ou multipart/form-data
.
Méthodes MediaTypeOptions
RequestBodyLogLimit
et ResponseBodyLogLimit
using Microsoft.AspNetCore.HttpLogging;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpLogging(logging =>
{
logging.LoggingFields = HttpLoggingFields.All;
logging.RequestHeaders.Add("sec-ch-ua");
logging.ResponseHeaders.Add("MyResponseHeader");
logging.MediaTypeOptions.AddText("application/javascript");
logging.RequestBodyLogLimit = 4096;
logging.ResponseBodyLogLimit = 4096;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
context.Response.Headers["MyResponseHeader"] =
new string[] { "My Response Header Value" };
await next();
});
app.MapGet("/", () => "Hello World!");
app.Run();