136 lines
4.3 KiB
C#
136 lines
4.3 KiB
C#
using PostFundManagement.Domain.Attributes;
|
|
|
|
namespace PostFundManagement.Application.Interceptors;
|
|
|
|
public sealed class LoggingInterceptor(ILogger<LoggingInterceptor> logger) : IAsyncInterceptor
|
|
{
|
|
public void InterceptSynchronous(IInvocation invocation)
|
|
{
|
|
invocation.Proceed();
|
|
|
|
CheckAndLogIfFailed(invocation, invocation.ReturnValue);
|
|
}
|
|
|
|
public void InterceptAsynchronous(IInvocation invocation) =>
|
|
invocation.ReturnValue = InternalInterceptAsynchronous(invocation);
|
|
|
|
public void InterceptAsynchronous<TResult>(IInvocation invocation) =>
|
|
invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation);
|
|
|
|
private static async Task InternalInterceptAsynchronous(IInvocation invocation)
|
|
{
|
|
invocation.Proceed();
|
|
|
|
var task = (Task)invocation.ReturnValue;
|
|
|
|
await task.ConfigureAwait(false);
|
|
}
|
|
|
|
private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation)
|
|
{
|
|
invocation.Proceed();
|
|
|
|
var task = (Task<TResult>)invocation.ReturnValue;
|
|
var resultObj = await task.ConfigureAwait(false);
|
|
|
|
var method = invocation.MethodInvocationTarget ?? invocation.Method;
|
|
var auditAttr = method.GetCustomAttribute<LogAttribute>()
|
|
?? invocation.Method.GetCustomAttribute<LogAttribute>();
|
|
|
|
if (auditAttr == null) return resultObj;
|
|
|
|
CheckAndLogIfFailed(invocation, resultObj);
|
|
|
|
return resultObj;
|
|
}
|
|
|
|
private void CheckAndLogIfFailed(IInvocation invocation, object? resultObj)
|
|
{
|
|
if (resultObj is IResultBase result && result.IsFailed)
|
|
{
|
|
try
|
|
{
|
|
var method = invocation.MethodInvocationTarget ?? invocation.Method;
|
|
var parameters = BuildPayloadSummary(method.GetParameters(), invocation.Arguments);
|
|
|
|
var errorMessages = new List<string>();
|
|
|
|
if (result.Reasons != null)
|
|
{
|
|
foreach (var reason in result.Reasons)
|
|
if (reason is IError error)
|
|
errorMessages.Add(error.Message);
|
|
}
|
|
|
|
var errorsString = string.Join("; ", errorMessages);
|
|
|
|
logger.LogError("Method {MethodName} failed. Errors: [{ErrorType}] {Errors}. Parameters: {@Parameters}",
|
|
method.Name, result.Reasons?.FirstOrDefault()?.GetType().Name.Replace("Error", string.Empty), errorsString, parameters);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogWarning(ex, "Failed to write error log for method {MethodName}.", invocation.Method.Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string[] BuildPayloadSummary(ParameterInfo[] parameters, object[] args)
|
|
{
|
|
var entries = new List<string>();
|
|
|
|
for (var i = 0; i < parameters.Length; i++)
|
|
{
|
|
var param = parameters[i];
|
|
var arg = args[i];
|
|
|
|
if (param.ParameterType == typeof(CancellationToken))
|
|
continue;
|
|
|
|
if (arg == null)
|
|
{
|
|
entries.Add($"{param.Name}: null");
|
|
|
|
continue;
|
|
}
|
|
|
|
if (arg is IFormFile file)
|
|
{
|
|
entries.Add($"{param.Name}: [File] Name='{file.FileName}', Size={file.Length} bytes, Type='{file.ContentType}'");
|
|
|
|
continue;
|
|
}
|
|
|
|
if (arg is IEnumerable<IFormFile> files)
|
|
{
|
|
var fileSummaries = new List<string>();
|
|
|
|
foreach (var f in files)
|
|
fileSummaries.Add($"'{f.FileName}' ({f.Length} bytes)");
|
|
|
|
entries.Add($"{param.Name}: [Files] count={fileSummaries.Count} [{string.Join(", ", fileSummaries)}]");
|
|
|
|
continue;
|
|
}
|
|
|
|
if (arg is Stream stream)
|
|
{
|
|
entries.Add($"{param.Name}: [Stream] Length={(stream.CanSeek ? stream.Length : -1)} bytes");
|
|
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(arg);
|
|
|
|
entries.Add($"{param.Name}: {json}");
|
|
}
|
|
catch
|
|
{
|
|
entries.Add($"{param.Name}: [Unserializable]");
|
|
}
|
|
}
|
|
|
|
return [.. entries];
|
|
}
|
|
} |