I would like to log the body for some requests in my API and have created an ActionFilterAttribute for this purpose. Therefore, I created a simple TypeFilterAttribute which calls my ActionFilterAttribute in it. Locally everything works fine, but when I deploy it nothing is logged unless I call the ILogger once in the constructor. Correct, I need to use the ILogger once in the RequestLoggerService in the constructor, then everything works.
Why do I need to call the ILogger in the constructor for logging to work?
I deliberately do not want to use the ILogger as a static variable like:
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
The reason is the simplified overloading of the ILogger in UnitTests.
Simplified, my code looks like this:
Example of controller:
[NoAuthorization]
[HttpPost("response")]
[RequestLogger(true, true)]
public IActionResult PostResponse([FromBody] StringRequestModel model)
{
return Ok($"Received Message: '{model.Message}' at {DateTime.UtcNow.ToShortDateString()} - {DateTime.UtcNow.ToLongTimeString()} UTC");
}
My RequestLoggerAttribute:
public class RequestLoggerAttribute : TypeFilterAttribute
{
public RequestLoggerAttribute(bool logBody = false, bool logHeader = false) : base(typeof(RequestLoggerService))
{
Arguments = new object[] { logBody, logHeader };
}
}
My RequestLoggerService:
public class RequestLoggerService : ActionFilterAttribute
{
private readonly bool _logHeader;
private readonly bool _logBody;
public ILogger _logger = LogManager.GetCurrentClassLogger();
public RequestLoggerService(bool logBody, bool logHeader)
{
_logHeader = logHeader;
_logBody = logBody;
// Why do I need this line?
_logger.Info($"{nameof(RequestLoggerService)} called.");
}
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// log HttpContext header
_logger.Info($"requestHeaders: {requestHeadersText}");
// log HttpContext body
_logger.Info($"requestBody: {requestBodyText}");
}
}