如何确定在运行时调用了哪个类的“main”方法?
我想动态确定调用哪个类的主要方法,以便更容易消化组合日志文件。
目前,单个(轮换)日志文件聚合了多个守护进程的所有日志输出,但没有明显的方法来确定日志条目源自哪个守护进程,因为所有守护进程都使用共享代码库,并且记录器是使用 log4j 的 getLogger(Something.class) 创建
由于我们首先使用自定义 Layout 类,因此实际上输出信息不是问题,但查找信息才是问题。
一种可以作为后备的方法是在调用时定义一个属性并读取该属性。
java -cp ... -Dmain.program=<WHATEVER> MainProgram
但是,如果该功能已经存在,则无需创建新的约定。
更新:就我的目的而言,以下内容似乎工作正常:
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;
}
}
感谢您的建议!
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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您只需要执行一次,您可以遍历异常堆栈并查看最后一个类/方法调用。
但很容易出错。如果我通过反射加载你的类,你会在顶部看到一个完全不同的方法。
您可以尝试 M. Jessup 变体(匹配 main 方法签名),但如果我也从代码中调用 main 方法,它将失败。
If you only need to do it once you can walk the exception stack and look at the last class/method call.
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.
这有点 hackish,但您可以使用静态方法 Thread.getAllStackTraces()。这将为您提供虚拟机中每个活动线程的堆栈跟踪,并假设启动应用程序的线程仍然活动,您可以检查跟踪并查找其方法签名与 main(String[] args) 匹配的底部元素。
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 撰写了两篇关于如何使用 Log4j 的映射诊断上下文(Servlet 过滤器的源代码)的文章 http://veerasundar.com/blog/2009/11/log4j-mdc-mapped-diagnostic-context-example-code/ 这可能会根据您的用例进行修改。
让您的应用程序类(使用 main 方法)将其类名添加为可以写入日志文件的变量。
是不是比在运行时添加属性要少一些工作?不,不是真的,但是,更优雅
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