29

logging exception the code below allows to save the content of an exception in a text file. Here I'm getting only the decription of the error.

but it is not telling me where the exception occured, at which line. Can anyone tell me how can I achive that so I can get even the line number where the exception occured?

#region WriteLogError
/// <summary>
/// Write an error Log in File
/// </summary>
/// <param name="errorMessage"></param>
public void WriteLogError(string errorMessage)
{
  try
  {
    string path = "~/Error/" + DateTime.Today.ToString("dd-mm-yy") + ".txt";
    if (!File.Exists(System.Web.HttpContext.Current.Server.MapPath(path)))
    {
      File.Create(System.Web.HttpContext.Current.Server.MapPath(path))
     .Close();
    }
    using (StreamWriter w = File.AppendText(System.Web.HttpContext.Current.Server.MapPath(path)))
    {
      w.WriteLine("\r\nLog Entry : ");
      w.WriteLine("{0}", DateTime.Now.ToString(CultureInfo.InvariantCulture));
      string err = "Error in: " + System.Web.HttpContext.Current.Request.Url.ToString() 
                 + ". Error Message:" + errorMessage;
      w.WriteLine(err);
      w.WriteLine("__________________________");
      w.Flush();
      w.Close();
    }
  }
  catch (Exception ex)
  {
    WriteLogError(ex.Message);
  }

}

#endregion
shA.t
  • 16,580
  • 5
  • 54
  • 111
happysmile
  • 7,537
  • 36
  • 105
  • 181
  • On a side note, this code is *not* thread-safe, and IIS is a multithreading environment. – Steven Sudit Aug 16 '10 at 07:12
  • 6
    Recursively calling WriteLogError() inside your catch block is a pretty bad idea... – jeroenh Aug 16 '10 at 07:14
  • 1
    @jeroenh: Failure during logging can't be reported with more of the same logging. One alternative is to use an Event Log, which is a pain but useful. Another is to either silently ignore it or else kill the process. – Steven Sudit Aug 16 '10 at 08:52

7 Answers7

55

I find that the easiest way to log exceptions in C# is to call the ToString() method:

try
{

}
catch (Exception ex)
{
    Console.WriteLine(ex.ToString());
}

This usually gives you all the information you need such as the error message and the stack trace, plus any extra exception specific context information. (however note that the stack trace will only show you source files and line numbers if you have your application compiled with debug information)

It is worth noting however that seeing a full stack trace can be fairly offputting for the user and so wherever possible you should try to handle exceptions and print out a more friendly error message.

On another note - you should replace your method WriteLogError with a fully featured logging framework (like Serilog) instead of trying to write your own.

Your logging method is not thread safe (your log file will probably end up with log messages being intermingled with each other) and also should definitely not call itself if you catch an exception - this will mean that any exceptions that occur whilst logging errors will probably cause a difficult to diagnose StackOverflow exception.

I could suggest how to fix those things, however you would be much better served just using a proper logging framework.

Justin
  • 84,773
  • 49
  • 224
  • 367
7

Just log ToString(). Not only will it give you the stack trace, but it'll also include the inner exceptions.

Steven Sudit
  • 19,391
  • 1
  • 51
  • 53
  • 2
    Please note that he needs to distribute the debugging symbols, too, if he wants linenumbers (But I think they can be merged into the exe using ilmerge). – Bobby Aug 16 '10 at 07:21
  • 1
    @Bobby: Line numbers are nice, but a regular stack trace will at least give method names, and that's usually plenty. – Steven Sudit Aug 16 '10 at 08:50
  • True, but he explicitly asked for them. – Bobby Aug 16 '10 at 08:54
  • @Bobby: You're right, he did. However, his code wasn't showing the stack trace at all, so I figured that this was the deeper issue. Line numbers are nice and I'm all for them, though. – Steven Sudit Aug 16 '10 at 09:08
4

Also, when you deploy a release build of your code to a production environment for instance, don't forget to include the .pdb files in the release package. You need that file to get the line number of the code that excepted (see How much information do pdb files contain? (C# / .NET))

Community
  • 1
  • 1
theburningmonk
  • 15,701
  • 14
  • 61
  • 104
1

Your solution is pretty good. I went through the same phase
and eventually needed to log more and more (it will come...):

  • logging source location
  • callstack before exception (could be in really different place)
  • all internal exceptions in the same way
  • process id / thread id
  • time (or request ticks)
  • for web - url, http headers, client ip, cookies, web session content
  • some other critical variable values
  • loaded assemblies in memory
  • ...

Preferably in the way that I clicked on the file link where the error occurred,
or clicked on a link in the callstack, and Visual Studio opened up at the appropriate location.
(Of course, all you need to do is *.PDB files, where the paths from the IL code
to your released source in C # are stored.)

So I finally started using this solution:
It exists as a Nuget package - Desharp.
It's for both application types - web and desktop.
See it's Desharp Github documentation. It has many configuration options.

try {
    var myStrangeObj = new { /*... something really mysterious ...*/ };
    throw new Exception("Something really baaaaad with my strange object :-)");
} catch (Exception ex) {

    // store any rendered object in debug.html or debug.log file
    Desharp.Debug.Log(myStrangeObj, Desharp.Level.DEBUG);

    // store exception with all inner exceptions and everything else
    // you need to know later in exceptions.html or exceptions.log file
    Desharp.Debug.Log(ex);
}

It has HTML log formats, every exception in one line,
and from html page you can open in browser, you can click
on file link and go to Visual Studio - it's really addictive!
It's only necessary to install this Desharp editor opener.

See some demos here:

Try to check out any of those repos and log something by the way above.
then you can see logged results into ~/Logs directory. Mostly anything is configurable.

Tom Flídr
  • 101
  • 5
0

I am only answering for the ask, other people have already mentioned about the code already. If you want the line number to be included in your log you need to include the generated debug files (pdb) in your deployment to the server. If its just your Dev/Test region that is fine but I don't recommend using in production.

Naveen
  • 111
  • 1
  • 2
  • 8
0

Please note that the exception class is serializable. This means that you could easily write the exception class to disk using the builtin XmlSerializer - or use a custom serializer to write to a txt file for example.

Logging to output can ofcourse be done by using ToString() instead of only reading the error message as mentioned in other answers.

Exception class

https://learn.microsoft.com/en-us/dotnet/api/system.exception?redirectedfrom=MSDN&view=netframework-4.7.2

Info about serialization, the act of converting an object to a file on disk and vice versa.

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/

sommmen
  • 6,570
  • 2
  • 30
  • 51
0

I don't know how to get the line number where an exception occurs, but if you use those methods you can get a fast idea:

    catch (... ex)
    {
       ...
       string method_source = System.Reflection.MethodBase.GetCurrentMethod().Name;
       string object_source = ex.Source;
       Console.WriteLine("An exception happended in the object/application" + object_source + " in the method " + method_source); 
       ...
    }

It is not so complete as a ex.Message or ex.ToString(), but I use it to save logs in databases.

Jaime
  • 7
  • 4