Skip to content

Use LoggerMessage in HttpAbstractions #33927

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 3 commits into from
Jul 8, 2021
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
42 changes: 29 additions & 13 deletions src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Builder;
Expand All @@ -18,18 +19,19 @@

namespace Microsoft.AspNetCore.Hosting
{
internal class GenericWebHostService : IHostedService
internal sealed partial class GenericWebHostService : IHostedService
{
public GenericWebHostService(IOptions<GenericWebHostServiceOptions> options,
IServer server,
ILoggerFactory loggerFactory,
DiagnosticListener diagnosticListener,
ActivitySource activitySource,
IHttpContextFactory httpContextFactory,
IApplicationBuilderFactory applicationBuilderFactory,
IEnumerable<IStartupFilter> startupFilters,
IConfiguration configuration,
IWebHostEnvironment hostingEnvironment)
public GenericWebHostService(
IOptions<GenericWebHostServiceOptions> options,
IServer server,
ILoggerFactory loggerFactory,
DiagnosticListener diagnosticListener,
ActivitySource activitySource,
IHttpContextFactory httpContextFactory,
IApplicationBuilderFactory applicationBuilderFactory,
IEnumerable<IStartupFilter> startupFilters,
IConfiguration configuration,
IWebHostEnvironment hostingEnvironment)
{
Options = options.Value;
Server = server;
Expand Down Expand Up @@ -122,15 +124,15 @@ public async Task StartAsync(CancellationToken cancellationToken)
{
foreach (var address in addresses)
{
LifetimeLogger.ListeningOnAddress(address);
Log.ListeningOnAddress(LifetimeLogger, address);
}
}

if (Logger.IsEnabled(LogLevel.Debug))
{
foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies())
{
Logger.StartupAssemblyLoaded(assembly);
Log.StartupAssemblyLoaded(Logger, assembly);
}
}

Expand All @@ -154,5 +156,19 @@ public async Task StopAsync(CancellationToken cancellationToken)
HostingEventSource.Log.HostStop();
}
}

