I am using Serilog
and Serilog.Exceptions
for structured logging purposes in my MVC5 application.
I want to remove the stack trace from the value of the "Exception" field in the log. I understand that I am using the new JsonFormatter()
in the RollingFile
sink, hence the exception object, say, ex
, gets formatted as ex.ToString()
and the entire object gets written as it is.
I am using new DestructuringOptionsBuilder().WithDefaultDestructurers()
to show stack trace in "ExceptionDetails" section which looks much better as a separate field.
Is it possible to see only the name of the exception as a value of the "Exception" field in the log rather than the entire stack trace and other details as ex.ToString()
while writing to a JSON file sink?
Here is my exception log:
{
"Timestamp": "2021-09-02T15:04:02.4469999+05:00",
"Level": "Error",
"MessageTemplate": "Unhandled Exception",
"Exception": "System.NullReferenceException: Object reference not set to an instance of an object.\r\n at AppV2.Controllers.BaseController.Initialize(RequestContext requestContext) in E:\\Workspace\\AppV2\\AppV2\\Controllers\\BaseController.cs:line 115\r\n at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)\r\n at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)\r\n at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)\r\n at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)\r\n at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)\r\n at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)",
"Properties": {
"UserName": "[email protected]",
"ThreadId": 5,
"Caller": "AppV2.Extensions.Logger.LogError(System.Exception, System.String, System.Object[])",
"MachineName": "DESKTOP-GHV3V41",
"HttpRequestId": "e9922caf-7e25-47f8-9941-263ba1ec4278",
"HttpRequestNumber": 1,
"HttpRequestClientHostIP": "::1",
"HttpRequestType": "GET",
"HttpRequestRawUrl": "/",
"ExceptionDetails": {
"Type": "System.NullReferenceException",
"HResult": -2147467261,
"Message": "Object reference not set to an instance of an object.",
"Source": "Boilerplate.Web.Mvc5.Sample",
"StackTrace": " at AppV2.Controllers.BaseController.Initialize(RequestContext requestContext) in E:\\Workspace\\AppV2\\AppV2\\Controllers\\BaseController.cs:line 115\r\n at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)\r\n at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)\r\n at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)\r\n at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)\r\n at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)\r\n at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)\r\n at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)",
"TargetSite": "Void Initialize(System.Web.Routing.RequestContext)"
}
}
}
Here is my Logger
class:
public class Logger
{
private static readonly ILogger logger;
static Logger()
{
logger = new LoggerConfiguration()
.Enrich.WithUserName(anonymousUsername: "Not Authenticated")
.Enrich.FromLogContext()
.Enrich.With(new ThreadEnrich())
.Enrich.WithCaller()
.Enrich.WithMachineName()
.Enrich.WithHttpRequestId()
.Enrich.WithHttpRequestNumber()
.Enrich.WithHttpRequestClientHostIP()
.Enrich.WithHttpRequestType()
.Enrich.WithHttpRequestRawUrl()
.Enrich.WithMvcRouteData()
.Enrich.WithExceptionDetails(
new DestructuringOptionsBuilder()
.WithDefaultDestructurers())
.Enrich.WithDemystifiedStackTraces()
.WriteTo.RollingFile(new JsonFormatter(),
HttpContext.Current.Server.MapPath($"~/logs/log-.json"),
LogEventLevel.Debug,
fileSizeLimitBytes: 655360)
.CreateLogger();
}
public static void LogInformation(string info, object[] data = null)
{
logger.Information(info, data);
}
public static void LogDebug(string debug, object[] data = null)
{
logger.Debug(debug, data);
}
public static void LogWarning(string warning, object[] data = null, Exception e = null)
{
logger.Warning(e, warning, data);
}
public static void LogError(Exception e, string error, object[] data = null)
{
logger.Error(e, error, data);
}
}
Any suggestions regarding my Logger
class are also welcome.
I researched and I think you should check the Serilog filters. You can filter event fields, sources or even filter data if they have a certain value, for example. You can do this by configuring the respective filters in your logger configuration on code or in the JSON file.
Refer to this link for more information https://github.com/serilog/serilog-filters-expressions