C# - How to get Class Name and Line Number when an Exception is called
I need two methods, one for getting the Class from where the exception was called开发者_如何学Go, and another one which gets the line number where an exception was called.
So far I have this code, which gets me the Class Name and Line Number together (example: DatabaseHandler.cs:line 70):
private string GetClassAndLine()
{
string tempName = e.GetBaseException().ToString();
int tempPosition = 0;
int length = tempName.Length;
for (int i = 0; i < length; i++)
{
if (tempName.ElementAt(i).Equals('\\'))
{
tempPosition = i + 1;
}
}
return tempName.Substring(tempPosition, length - tempPosition);
}
So if you have any ideas how I could get them individually, it would be of great help. These are then passed into Oracle to store any exceptions which occur.
Update 2:
I am currently testing this code, as some suggested:
private string GetClassName()
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(e, true);
return trace.GetFrame(0).GetMethod().ReflectedType.FullName;
}
private int GetLineNumber()
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(e, true);
return trace.GetFrame(0).GetFileLineNumber();
}
This is what was returned at a particular Database Exception. No Line Number or Class Name where it was triggered. How can I get that?
Error was found at Class: Oracle.DataAccess.Client.OracleException.
Line Number: 0
What I want is for Example: "Class: Logging.cs, Line: 57"
Thanks, Ryan
You can do like this
try
{
// Some code that can cause an exception.
throw new Exception("An error has happened");
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine(trace.GetFrame(0).GetMethod().ReflectedType.FullName);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
Console.WriteLine("Column: " + trace.GetFrame(0).GetFileColumnNumber());
}
System.Environment.StackTrace
. Useful any time, not just on exceptions. Might need a bit of string manipulation using that though;
If you prefer something a little more hi-tech, you can use System.Diagnostics.StackFrame
; Check the object browser for full details, but it's got methods for finding the filename, line and column number, etc.
I'm using the following class DebugE
to trace exceptions and log stuff in the application:
It outputs the Thread# DateTime, ClassName.MethodName, Line & Col numbers and the exception message.
using System;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Text.RegularExpressions;
namespace YourApp
{
class DebugE
{
public static void d(Exception e)
{
try
{
MethodBase site = e.TargetSite;//Get the methodname from the exception.
string methodName = site == null ? "" : site.Name;//avoid null ref if it's null.
methodName = ExtractBracketed(methodName);
StackTrace stkTrace = new System.Diagnostics.StackTrace(e, true);
for (int i = 0; i < 3; i++)
{
//In most cases GetFrame(0) will contain valid information, but not always. That's why a small loop is needed.
var frame = stkTrace.GetFrame(i);
int lineNum = frame.GetFileLineNumber();//get the line and column numbers
int colNum = frame.GetFileColumnNumber();
string className = ExtractBracketed(frame.GetMethod().ReflectedType.FullName);
Trace.WriteLine(ThreadAndDateInfo + "Exception: " + className + "." + methodName + ", Ln " + lineNum + " Col " + colNum + ": " + e.Message);
if (lineNum + colNum > 0)
break; //exit the for loop if you have valid info. If not, try going up one frame...
}
}
catch (Exception ee)
{
//Avoid any situation that the Trace is what crashes you application. While trace can log to a file. Console normally not output to the same place.
Console.WriteLine("Tracing exception in d(Exception e)" + ee.Message);
}
}
public static void d(string str)
{
try
{
StackFrame frame = new StackFrame(1);
var method = frame.GetMethod();
string name = ExtractBracketed(method.Name);//extract the content that is inside <brackets> the rest is irrelevant
Trace.WriteLine(ThreadAndDateInfo + method.DeclaringType + "." + name + ": " + str);
}
catch (Exception e)
{
Console.WriteLine("Tracing exception in d(string str)" + e.Message);
}
}
private static string ExtractBracketed(string str)
{
string s;
if (str.IndexOf('<') > -1) //using the Regex when the string does not contain <brackets> returns an empty string.
s = Regex.Match(str, @"\<([^>]*)\>").Groups[1].Value;
else
s = str;
if (s == "")
return "'Emtpy'"; //for log visibility we want to know if something it's empty.
else
return s;
}
public static string ThreadAndDateInfo
{
//returns thread number and precise date and time.
get { return "[" + Thread.CurrentThread.ManagedThreadId + " - " + DateTime.Now.ToString("dd/MM HH:mm:ss.ffffff") + "] "; }
}
}
}
Call if from anywhere in your application:
catch (Exception e)
{
DebugE.d(e);
}
To use it for plain logging, call DebugE.d("some text");
It will return the same but without the line and col numbers.
Note that for production applications I always end up calling a "simpler" call systematically:
void debug(string methodName, exception e)
.
This is because the "nicer" solution above DID NOT ALWAYS RETURN THE CORRECT METHOD information to me. If my guess is correct, this would be the case if your exception occurs in a method that does not have a try catch
, but was called by another method that does have a 'try catch'. If this is the only reason, you can say "i'll add proper try catch". The problem is that in real life you get a real problem, a real log to analyse. When you notice the irrelevant or insufficient method information you don't get the chance to go back to your code, add the try/catch and quickly reproduce the exception. You just end up with missing information to deal with...
The current improved methods digs a few frames deep to try and get around this and retrieve the class, line and column in these special situations it could look like this (the trace on the 3rd frame actually returns a valid name and line number):
[1 - 21/11 14:37:50.424914] Exception: System.Threading.Tasks.Task.Delay, Ln 0 Col 0: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue.
Parameter name: delay
[1 - 21/11 14:37:50.425914] Exception: System.Threading.Tasks.Task.Delay, Ln 0 Col 0: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue.
Parameter name: delay
[1 - 21/11 14:37:50.426415] Exception: ScheduleAction.Delay, Ln 156 Col 17: The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue.
Parameter name: delay
精彩评论