private static partial class Log
{
[LoggerMessage(14, LogLevel.Information,
"Now listening on: {address}",
EventName = "ListeningOnAddress")]
public static partial void ListeningOnAddress(ILogger logger, string address);

[LoggerMessage(13, LogLevel.Debug,
"Loaded hosting startup assembly {assemblyName}",
EventName = "HostingStartupAssemblyLoaded",
SkipEnabledCheck = true)]
public static partial void StartupAssemblyLoaded(ILogger logger, string assemblyName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Web;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -87,7 +90,7 @@ public void BeginRequest(HttpContext httpContext, HostingApplication.Context con
// Scope may be relevant for a different level of logging, so we always create it
// see: https://github.com/aspnet/Hosting/pull/944
// Scope can be null if logging is not on.
context.Scope = _logger.RequestScope(httpContext);
context.Scope = Log.RequestScope(_logger, httpContext);

if (_logger.IsEnabled(LogLevel.Information))
{
Expand Down Expand Up @@ -359,5 +362,75 @@ private void StopActivity(Activity activity, HttpContext httpContext)
_diagnosticListener.Write(ActivityStopKey, httpContext);
activity.Stop(); // Resets Activity.Current (we want this after the Write)
}

private static class Log
{
public static IDisposable RequestScope(ILogger logger, HttpContext httpContext)
{
return logger.BeginScope(new HostingLogScope(httpContext));
}

private sealed class HostingLogScope : IReadOnlyList<KeyValuePair<string, object>>
{
private readonly string _path;
private readonly string _traceIdentifier;

private string? _cachedToString;

public int Count => 2;

public KeyValuePair<string, object> this[int index]
{
get
{
if (index == 0)
{
return new KeyValuePair<string, object>("RequestId", _traceIdentifier);
}
else if (index == 1)
{
return new KeyValuePair<string, object>("RequestPath", _path);
}

throw new ArgumentOutOfRangeException(nameof(index));
}
}

public HostingLogScope(HttpContext httpContext)
{
_traceIdentifier = httpContext.TraceIdentifier;
_path = (httpContext.Request.PathBase.HasValue
? httpContext.Request.PathBase + httpContext.Request.Path
: httpContext.Request.Path).ToString();
}

public override string ToString()
{
if (_cachedToString == null)
{
_cachedToString = string.Format(
CultureInfo.InvariantCulture,
"RequestPath:{0} RequestId:{1}",
_path,
_traceIdentifier);
}

return _cachedToString;
}

public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
for (var i = 0; i < Count; ++i)
{
yield return this[i];
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}
}
137 changes: 1 addition & 136 deletions src/Hosting/Hosting/src/Internal/HostingLoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace Microsoft.AspNetCore.Hosting
{
internal static class HostingLoggerExtensions
{
private static readonly Action<ILogger, string, Exception?> _startupAssemblyLoaded =
LoggerMessage.Define<string>(LogLevel.Debug, LoggerEventIds.HostingStartupAssemblyLoaded, "Loaded hosting startup assembly {assemblyName}", skipEnabledCheck: true);

private static readonly Action<ILogger, string, Exception?> _listeningOnAddress =
LoggerMessage.Define<string>(LogLevel.Information, LoggerEventIds.ServerListeningOnAddresses, "Now listening on: {address}");

public static IDisposable RequestScope(this ILogger logger, HttpContext httpContext)
{
return logger.BeginScope(new HostingLogScope(httpContext));
}

public static void ListeningOnAddress(this ILogger logger, string address)
{
_listeningOnAddress(logger, address, null);
}

public static void StartupAssemblyLoaded(this ILogger logger, string assemblyName)
{
_startupAssemblyLoaded(logger, assemblyName, null);
}

public static void ApplicationError(this ILogger logger, Exception exception)
{
logger.ApplicationError(
Expand All @@ -52,8 +27,7 @@ public static void HostingStartupAssemblyError(this ILogger logger, Exception ex

public static void ApplicationError(this ILogger logger, EventId eventId, string message, Exception exception)
{
var reflectionTypeLoadException = exception as ReflectionTypeLoadException;
if (reflectionTypeLoadException != null)
if (exception is ReflectionTypeLoadException reflectionTypeLoadException)
{
foreach (var ex in reflectionTypeLoadException.LoaderExceptions)
{
Expand All @@ -69,115 +43,6 @@ public static void ApplicationError(this ILogger logger, EventId eventId, string
message: message,
exception: exception);
}

public static void Starting(this ILogger logger)
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug(
eventId: LoggerEventIds.Starting,
message: "Hosting starting");
}
}

public static void Started(this ILogger logger)
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug(
eventId: LoggerEventIds.Started,
message: "Hosting started");
}
}

public static void Shutdown(this ILogger logger)
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug(
eventId: LoggerEventIds.Shutdown,
message: "Hosting shutdown");
}
}

public static void ServerShutdownException(this ILogger logger, Exception ex)
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug(
eventId: LoggerEventIds.ServerShutdownException,
exception: ex,
message: "Server shutdown exception");
}
}

private class HostingLogScope : IReadOnlyList<KeyValuePair<string, object>>
{
private readonly string _path;
private readonly string _traceIdentifier;

private string? _cachedToString;

public int Count
{
get
{
return 2;
}
}

public KeyValuePair<string, object> this[int index]
{
get
{
if (index == 0)
{
return new KeyValuePair<string, object>("RequestId", _traceIdentifier);
}
else if (index == 1)
{
return new KeyValuePair<string, object>("RequestPath", _path);
}

throw new ArgumentOutOfRangeException(nameof(index));
}
}

public HostingLogScope(HttpContext httpContext)
{
_traceIdentifier = httpContext.TraceIdentifier;
_path = (httpContext.Request.PathBase.HasValue
? httpContext.Request.PathBase + httpContext.Request.Path
: httpContext.Request.Path).ToString();
}

public override string ToString()
{
if (_cachedToString == null)
{
_cachedToString = string.Format(
CultureInfo.InvariantCulture,
"RequestPath:{0} RequestId:{1}",
_path,
_traceIdentifier);
}

return _cachedToString;
}

public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
for (int i = 0; i < Count; ++i)
{
yield return this[i];
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}

29 changes: 14 additions & 15 deletions src/Hosting/Hosting/src/Internal/LoggerEventIds.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Logging;

namespace Microsoft.AspNetCore.Hosting
{
internal static class LoggerEventIds
{
public static readonly EventId RequestStarting = new EventId(1, "RequestStarting");
public static readonly EventId RequestFinished = new EventId(2, "RequestFinished");
public static readonly EventId Starting = new EventId(3, "Starting");
public static readonly EventId Started = new EventId(4, "Started");
public static readonly EventId Shutdown = new EventId(5, "Shutdown");
public static readonly EventId ApplicationStartupException = new EventId(6, "ApplicationStartupException");
public static readonly EventId ApplicationStoppingException = new EventId(7, "ApplicationStoppingException");
public static readonly EventId ApplicationStoppedException = new EventId(8, "ApplicationStoppedException");
public static readonly EventId HostedServiceStartException = new EventId(9, "HostedServiceStartException");
public static readonly EventId HostedServiceStopException = new EventId(10, "HostedServiceStopException");
public static readonly EventId HostingStartupAssemblyException = new EventId(11, "HostingStartupAssemblyException");
public static readonly EventId ServerShutdownException = new EventId(12, "ServerShutdownException");
public static readonly EventId HostingStartupAssemblyLoaded = new EventId(13, "HostingStartupAssemblyLoaded");
public static readonly EventId ServerListeningOnAddresses = new EventId(14, "ServerListeningOnAddresses");
public const int RequestStarting = 1;
public const int RequestFinished = 2;
public const int Starting = 3;
public const int Started = 4;
public const int Shutdown = 5;
public const int ApplicationStartupException = 6;
public const int ApplicationStoppingException = 7;
public const int ApplicationStoppedException = 8;
public const int HostedServiceStartException = 9;
public const int HostedServiceStopException = 10;
public const int HostingStartupAssemblyException = 11;
public const int ServerShutdownException = 12;
public const int HostingStartupAssemblyLoaded = 13;
public const int ServerListeningOnAddresses = 14;
}
}
Loading