diff --git a/backend/src/Squidex.Infrastructure/Commands/LogCommandMiddleware.cs b/backend/src/Squidex.Infrastructure/Commands/LogCommandMiddleware.cs index 2e0b0538d..93955e58a 100644 --- a/backend/src/Squidex.Infrastructure/Commands/LogCommandMiddleware.cs +++ b/backend/src/Squidex.Infrastructure/Commands/LogCommandMiddleware.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Logging; namespace Squidex.Infrastructure.Commands; -public sealed class LogCommandMiddleware(ILogger log) : ICommandMiddleware +public sealed partial class LogCommandMiddleware(ILogger log) : ICommandMiddleware { public async Task HandleAsync(CommandContext context, NextDelegate next, CancellationToken ct) @@ -20,7 +20,7 @@ public sealed class LogCommandMiddleware(ILogger log) : IC { if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug("Command {command} with ID {id} started.", type, context.ContextId); + LogCommandStarted(log, type, context.ContextId); } var watch = ValueStopwatch.StartNew(); @@ -28,22 +28,37 @@ public sealed class LogCommandMiddleware(ILogger log) : IC { await next(context, ct); - log.LogInformation("Command {command} with ID {id} succeeded.", type, context.ContextId); + LogCommandSucceeded(log, type, context.ContextId); } finally { - log.LogInformation("Command {command} with ID {id} completed after {time}ms.", type, context.ContextId, watch.Stop()); + LogCommandCompleted(log, type, context.ContextId, watch.Stop()); } } catch (Exception ex) { - log.LogError(ex, "Command {command} with ID {id} failed.", type, context.ContextId); + LogCommandFailed(log, type, context.ContextId, ex); throw; } if (!context.IsCompleted) { - log.LogCritical("Command {command} with ID {id} not handled.", type, context.ContextId); + LogCommandNotHandled(log, type, context.ContextId); } } + + [LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = "Command {command} with ID {id} started.")] + private static partial void LogCommandStarted(ILogger logger, Type command, Guid id); + + [LoggerMessage(EventId = 2, Level = LogLevel.Information, Message = "Command {command} with ID {id} succeeded.")] + private static partial void LogCommandSucceeded(ILogger logger, Type command, Guid id); + + [LoggerMessage(EventId = 3, Level = LogLevel.Information, Message = "Command {command} with ID {id} completed after {time}ms.")] + private static partial void LogCommandCompleted(ILogger logger, Type command, Guid id, long time); + + [LoggerMessage(EventId = 4, Level = LogLevel.Error, Message = "Command {command} with ID {id} failed.")] + private static partial void LogCommandFailed(ILogger logger, Type command, Guid id, Exception exception); + + [LoggerMessage(EventId = 5, Level = LogLevel.Critical, Message = "Command {command} with ID {id} not handled.")] + private static partial void LogCommandNotHandled(ILogger logger, Type command, Guid id); } diff --git a/backend/src/Squidex.Infrastructure/EventSourcing/Consume/EventConsumerProcessor.cs b/backend/src/Squidex.Infrastructure/EventSourcing/Consume/EventConsumerProcessor.cs index 66e3db23d..71430b460 100644 --- a/backend/src/Squidex.Infrastructure/EventSourcing/Consume/EventConsumerProcessor.cs +++ b/backend/src/Squidex.Infrastructure/EventSourcing/Consume/EventConsumerProcessor.cs @@ -13,7 +13,7 @@ using Squidex.Infrastructure.Tasks; namespace Squidex.Infrastructure.EventSourcing.Consume; -public class EventConsumerProcessor : IEventSubscriber +public partial class EventConsumerProcessor : IEventSubscriber { private readonly SimpleState state; private readonly IEventFormatter eventFormatter; @@ -69,7 +69,7 @@ public class EventConsumerProcessor : IEventSubscriber } catch (Exception ex) { - log.LogCritical(ex, "Failed to complete consumer."); + LogFailedToCompleteConsumer(log, ex); } } @@ -107,7 +107,7 @@ public class EventConsumerProcessor : IEventSubscriber if (logWindow.CanRetryAfterFailure()) { - log.LogError(exception, "Failed to handle event."); + LogFailedToHandleEvent(log, exception); } }, State.Position); } @@ -215,8 +215,7 @@ public class EventConsumerProcessor : IEventSubscriber ex = new AggregateException(ex, unsubscribeException); } - log.LogCritical(ex, "Failed to update consumer {consumer} at position {position} from {caller}.", - eventConsumer.Name, position, caller); + LogFailedToUpdateConsumer(log, eventConsumer.Name, position, caller, ex); State = previousState.Stopped(ex); } @@ -233,7 +232,7 @@ public class EventConsumerProcessor : IEventSubscriber { if (log.IsEnabled(LogLevel.Debug)) { - log.LogDebug("Event consumer {consumer} reset started", eventConsumer.Name); + LogEventConsumerResetStarted(log, eventConsumer.Name); } var watch = ValueStopwatch.StartNew(); @@ -243,7 +242,7 @@ public class EventConsumerProcessor : IEventSubscriber } finally { - log.LogDebug("Event consumer {consumer} reset completed after {time}ms.", eventConsumer.Name, watch.Stop()); + LogEventConsumerResetCompleted(log, eventConsumer.Name, watch.Stop()); } } @@ -282,4 +281,19 @@ public class EventConsumerProcessor : IEventSubscriber { return eventStore.CreateSubscription(subscriber, eventConsumer.EventsFilter, State.Position); } + + [LoggerMessage(EventId = 1, Level = LogLevel.Critical, Message = "Failed to complete consumer.")] + private static partial void LogFailedToCompleteConsumer(ILogger logger, Exception exception); + + [LoggerMessage(EventId = 2, Level = LogLevel.Error, Message = "Failed to handle event.")] + private static partial void LogFailedToHandleEvent(ILogger logger, Exception exception); + + [LoggerMessage(EventId = 3, Level = LogLevel.Critical, Message = "Failed to update consumer {consumer} at position {position} from {caller}.")] + private static partial void LogFailedToUpdateConsumer(ILogger logger, string consumer, string? position, string? caller, Exception exception); + + [LoggerMessage(EventId = 4, Level = LogLevel.Debug, Message = "Event consumer {consumer} reset started")] + private static partial void LogEventConsumerResetStarted(ILogger logger, string consumer); + + [LoggerMessage(EventId = 5, Level = LogLevel.Debug, Message = "Event consumer {consumer} reset completed after {time}ms.")] + private static partial void LogEventConsumerResetCompleted(ILogger logger, string consumer, long time); } diff --git a/backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs b/backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs index c472ab44e..6708076c9 100644 --- a/backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs +++ b/backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs @@ -13,7 +13,7 @@ using Squidex.Infrastructure.Timers; namespace Squidex.Infrastructure.Log; -public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore +public sealed partial class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore { private readonly IRequestLogRepository logRepository; private readonly ILogger log; @@ -88,7 +88,7 @@ public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLo } catch (Exception ex) { - log.LogError(ex, "Failed to track usage in background."); + LogTrackUsageFailed(log, ex); } finally { @@ -127,4 +127,7 @@ public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLo return Task.CompletedTask; } + + [LoggerMessage(EventId = 1, Level = LogLevel.Error, Message = "Failed to track usage in background.")] + private static partial void LogTrackUsageFailed(ILogger logger, Exception exception); } diff --git a/backend/src/Squidex.Infrastructure/Migrations/Migrator.cs b/backend/src/Squidex.Infrastructure/Migrations/Migrator.cs index 076b36cf1..efc19cb77 100644 --- a/backend/src/Squidex.Infrastructure/Migrations/Migrator.cs +++ b/backend/src/Squidex.Infrastructure/Migrations/Migrator.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Logging; namespace Squidex.Infrastructure.Migrations; -public sealed class Migrator( +public sealed partial class Migrator( IMigrationStatus migrationStatus, IMigrationPath migrationPath, ILogger log) @@ -41,7 +41,7 @@ public sealed class Migrator( { var name = migration.ToString()!; - log.LogInformation("Migration {migration} started.", name); + LogMigrationStarted(log, name); try { @@ -49,11 +49,11 @@ public sealed class Migrator( await migration.UpdateAsync(ct); - log.LogInformation("Migration {migration} completed after {time}ms.", name, watch.Stop()); + LogMigrationCompleted(log, name, watch.Stop()); } catch (Exception ex) { - log.LogCritical(ex, "Migration {migration} failed.", name); + LogMigrationFailed(log, name, ex); throw new MigrationFailedException(name, ex); } } @@ -76,7 +76,7 @@ public sealed class Migrator( { while (!await migrationStatus.TryLockAsync(ct)) { - log.LogInformation("Could not acquire lock to start migrating. Trying again in {time}ms.", LockWaitMs); + LogMigrationLockRetry(log, LockWaitMs); await Task.Delay(LockWaitMs, ct); } } @@ -92,4 +92,16 @@ public sealed class Migrator( { return migrationStatus.UnlockAsync(); } + + [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "Migration {migration} started.")] + private static partial void LogMigrationStarted(ILogger logger, string migration); + + [LoggerMessage(EventId = 2, Level = LogLevel.Information, Message = "Migration {migration} completed after {time}ms.")] + private static partial void LogMigrationCompleted(ILogger logger, string migration, long time); + + [LoggerMessage(EventId = 3, Level = LogLevel.Critical, Message = "Migration {migration} failed.")] + private static partial void LogMigrationFailed(ILogger logger, string migration, Exception exception); + + [LoggerMessage(EventId = 4, Level = LogLevel.Information, Message = "Could not acquire lock to start migrating. Trying again in {time}ms.")] + private static partial void LogMigrationLockRetry(ILogger logger, int time); } diff --git a/backend/src/Squidex.Web/Pipeline/RequestExceptionMiddleware.cs b/backend/src/Squidex.Web/Pipeline/RequestExceptionMiddleware.cs index c099f8080..c44607953 100644 --- a/backend/src/Squidex.Web/Pipeline/RequestExceptionMiddleware.cs +++ b/backend/src/Squidex.Web/Pipeline/RequestExceptionMiddleware.cs @@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging; namespace Squidex.Web.Pipeline; -public sealed class RequestExceptionMiddleware(RequestDelegate next) +public sealed partial class RequestExceptionMiddleware(RequestDelegate next) { private static readonly ActionDescriptor EmptyActionDescriptor = new ActionDescriptor(); private static readonly RouteData EmptyRouteData = new RouteData(); @@ -37,7 +37,7 @@ public sealed class RequestExceptionMiddleware(RequestDelegate next) } catch (Exception ex) { - log.LogError(ex, "An unexpected exception has occurred."); + LogUnexpectedException(log, ex); if (!context.Response.HasStarted) { @@ -77,4 +77,7 @@ public sealed class RequestExceptionMiddleware(RequestDelegate next) { return statusCode is >= 400 and < 600; } + + [LoggerMessage(EventId = 1, Level = LogLevel.Error, Message = "An unexpected exception has occurred.")] + private static partial void LogUnexpectedException(ILogger logger, Exception exception); }