Question NLog logging

raysefo

Well-known member
Joined
Feb 22, 2019
Messages
361
Programming Experience
10+
@Skydiver and @Sheepings thank you again for your help. As you suggested, I decided to log into a file rather than DB. I used Nlog, would you please have a look at my code? Is it good enough?

I already have UnhandledExceptionHandler so I added NLog logger as follows. I removed all the try/catchs in order to manage logging from a single point.

C#:
using System;
namespace Game.Handlers
{
    public class UnhandledExceptionLogger : ExceptionLogger
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();

        public override void Log(ExceptionLoggerContext context)
        {
            var ex = context.Exception;

            string strLogText = FormatException(ex);

            var requestedURi = (string)context.Request.RequestUri.AbsoluteUri;
            var requestMethod = context.Request.Method.ToString();
            var timeUtc = DateTime.Now;

            SqlErrorLogging sqlErrorLogging = new SqlErrorLogging();
            ApiError apiError = new ApiError()
            {
                Message = strLogText,
                RequestUri = requestedURi,
                RequestMethod = requestMethod,
                TimeUtc = DateTime.Now
            };
            //sqlErrorLogging.InsertErrorLog(apiError);
            //NLOG
            logger.Error(strLogText + Environment.NewLine + DateTime.Now);
        }


        private string FormatException(Exception ex, int depth = 0)
        {
            var indent = "";
            if (depth > 0)
                indent.PadRight(depth * 4);

            var sb = new StringBuilder();
            IndentLine($"Source --- {ex.Source}");
            IndentLine($"StackTrace --- {ex.StackTrace}");
            IndentLine($"TargetSite --- {ex.TargetSite}");

            if (ex.InnerException != null)
            {
                IndentLine("--- Inner Exception ---");
                sb.Append(FormatException(ex.InnerException, depth + 1));
                IndentLine("--- End Inner Exception ---");
            }
            if (ex.Message != null)
            {
                IndentLine($"Message --- {ex.Message}");
            }
            return sb.ToString();

            void IndentLine(string s)
            {
                sb.Append(indent);
                sb.AppendLine(s);
            }
        }

    }
}

Here is the sample NLog config:
C#:
<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>
      <target name="logfile" xsi:type="File" fileName="${basedir}/MyLogs/${date:format=yyyy-MM-dd}-api.log" />
      <target name="eventlog" xsi:type="EventLog" layout="${message}" log="Application" source=" GamePIN Api Services" />
      <target name="database" type="Database" connectionString="Data Source=(localdb)\MSSQLLocalDB;Database=Game; Initial Catalog=GameAPI;MultipleActiveResultSets=True;">
        <commandText> insert into ExceptionLog ([TimeStamp],[Level],Logger, [Message], UserId, Exception, StackTrace) values (@TimeStamp, @Level, @Logger, @Message, case when len(@UserID) = 0 then null else @UserId end, @Exception, @StackTrace); </commandText>
        <parameter name="@TimeStamp" layout="${date}" />
        <parameter name="@Level" layout="${level}" />
        <parameter name="@Logger" layout="${logger}" />
        <parameter name="@Message" layout="${message}" />
        <parameter name="@UserId" layout="${mdc:user_id}" />
        <parameter name="@Exception" layout="${exception}" />
        <parameter name="@StackTrace" layout="${stacktrace}" />
        <dbProvider>System.Data.SqlClient</dbProvider>
      </target>
    </targets>
    <rules>
      <!-- I am adding my 3 logging rules here -->
      <logger name="*" minlevel="Error" writeTo="database" />
      <logger name="*" minlevel="Error" writeTo="logfile" />
      <logger name="*" minlevel="Error" writeTo="eventlog" />
    </rules>
  </nlog>
 
Last edited:
Perhaps I'm missing it, but since NLog support all kinds of magic templates to layout how your log output looks like, why do you still have all that extra code to do all the formatting?

Also, NLog, like most logging libraries worth their salt, supports more than just logging errors. Some well placed logging calls to record informational and debug level data could help you in the future with just a simple web.config file change. Yes keep your current logging level to "Error" when you go to production, but it may help during load tests to go down to "Information" or "Debug" level so that you know what is happening when there is a failure, instead of having to re-run the load test with the lower setting when there is a failure.

Check on the startup costs of NLog. If it's relatively expensive, you may not want to be instantiating it at the last minute. Instead, this will be the time that you'll either want a singleton, or a just one instance that is injected into all classes that need to or should be logging.
 
Perhaps I'm missing it, but since NLog support all kinds of magic templates to layout how your log output looks like, why do you still have all that extra code to do all the formatting?

I already had those extra codes for logging into a database table. So if it is not needed as you suggested, I will remove them. I would like to know your opinion about putting this Nlog into UnhandledExceptionHandler. Is it OK? What is your suggestion?
 
What I am trying to say is that you can use similar tags/placeholders for your text file as well. For example, you have this code to stick in the current time stamp,
C#:
logger.Error(strLogText + Environment.NewLine + DateTime.Now);
but NLog already has a tag/placeholder for "${date} and ${time}"
 
When I put Nlog into CustomExceptionFilter, I am able to see the error in the file as follows. What does it mean and how to fix it?

C#:
2019-08-19 22:26:43.5956||ERROR|Game.Handlers.CustomExceptionFilter|System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at BusinessService.Utility.Utilities.<CallRazer>d__3.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\BusinessService\Utility\Utilities.cs:line 138
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at BusinessService.GameServicesTest.<CallProducts>d__11.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\BusinessService\GameServicesTest.cs:line 478
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at BusinessService.GameServicesTest.<GameProducts>d__10.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\BusinessService\GameServicesTest.cs:line 449
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Game.Controllers.LoadTestController.<PostProducts>d__5.MoveNext() in C:\Users\197199\Documents\Visual Studio 2017\Projects\Game\Game\Controllers\LoadTestController.cs:line 205
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__1`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()
 
I think its ironic you link to a post about timeout handling when all that website does is spin and loads for me. :) Yes, I followed the url, not the hyperlink since its broken.

I'm not sure why a httpclient would be responsible for an Iformat exception, or have i missed something somewhere? Stranger things have happened apparently Adding HttpClient headers generates a FormatException with some values

You're going to have to start debugging your code. There is only so much we can do...
 
I am getting the exception below. What is the point about format exception? I don't get it.

System.Threading.Tasks.TaskCanceledException: A task was canceled.
 
I am getting the exception below. What is the point about format exception? I don't get it.
The last error I read about your data writing issue was about Iformat exception, and I have gotten confused between your two separate issues, which there is no connection between your opening topic and Nlog.

A) Why not errors written to DB? and B) Your new problem with Nlog - Don't trail topics because you discover new problems. Each problem should be posted in a new topic and handled separately.
Ask a mod to split your topic from where i quoted Nlog or start a new topic with your new problem.
 
Ask a mod to split your topic from where i quoted Nlog or start a new topic with your new problem.
I split the Nlog part to a new thread.
 
Back
Top Bottom