Search code examples
javamain-method

How can I determine which class's `main` method was invoked at runtime?


I'd like to dynamically determine which class's main method was invoked, in order to allow for an easier to digest combined log file.

Currently, a single (rotated) log file aggregates all the log output from a number of daemons, but there is no obvious way to determine which daemon the log entry originated from, as all of the daemons use a shared code base, and loggers are created with log4j's getLogger(Something.class)

Since we're using a custom Layout class to begin with, actually outputting the information is not an issue, but finding it is.

One approach that could work as a fallback is defining a property at invocation time and reading that property.

java -cp ... -Dmain.program=<WHATEVER> MainProgram

However, there's no need to create a new convention if the ability already exists.

Update: For my purposes, the following seems to work fine:

import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
public class MyLayout extends PatternLayout {
  private static String _mainClass = null;
  public String format( LoggingEvent event ) {
    String mesg = super.format( event );
    if (mesg.indexOf("$main") > -1) {
      mesg = mesg.replaceAll("\\$main", getMainClass());
    }
    return mesg;
  }
  private static String getMainClass() {
    if (_mainClass == null) {
      StackTraceElement[] elem = new Exception().getStackTrace();
      int offset = elem.length - 1;
      if (elem[offset].getMethodName().equals("main")) {
        _mainClass = elem[offset].getClassName();
      }
      else {
        _mainClass = "<Unknown_Main_Class>";
      }
    }
    return _mainClass;
  }
}

Thanks for the suggestions!


Solution

  • If you only need to do it once you can walk the exception stack and look at the last class/method call.

        StackTraceElement[] elem = new Exception().getStackTrace();
        elem[elem.length - 1].getClassName();
    

    But is error prone. If i load your class via reflection you will see a completely different method at the top.

    You can try M. Jessup variant ( matching a main method signature ) but it will fail if I call a main method from the code too.