简体   繁体   中英

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!

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.

It is a bit hackish, but you could use the static method Thread.getAllStackTraces(). This will get you the stack trace for every live thread in the VM, and assuming the thread that started the application is still alive you could inspect the traces and look for a bottom element whose method signature matched main(String[] args).

Veera Sundar has written two articles on how to use Log4j 's Mapped Diagnostic Context (source code for Servlet Filters) http://veerasundar.com/blog/2009/11/log4j-mdc-mapped-diagnostic-context-example-code/ that might be possible modify for your use case.

Let your application classes (with the main method) add its class name as a variable which can be written to the log files.

Is it less work than adding a property at runtime? No, not really but, more elegant

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM