Implemented audit logging and automated logging
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
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: {Errors}. Parameters: {@Parameters}",
|
||||
method.Name, 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];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user