From c10b3accbaf60f3f880c578cbd320d7db01fde52 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 29 Nov 2021 20:45:24 +0100 Subject: [PATCH] Improved logging and proper scripting initializer. --- .../Scripting/JintScriptEngine.cs | 2 +- .../Orleans/LoggingFilter.cs | 22 ++++++-- .../src/Squidex.Web/ApiExceptionConverter.cs | 55 +++++++++++++------ .../ApiExceptionFilterAttribute.cs | 6 +- .../Config/Domain/InfrastructureServices.cs | 3 - 5 files changed, 58 insertions(+), 30 deletions(-) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs index cd381a5a6..ad25e3fee 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs @@ -230,7 +230,7 @@ namespace Squidex.Domain.Apps.Core.Scripting } catch (Exception ex) { - throw new ValidationException(T.Get("common.jsError", new { message = ex.ToString() })); + throw new ValidationException(T.Get("common.jsError", new { message = ex.GetType().Name }), ex); } } } diff --git a/backend/src/Squidex.Infrastructure/Orleans/LoggingFilter.cs b/backend/src/Squidex.Infrastructure/Orleans/LoggingFilter.cs index d38ad71f0..23d9258c0 100644 --- a/backend/src/Squidex.Infrastructure/Orleans/LoggingFilter.cs +++ b/backend/src/Squidex.Infrastructure/Orleans/LoggingFilter.cs @@ -25,20 +25,30 @@ namespace Squidex.Infrastructure.Orleans { await context.Invoke(); } - catch (DomainException) + catch (DomainException ex) { + if (ex.InnerException != null) + { + Log(context, ex.InnerException); + } + throw; } catch (Exception ex) { - log.LogError(ex, w => w - .WriteProperty("action", "GrainInvoked") - .WriteProperty("status", "Failed") - .WriteProperty("grain", context.Grain.ToString()) - .WriteProperty("grainMethod", context.ImplementationMethod.ToString())); + Log(context, ex); throw; } } + + private void Log(IIncomingGrainCallContext context, Exception ex) + { + log.LogError(ex, w => w + .WriteProperty("action", "GrainInvoked") + .WriteProperty("status", "Failed") + .WriteProperty("grain", context.Grain.ToString()) + .WriteProperty("grainMethod", context.ImplementationMethod.ToString())); + } } } diff --git a/backend/src/Squidex.Web/ApiExceptionConverter.cs b/backend/src/Squidex.Web/ApiExceptionConverter.cs index 7bcba509a..304ffb462 100644 --- a/backend/src/Squidex.Web/ApiExceptionConverter.cs +++ b/backend/src/Squidex.Web/ApiExceptionConverter.cs @@ -33,16 +33,16 @@ namespace Squidex.Web [500] = "https://tools.ietf.org/html/rfc7231#section-6.6.1" }; - public static (ErrorDto Error, bool WellKnown) ToErrorDto(int statusCode, HttpContext? httpContext) + public static (ErrorDto Error, Exception? Unhandled) ToErrorDto(int statusCode, HttpContext? httpContext) { var error = new ErrorDto { StatusCode = statusCode }; Enrich(httpContext, error); - return (error, true); + return (error, null); } - public static (ErrorDto Error, bool WellKnown) ToErrorDto(this ProblemDetails problem, HttpContext? httpContext) + public static (ErrorDto Error, Exception? Unhandled) ToErrorDto(this ProblemDetails problem, HttpContext? httpContext) { Guard.NotNull(problem, nameof(problem)); @@ -50,10 +50,10 @@ namespace Squidex.Web Enrich(httpContext, error); - return (error, true); + return (error, null); } - public static (ErrorDto Error, bool WellKnown) ToErrorDto(this Exception exception, HttpContext? httpContext) + public static (ErrorDto Error, Exception? Unhandled) ToErrorDto(this Exception exception, HttpContext? httpContext) { Guard.NotNull(exception, nameof(exception)); @@ -76,45 +76,66 @@ namespace Squidex.Web error.Type = Links.GetOrDefault(error.StatusCode); } - private static (ErrorDto Error, bool WellKnown) CreateError(Exception exception) + private static (ErrorDto Error, Exception? Unhandled) CreateError(Exception exception) { switch (exception) { case ValidationException ex: - return (CreateError(400, T.Get("common.httpValidationError"), null, ToErrors(ex.Errors)), true); + { + var message = T.Get("common.httpValidationError"); + + return (CreateError(400, message, null, ToErrors(ex.Errors)), GetInner(exception)); + } case DomainObjectNotFoundException ex: - return (CreateError(404, ex.ErrorCode), true); + return (CreateError(404, ex.ErrorCode), GetInner(exception)); case DomainObjectVersionException ex: - return (CreateError(412, ex.Message, ex.ErrorCode), true); + return (CreateError(412, ex.Message, ex.ErrorCode), GetInner(exception)); case DomainObjectDeletedException ex: - return (CreateError(410, ex.Message, ex.ErrorCode), true); + return (CreateError(410, ex.Message, ex.ErrorCode), GetInner(exception)); case DomainObjectConflictException ex: - return (CreateError(409, ex.Message, ex.ErrorCode), true); + return (CreateError(409, ex.Message, ex.ErrorCode), GetInner(exception)); case DomainForbiddenException ex: - return (CreateError(403, ex.Message, ex.ErrorCode), true); + return (CreateError(403, ex.Message, ex.ErrorCode), GetInner(exception)); case DomainException ex: - return (CreateError(400, ex.Message, ex.ErrorCode), true); + return (CreateError(400, ex.Message, ex.ErrorCode), GetInner(exception)); case SecurityException: - return (CreateError(403), false); + return (CreateError(403), exception); case DecoderFallbackException ex: - return (CreateError(400, ex.Message), true); + return (CreateError(400, ex.Message), null); case BadHttpRequestException ex: - return (CreateError(ex.StatusCode, ex.Message), true); + return (CreateError(ex.StatusCode, ex.Message), null); default: - return (CreateError(500), false); + return (CreateError(500), exception); } } + private static Exception? GetInner(Exception exception) + { + var current = exception; + + while (current != null) + { + if (current is not DomainException) + { + return current; + } + + current = current.InnerException; + } + + return null; + } + private static ErrorDto CreateError(int status, string? message = null, string? errorCode = null, IEnumerable? details = null) { var error = new ErrorDto { StatusCode = status, Message = message }; diff --git a/backend/src/Squidex.Web/ApiExceptionFilterAttribute.cs b/backend/src/Squidex.Web/ApiExceptionFilterAttribute.cs index 894e45dcf..9a7b6d2c4 100644 --- a/backend/src/Squidex.Web/ApiExceptionFilterAttribute.cs +++ b/backend/src/Squidex.Web/ApiExceptionFilterAttribute.cs @@ -28,13 +28,13 @@ namespace Squidex.Web public void OnException(ExceptionContext context) { - var (error, wellKnown) = context.Exception.ToErrorDto(context.HttpContext); + var (error, unhandled) = context.Exception.ToErrorDto(context.HttpContext); - if (!wellKnown) + if (unhandled != null) { var log = context.HttpContext.RequestServices.GetRequiredService(); - log.LogError(context.Exception, w => w + log.LogError(unhandled, w => w .WriteProperty("message", "An unexpected exception has occurred.")); } diff --git a/backend/src/Squidex/Config/Domain/InfrastructureServices.cs b/backend/src/Squidex/Config/Domain/InfrastructureServices.cs index a45549ef3..10e724ba7 100644 --- a/backend/src/Squidex/Config/Domain/InfrastructureServices.cs +++ b/backend/src/Squidex/Config/Domain/InfrastructureServices.cs @@ -72,9 +72,6 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); - services.AddSingletonAs() - .AsOptional(); - services.AddSingletonAs() .As();