Get Currently Executing Class/Method Name?

I have seen a few different flavors of exception logging utility out there, and a common concept is to capture the class and method that were running when the exception was thrown. In the case that made me wonder this, the logger is used for more than just exceptions. It has method signatures like:

public static void logMessage
    (LoggingLevel loggingLevel, String className, String methodName, String message)

It seems to me that we should be able to get the className and methodName parameters programatically. Can it be done? How?

Answer

My first thought (which does work) is to throw and catch a DmlException (or any Exception type you wish), and use its stack trace string as a starting point.

public class StackTrace
{
    public static String getCurrentString()
    {
        try { throw new DmlException(); }
        catch (DmlException e)
        {
            return e.getStackTraceString().substringAfter('\n');
        }
    }
}

Note the substringAfter('\n'). One of the tricky aspects of this pursuit is that you add calls to the stack in any attempt to write a generic tool to parse the stack trace for you.

While the above code works, upon further inspection it seems the Exception constructor does the work of building the stack trace, and we don’t even need to throw. The following method is more concise, works just as well, and consumes less CPU:

public static String getCurrrentString()
{
    return new DmlException().getStackTraceString().substringAfter('\n');
}

So now we know how to get the stack trace. That’s all well and good, but we still need to parse it to get the class name and method. Here are some example values:

Class.Demo.Subclass.doStuff: line 18, column 1
Class.Demo.doStuff: line 7, column 1
AnonymousBlock: line 1, column 1

So how do we get the class and method names? Here’s one approach:

global static String getClassName(String line)
{
    if (line.startsWith('Class.'))
        line = line.substringAfter('Class.');
    return line.substringBefore(':').substringBeforeLast('.');
}    
global static String getMethod(String line)
{
    return line.substringBefore(':').substringAfterLast('.');
}

And if you want convenience methods to get the currently executing class and method, they would look something like:

global static String getClassName()
{
    return getClassName(new DmlException().getStackTraceString().substringAfter('\n'));
}
global static String getMethod()
{
    return getMethod(new DmlException().getStackTraceString().substringAfter('\n'));
}

Back to the initial problem, how would we integrate this approach into our Logger class? If we try the below approach, we’ll log every time that we’re in the Logger.smartLog method!

public static void smartLog(LoggingLevel level)
{
    logMessage(level, StackTrace.getClassName(), StackTrace.getMethod());
}

The most efficient and straightforward approach would be to simply not add that call to the stack.

public static void smartLog(LoggingLevel level)
{
    String trace = new DmlException().getStackTraceString().substringAfter('\n');
    logMessage(level, StackTrace.getClassName(trace), StackTrace.getMethod(trace));
}

Attribution
Source : Link , Question Author : Adrian Larson , Answer Author : Adrian Larson

Leave a Comment