Following the tutorial from Filip W's blog, I've ended up creating my own implementation for a custom ActionFilter.
This logs the execution name, action, parameters and elapsed time of every ApiController in my solution.
The post is a bit old (2013), that's why I'm still thinking it must be a better/simpler way to do this, any suggestion? improvements?
public sealed class LogActionFilter : FilterAttribute, IActionFilter
{
private readonly Stopwatch _stopwatch = new Stopwatch();
public bool AllowMultiple => false;
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext,
CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
await InternalActionExecuting(actionContext);
if (actionContext.Response != null)
return actionContext.Response;
HttpActionExecutedContext executedContext;
try
{
var response = await continuation();
executedContext = new HttpActionExecutedContext(actionContext, null)
{
Response = response
};
}
catch (Exception exception)
{
executedContext = new HttpActionExecutedContext(actionContext, exception);
}
await InternalActionExecuted(executedContext);
_stopwatch.Reset();
return executedContext.Response;
}
private Task InternalActionExecuting(HttpActionContext actionContext)
{
_stopwatch.Start();
return Log("Executing", actionContext, 0);
}
private Task InternalActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
_stopwatch.Stop();
return Log("Executed", actionExecutedContext.ActionContext, _stopwatch.ElapsedMilliseconds);
}
private Task Log(string action, HttpActionContext actionContext, long elapsedTime)
{
return Task.Run(() =>
{
var controllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
var actionName = actionContext.ActionDescriptor.ActionName;
var parameters = string.Join(", ", actionContext.ActionArguments.Values.Select(x => x).ToArray());
var message = $"{action}: ctrl: {controllerName}, act: {actionName}, params: {parameters}" +
$"{(elapsedTime > 0 ? "took (ms): " + elapsedTime : string.Empty) }";
Trace.WriteLine(message, "Action filter log");
});
}
}