Skip to content
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

[CORELIB-75] DI injected logger #757

Open
wants to merge 4 commits into
base: v9.0-preview
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ dotnet_diagnostic.CA1032.severity = none
dotnet_diagnostic.CA1034.severity = none
dotnet_diagnostic.CA1019.severity = none
dotnet_diagnostic.CA1308.severity = none
dotnet_diagnostic.CA1848.severity = none
dotnet_diagnostic.IDE0058.severity = none

# Disable temporarily
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
using LeanCode.CQRS.Execution;
using LeanCode.OpenTelemetry;
using Microsoft.AspNetCore.Http;
using Serilog;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.AspNetCore.Middleware;

public class CQRSExceptionTranslationMiddleware
{
private readonly ILogger logger = Log.ForContext<CQRSExceptionTranslationMiddleware>();
private readonly ILogger<CQRSExceptionTranslationMiddleware> logger;
private readonly CQRSMetrics metrics;
private readonly RequestDelegate next;

public CQRSExceptionTranslationMiddleware(CQRSMetrics metrics, RequestDelegate next)
public CQRSExceptionTranslationMiddleware(
ILogger<CQRSExceptionTranslationMiddleware> logger,
CQRSMetrics metrics,
RequestDelegate next
)
{
this.logger = logger;
this.metrics = metrics;
this.next = next;
}
Expand All @@ -40,7 +45,7 @@ public async Task InvokeAsync(HttpContext httpContext)
activity?.SetTag("error.code", ex.ErrorCode);

var result = WrapInCommandResult(ex);
logger.Warning("Command {@Command} is not valid with result {@Result}", cqrsPayload.Payload, result);
logger.LogWarning("Command {@Command} is not valid with result {@Result}", cqrsPayload.Payload, result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is {@Command} syntax an extensions logging standard? I've always though it was a serilog goodie (chat gpt confirms it). So, I sb ever want's to change logger implementation I guess it'd break.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, right in some loggers ToString() might be called here. We probably need to change @Command to Command and pass JsonSerializer.Serialize(cqrsPayload.Payload) as an argument to make it work with any logger.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a good approach. It will break the "sanitizer" logic that we have and we need to support that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I'm not sure if we can do anything about it right now other then making sanitization logger agnostic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if we'd abstract this way from Serilog we'd lose this functionality, which would be sad. Is there a way to not abstract the Serilog, and still use the DI based loggers? If so, I'd say let's go with it (unless it isn't too ugly), and in the other case I'd stick with what we've done until now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If serilog does not provide anything out of the box, I think we can safely register Serilog.ILogger<T> as open generic and link it with DI

var executionResult = ExecutionResult.WithPayload(result, StatusCodes.Status422UnprocessableEntity);
cqrsPayload.SetResult(executionResult);
metrics.CQRSFailure(CQRSMetrics.ValidationFailure);
Expand Down
24 changes: 15 additions & 9 deletions src/CQRS/LeanCode.CQRS.AspNetCore/Middleware/CQRSMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,28 @@
using LeanCode.CQRS.AspNetCore.Serialization;
using LeanCode.CQRS.Execution;
using Microsoft.AspNetCore.Http;
using Serilog;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.AspNetCore.Middleware;

public class CQRSMiddleware
{
private static readonly byte[] NullString = "null"u8.ToArray();

private readonly ILogger logger = Log.ForContext<CQRSMiddleware>();
private readonly ILogger<CQRSMiddleware> logger;

private readonly CQRSMetrics metrics;
private readonly ISerializer serializer;
private readonly RequestDelegate next;

public CQRSMiddleware(CQRSMetrics metrics, ISerializer serializer, RequestDelegate next)
public CQRSMiddleware(
ILogger<CQRSMiddleware> logger,
CQRSMetrics metrics,
ISerializer serializer,
RequestDelegate next
)
{
this.logger = logger;
this.metrics = metrics;
this.serializer = serializer;
this.next = next;
Expand All @@ -37,15 +43,15 @@ public async Task InvokeAsync(HttpContext httpContext)
}
catch (Exception ex)
{
logger.Warning(ex, "Cannot deserialize object body from the request stream for type {Type}", objectType);
logger.LogWarning(ex, "Cannot deserialize object body from the request stream for type {Type}", objectType);
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
metrics.CQRSFailure(CQRSMetrics.SerializationFailure);
return;
}

if (obj is null)
{
logger.Warning("Client sent an empty object for type {Type}, ignoring", objectType);
logger.LogWarning("Client sent an empty object for type {Type}, ignoring", objectType);
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
metrics.CQRSFailure(CQRSMetrics.SerializationFailure);
return;
Expand All @@ -60,11 +66,11 @@ public async Task InvokeAsync(HttpContext httpContext)
}
catch (Exception ex) when (ex is OperationCanceledException || ex.InnerException is OperationCanceledException)
{
logger.Debug(ex, "{ObjectKind} {@Object} cancelled", objectType, obj);
logger.LogDebug(ex, "{ObjectKind} {@Object} cancelled", objectType, obj);
}
catch (Exception ex)
{
logger.Error(ex, "Cannot execute object {@Object} of type {Type}", obj, objectType);
logger.LogError(ex, "Cannot execute object {@Object} of type {Type}", obj, objectType);
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
metrics.CQRSFailure(CQRSMetrics.InternalError);
}
Expand All @@ -76,7 +82,7 @@ private async Task SerializeResultAsync(HttpContext httpContext, CQRSObjectMetad

if (payload.Result is null)
{
logger.Warning("CQRS execution ended with no result");
logger.LogWarning("CQRS execution ended with no result");
metrics.CQRSFailure(CQRSMetrics.InternalError);
return;
}
Expand Down Expand Up @@ -106,7 +112,7 @@ await serializer.SerializeAsync(
{
// assuming that in other cases the middleware itself will log & report appropriate metric
metrics.CQRSSuccess();
logger.Information(
logger.LogInformation(
"{ObjectKind} {@Object} executed successfully",
objectMetadata.ObjectKind,
payload.Payload
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
using LeanCode.CQRS.Security;
using LeanCode.OpenTelemetry;
using Microsoft.AspNetCore.Http;
using Serilog;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.AspNetCore.Middleware;

public class CQRSSecurityMiddleware
{
private readonly CQRSMetrics metrics;
private readonly RequestDelegate next;
private readonly ILogger logger = Log.ForContext<CQRSSecurityMiddleware>();
private readonly ILogger<CQRSSecurityMiddleware> logger;

public CQRSSecurityMiddleware(CQRSMetrics metrics, RequestDelegate next)
public CQRSSecurityMiddleware(CQRSMetrics metrics, RequestDelegate next, ILogger<CQRSSecurityMiddleware> logger)
{
this.metrics = metrics;
this.next = next;
this.logger = logger;
}

public async Task InvokeAsync(HttpContext context)
Expand All @@ -29,7 +30,7 @@ public async Task InvokeAsync(HttpContext context)

if (customAuthorizers.Count > 0 && !(user.Identity?.IsAuthenticated ?? false))
{
logger.Warning(
logger.LogWarning(
"The current user is not authenticated and the object {@Object} requires authorization",
payload.Payload
);
Expand Down Expand Up @@ -58,7 +59,7 @@ public async Task InvokeAsync(HttpContext context)
if (!authorized)
{
activity?.SetTag("authorizer.authorized", false);
logger.Warning(
logger.LogWarning(
"User is not authorized for {@Object}, authorizer {AuthorizerType} did not pass",
payload.Payload,
customAuthorizer.GetType().FullName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
using LeanCode.CQRS.Validation;
using LeanCode.OpenTelemetry;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.AspNetCore.Middleware;

public class CQRSValidationMiddleware
{
private readonly Serilog.ILogger logger = Serilog.Log.ForContext<CQRSValidationMiddleware>();
private readonly ILogger<CQRSValidationMiddleware> logger;

private readonly CQRSMetrics metrics;
private readonly RequestDelegate next;

public CQRSValidationMiddleware(CQRSMetrics metrics, RequestDelegate next)
public CQRSValidationMiddleware(ILogger<CQRSValidationMiddleware> logger, CQRSMetrics metrics, RequestDelegate next)
{
this.logger = logger;
this.metrics = metrics;
this.next = next;
}
Expand All @@ -41,7 +43,7 @@ public async Task InvokeAsync(HttpContext httpContext, ICommandValidatorResolver

if (!result.IsValid)
{
logger.Warning("Command {@Command} is not valid with result {@Result}", payload.Payload, result);
logger.LogWarning("Command {@Command} is not valid with result {@Result}", payload.Payload, result);
var commandResult = CommandResult.NotValid(result);
payload.SetResult(ExecutionResult.WithPayload(commandResult, StatusCodes.Status422UnprocessableEntity));
metrics.CQRSFailure(CQRSMetrics.ValidationFailure);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
using LeanCode.CQRS.Execution;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Serilog;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.AspNetCore.Middleware;

public class NonProductionResponseLoggerMiddleware
{
private readonly ILogger logger;
private readonly ILogger<NonProductionResponseLoggerMiddleware> logger;
private readonly IHostEnvironment environment;

public NonProductionResponseLoggerMiddleware(IHostEnvironment env)
public NonProductionResponseLoggerMiddleware(
ILogger<NonProductionResponseLoggerMiddleware> logger,
IHostEnvironment env
)
{
environment = env;
logger = Log.ForContext<NonProductionResponseLoggerMiddleware>();
}

public NonProductionResponseLoggerMiddleware(IHostEnvironment env, ILogger logger)
{
environment = env;
this.logger = logger;
environment = env;
}

public async Task InvokeAsync(HttpContext httpContext, RequestDelegate next)
Expand All @@ -30,7 +27,7 @@ public async Task InvokeAsync(HttpContext httpContext, RequestDelegate next)

if (!environment.IsProduction())
{
logger.Information("Request executed with response {@Response}", payload.Result);
logger.LogInformation("Request executed with response {@Response}", payload.Result);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
using LeanCode.CQRS.Execution;
using Microsoft.AspNetCore.Http;
using Serilog;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.AspNetCore.Middleware;

public class ResponseLoggerMiddleware
{
private readonly ILogger logger;
private readonly ILogger<ResponseLoggerMiddleware> logger;
private readonly RequestDelegate next;

public ResponseLoggerMiddleware(RequestDelegate next)
public ResponseLoggerMiddleware(ILogger<ResponseLoggerMiddleware> logger, RequestDelegate next)
{
logger = Log.ForContext<ResponseLoggerMiddleware>();

this.logger = logger;
this.next = next;
}

public async Task InvokeAsync(HttpContext httpContext)
{
await next(httpContext);
var result = httpContext.GetCQRSRequestPayload().Result;
logger.Information("Request executed with response {@Response}", result);
logger.LogInformation("Request executed with response {@Response}", result);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
using LeanCode.DomainModels.Model;
using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.MassTransitRelay.Middleware;

public class EventsPublisherMiddleware
{
private readonly Serilog.ILogger logger = Serilog.Log.ForContext<EventsPublisherMiddleware>();
private readonly ILogger<EventsPublisherMiddleware> logger;
private readonly RequestDelegate next;
private readonly AsyncEventsInterceptor interceptor;

public EventsPublisherMiddleware(RequestDelegate next, AsyncEventsInterceptor interceptor)
public EventsPublisherMiddleware(
ILogger<EventsPublisherMiddleware> logger,
RequestDelegate next,
AsyncEventsInterceptor interceptor
)
{
this.logger = logger;
this.next = next;
this.interceptor = interceptor;
}
Expand All @@ -32,7 +38,7 @@ private Task PublishEventsAsync(
CancellationToken cancellationToken
)
{
logger.Debug("Publishing {Count} raised events", events.Count);
logger.LogDebug("Publishing {Count} raised events", events.Count);
var conversationId = Guid.NewGuid();

var publishTasks = events.Select(evt =>
Expand All @@ -49,7 +55,7 @@ private Task PublishEventAsync(
CancellationToken cancellationToken
)
{
logger.Debug("Publishing event of type {DomainEvent}", evt.GetType());
logger.LogDebug("Publishing event of type {DomainEvent}", evt.GetType());
return publishEndpoint.Publish(
(object)evt, // Cast is necessary to publish the event as it's type, not an `IDomainEvent`
publishCtx =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using System.Security.Claims;
using LeanCode.Contracts.Security;
using Microsoft.Extensions.Logging;

namespace LeanCode.CQRS.Security;

public class DefaultPermissionAuthorizer : CustomAuthorizer<object, string[]>, IHasPermissions
{
private readonly Serilog.ILogger logger = Serilog.Log.ForContext<DefaultPermissionAuthorizer>();
private readonly ILogger<DefaultPermissionAuthorizer> logger;

private readonly RoleRegistry registry;

public DefaultPermissionAuthorizer(RoleRegistry registry)
public DefaultPermissionAuthorizer(ILogger<DefaultPermissionAuthorizer> logger, RoleRegistry registry)
{
this.logger = logger;
this.registry = registry;
}

Expand All @@ -23,7 +25,7 @@ CancellationToken cancellationToken
{
if (!user.HasPermission(registry, customData ?? Array.Empty<string>()))
{
logger.Warning(
logger.LogWarning(
"User does not have sufficient permissions ({Permissions}) to run {@Object}",
customData,
obj
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using Serilog;
using Microsoft.Extensions.Logging;

namespace LeanCode.AuditLogs;

public class AzureBlobAuditLogStorage : IAuditLogStorage
{
private const string SuffixKey = "Suffix";
private readonly ILogger logger = Log.ForContext<AzureBlobAuditLogStorage>();
private readonly ILogger<AzureBlobAuditLogStorage> logger;

private static ReadOnlySpan<byte> NewLineBytes => "\n"u8;
private static readonly JsonSerializerOptions Options = new()
Expand All @@ -28,11 +28,13 @@ public class AzureBlobAuditLogStorage : IAuditLogStorage
private readonly AzureBlobAuditLogStorageConfiguration config;

public AzureBlobAuditLogStorage(
ILogger<AzureBlobAuditLogStorage> logger,
BlobServiceClient blobClient,
TableServiceClient tableClient,
AzureBlobAuditLogStorageConfiguration config
)
{
this.logger = logger;
this.blobClient = blobClient;
this.tableClient = tableClient;
this.config = config;
Expand All @@ -57,7 +59,7 @@ private async Task AppendLogToBlobAsync(AuditLogMessage auditLogMessage, Cancell
using var stream = Serialize(auditLogMessage);
await blob.AppendBlockAsync(stream, cancellationToken: cancellationToken);

logger.Verbose("Log append to the blob {BlobName}", blob.Name);
logger.LogDebug("Log append to the blob {BlobName}", blob.Name);
}

private async Task<AppendBlobClient> CreateBlobAsync(
Expand Down
Loading