debugcsharpMinor
Generating unique ID of an exception
Viewed 0 times
uniquegeneratingexception
Problem
For classifying error reports, I need to generate an ID from an exception. That ID should be
The following code seems to do the job:
Do you see any problems with the code?
- (more or less) unique
- a short alpha numeric string
- equal for equivalent exceptions (even on different systems)
The following code seems to do the job:
public static string GetExceptionID(this Exception ex)
{
if (ex == null) return "0000";
int hash = 31;
var innerException = ex;
while (innerException != null)
{
hash ^= GetHash(innerException.GetType().ToString());
hash ^= innerException.StackTrace
.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
// If *.pdb file is provided, the file and line no. (e.g. "... in C:\Path...") is part of the stacktrace.
// The next line cutting off that part
.Select(line => line.Substring(0, line.IndexOf(" in ") currentHash ^= val.GetHash());
innerException = innerException.InnerException;
}
return Convert.ToBase64String(BitConverter.GetBytes(hash))
.Replace('+', 'P')
.Replace('-', 'M')
.Replace("=", "")
.ToUpper();
}
// https://en.wikipedia.org/wiki/Jenkins_hash_function
private static int GetHash(this string str)
{
if (str == null) return 1;
int hash = 31;
foreach (char c in str)
{
unchecked
{
hash += c;
hash += hash > 6;
}
}
hash += hash > 11;
hash += hash << 15;
return hash;
}Do you see any problems with the code?
Solution
Stack trace
I think you shouldn't work with the stack string but retrieve the stack and go through each frame yourself. I find it would make the analysis more reliable and you could get the information you need without extracting it from the string because you would have direct access to each part.
This snippet comes from my Exception prettyfier.
Other suggestions
It would be a good idea to split this method into three or four methods.
Example:
where
Now you can test and maintain each part of the exception id creation separately.
I think you shouldn't work with the stack string but retrieve the stack and go through each frame yourself. I find it would make the analysis more reliable and you could get the information you need without extracting it from the string because you would have direct access to each part.
private static IEnumerable GetStackTrace(this Exception exception)
{
var stackTrace = new StackTrace(exception, true);
var stackFrames = stackTrace.GetFrames();
var result = stackFrames?.Select(sf => new
{
Caller = (sf.GetMethod() as MethodInfo)?.ToShortString() ?? string.Empty,
FileName = Path.GetFileName(sf.GetFileName()),
LineNumber = sf.GetFileLineNumber(),
});
}This snippet comes from my Exception prettyfier.
Other suggestions
It would be a good idea to split this method into three or four methods.
- the first one gets you the information you need from the stack - you could implement it either based on the string or on the raw stack trace
- the second one would encode the data as
Base64String
- the third and last one would clean-up or encode the string generated by the second one
- the fourth could be a helper encapsulating the three other methods
Example:
var ex.ToExceptionId()where
public static string ToExceptionId(this Exception ex)
{
return ex.GetStackTrace().ToBase64String().EncodeBase64String();
}Now you can test and maintain each part of the exception id creation separately.
Code Snippets
private static IEnumerable<dynamic> GetStackTrace(this Exception exception)
{
var stackTrace = new StackTrace(exception, true);
var stackFrames = stackTrace.GetFrames();
var result = stackFrames?.Select(sf => new
{
Caller = (sf.GetMethod() as MethodInfo)?.ToShortString() ?? string.Empty,
FileName = Path.GetFileName(sf.GetFileName()),
LineNumber = sf.GetFileLineNumber(),
});
}var ex.ToExceptionId()public static string ToExceptionId(this Exception ex)
{
return ex.GetStackTrace().ToBase64String().EncodeBase64String();
}Context
StackExchange Code Review Q#149746, answer score: 5
Revisions (0)
No revisions yet.