Add LoggingConnectionFilter.
This commit is contained in:
parent
307e020703
commit
1c40548928
|
|
@ -8,7 +8,7 @@ using Microsoft.AspNet.Builder;
|
|||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Server.Kestrel;
|
||||
using Microsoft.AspNet.Server.Kestrel.Https;
|
||||
using Microsoft.AspNet.Server.Kestrel.Filter;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
|
|
@ -39,6 +39,8 @@ namespace SampleApp
|
|||
Console.WriteLine("Could not find certificate at '{0}'. HTTPS is not enabled.", testCertPath);
|
||||
}
|
||||
|
||||
app.UseKestrelConnectionLogging();
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
Console.WriteLine("{0} {1}{2}{3}",
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Server.Kestrel.Filter;
|
||||
using Microsoft.AspNet.Server.Kestrel.Https;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Https
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Filter
|
||||
{
|
||||
public static class HttpsApplicationBuilderExtensions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
// 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 System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Filter
|
||||
{
|
||||
public class LoggingConnectionFilter : IConnectionFilter
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IConnectionFilter _previous;
|
||||
|
||||
public LoggingConnectionFilter(ILogger logger, IConnectionFilter previous)
|
||||
{
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
if (previous == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(previous));
|
||||
}
|
||||
|
||||
_logger = logger;
|
||||
_previous = previous;
|
||||
}
|
||||
|
||||
public async Task OnConnection(ConnectionFilterContext context)
|
||||
{
|
||||
await _previous.OnConnection(context);
|
||||
|
||||
context.Connection = new LoggingStream(context.Connection, _logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Filter
|
||||
{
|
||||
public static class LoggingFilterApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Emits verbose logs for bytes read from and written to the connection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseKestrelConnectionLogging(this IApplicationBuilder app)
|
||||
{
|
||||
return app.UseKestrelConnectionLogging(nameof(LoggingConnectionFilter));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emits verbose logs for bytes read from and written to the connection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseKestrelConnectionLogging(this IApplicationBuilder app, string loggerName)
|
||||
{
|
||||
var serverInfo = app.ServerFeatures.Get<IKestrelServerInformation>();
|
||||
if (serverInfo != null)
|
||||
{
|
||||
var prevFilter = serverInfo.ConnectionFilter ?? new NoOpConnectionFilter();
|
||||
var loggerFactory = app.ApplicationServices.GetRequiredService<ILoggerFactory>();
|
||||
var logger = loggerFactory.CreateLogger(loggerName ?? nameof(LoggingConnectionFilter));
|
||||
serverInfo.ConnectionFilter = new LoggingConnectionFilter(logger, prevFilter);
|
||||
}
|
||||
return app;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// 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 System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Filter
|
||||
{
|
||||
internal class LoggingStream : Stream
|
||||
{
|
||||
private readonly Stream _inner;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LoggingStream(Stream inner, ILogger logger)
|
||||
{
|
||||
_inner = inner;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inner.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inner.CanSeek;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inner.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inner.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inner.Position;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_inner.Position = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
_inner.Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int read = _inner.Read(buffer, offset, count);
|
||||
Log("Read", read, buffer, offset);
|
||||
return read;
|
||||
}
|
||||
|
||||
public async override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
int read = await _inner.ReadAsync(buffer, offset, count, cancellationToken);
|
||||
Log("ReadAsync", read, buffer, offset);
|
||||
return read;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return _inner.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
_inner.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
Log("Write", count, buffer, offset);
|
||||
_inner.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
Log("WriteAsync", count, buffer, offset);
|
||||
return _inner.WriteAsync(buffer, offset, count, cancellationToken);
|
||||
}
|
||||
|
||||
private void Log(string method, int count, byte[] buffer, int offset)
|
||||
{
|
||||
var builder = new StringBuilder($"{method}[{count}] ");
|
||||
|
||||
// Write the hex
|
||||
for (int i = offset; i < offset + count; i++)
|
||||
{
|
||||
builder.Append(buffer[i].ToString("X2"));
|
||||
builder.Append(" ");
|
||||
}
|
||||
builder.AppendLine();
|
||||
// Write the bytes as if they were ASCII
|
||||
for (int i = offset; i < offset + count; i++)
|
||||
{
|
||||
builder.Append((char)buffer[i]);
|
||||
}
|
||||
|
||||
_logger.LogVerbose(builder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue