Java Log4J:创建 Logger 实例的策略
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1770076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Log4J: Strategies for creating Logger instances
提问by Adrian
I decided to use Log4J logging framework for a new Java project. I am wondering what strategy should I use for creating/managing Logger instances and why?
我决定在一个新的 Java 项目中使用 Log4J 日志框架。我想知道我应该使用什么策略来创建/管理 Logger 实例,为什么?
one instance of Logger per class e.g.
class Foo { private static final Logger log = Logger.getLogger(Foo.class); }
- one instance of Logger per thread
- one instance of Logger per application
- horizontal slicing : one instance of Logger in each layer of an application (e.g. the view layer, the controller layer and the persistence layer)
- vertical slicing : one instance of Logger within functional partitions of the application
每个类一个 Logger 实例,例如
class Foo { private static final Logger log = Logger.getLogger(Foo.class); }
- 每个线程一个 Logger 实例
- 每个应用程序一个 Logger 实例
- 水平切片:应用程序的每一层(例如视图层、控制器层和持久层)中的一个 Logger 实例
- 垂直切片:应用程序功能分区中的一个 Logger 实例
Note: This issue is already considered to some extent in these articles:
注意:这些文章中已经在一定程度上考虑了这个问题:
采纳答案by PSpeed
Typically, you'd have loggers setup per class because that's a nice logical component. Threads are already part of the log messages (if your filter displays them) so slicing loggers that way is probably redundant.
通常,您会为每个类设置记录器,因为这是一个很好的逻辑组件。线程已经是日志消息的一部分(如果您的过滤器显示它们),因此以这种方式切片记录器可能是多余的。
Regarding application or layer based loggers, the problem is that you have to find a place to stick that Logger object. Not a really big deal. The bigger issue is that some classes may be used at multiple levels of from multiple applications... it could be difficult to get your logger right. Or at least tricky.
关于基于应用程序或基于层的记录器,问题在于您必须找到一个地方来粘贴那个 Logger 对象。没什么大不了的。更大的问题是,某些类可能会在多个应用程序的多个级别上使用……可能很难让您的记录器正确。或者至少是棘手的。
...and the last thing you want is bad assumptions in your logging setup.
...您最不想要的就是日志设置中的错误假设。
If you care about applications and layers and have easy separation points, the NDC is the way to go. The code can be a little excessive sometimes but I don't know how many times I've been saved by an accurate context stack showing me that Foo.bar() was called from application X in layer Y.
如果您关心应用程序和层并且有简单的分离点,那么 NDC 就是您要走的路。代码有时可能有点过分,但我不知道我被准确的上下文堆栈保存了多少次,该堆栈显示 Foo.bar() 是从 Y 层的应用程序 X 调用的。
回答by rsp
The strategy that is most used is to create a logger per class. If you create new threads give them a usefull name, so their logging is easily distinguishable.
最常用的策略是为每个类创建一个记录器。如果你创建新线程,给它们一个有用的名字,这样它们的日志就很容易区分。
Creating loggers per class has the benefit of being able to switch on/off logging in the package structure of your classes:
为每个类创建记录器的好处是能够在类的包结构中打开/关闭日志记录:
log4j.logger.org.apache = INFO
log4j.logger.com.example = DEBUG
log4j.logger.com.example.verbose = ERROR
The above would set all apache library code to INFO
level, switch logging from your own code to DEBUG
level with the exception of the verbose package.
以上会将所有 apache 库代码设置为INFO
级别,将日志记录从您自己的代码切换到DEBUG
级别,但详细包除外。
回答by Thorbj?rn Ravn Andersen
Common convention is "a logger pr class and use the class name as its name". This is good advice.
常见的约定是“记录器 pr 类并使用类名作为其名称”。这是一个很好的建议。
My personal experience is that this logger variable should NOT be declared static but an instance variable which is retrieved for each new. This allows the logging framework to treat two calls differently depending on where they come from. A static variable is the same for ALL instances of that class (in that class loader).
我个人的经验是,这个记录器变量不应该被声明为静态的,而是一个为每个新变量检索的实例变量。这允许日志框架根据它们的来源对两个调用进行不同的处理。对于该类的所有实例(在该类加载器中),静态变量是相同的。
Also you should learn all the possibilities with your logging backend of choice. You may have possibilities you did not expect possible.
此外,您应该了解您选择的日志记录后端的所有可能性。你可能有你没有预料到的可能性。
回答by Matthew Farwell
As has been said by others, I would create a Logger per class:
正如其他人所说,我会为每个班级创建一个记录器:
private final static Logger LOGGER = Logger.getLogger(Foo.class);
or
或者
private final Logger logger = Logger.getLogger(this.getClass());
However, I have found it useful in the past to have other information in the logger. For instance, if you have a web site, you could include the user ID in every log message. That way,, you can trace everything a user is doing (very useful for debugging problems etc).
但是,我发现过去在记录器中包含其他信息很有用。例如,如果您有一个网站,您可以在每条日志消息中包含用户 ID。这样,您可以跟踪用户正在做的所有事情(对于调试问题等非常有用)。
The easiest way to do this is to use an MDC, but you can use a Logger created for each instance of the class with the name including the user ID.
最简单的方法是使用 MDC,但您可以使用为类的每个实例创建的 Logger,其名称包括用户 ID。
Another advantage of using an MDC is if you use SL4J, you can change the settings depending upon the values in your MDC. So if you wish to log all activity for a particular user at DEBUG level, and leave all of the other users at ERROR, you can. You can also redirect different output to different places depending upon your MDC.
使用 MDC 的另一个优点是,如果您使用 SL4J,则可以根据 MDC 中的值更改设置。因此,如果您希望在 DEBUG 级别记录特定用户的所有活动,并将所有其他用户保留在 ERROR,则可以。您还可以根据您的 MDC 将不同的输出重定向到不同的位置。
Some useful links:
一些有用的链接:
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html
回答by yawn
- Create one logger per class.
- If you have dependencies that require Commons Logging(quite likely) use slf4j's bridgefor Commons Logging. Instantiate your loggers (per class) using the Commons Logging interface:
private static final Log log = LogFactory.getLog(MyClass.class);
- Manifest this pattern in your IDE using shortcuts. I use IDEA's live templatesfor this purpose.
- Provide contextual information to threads using an NDC(thread local stack of strings) or an MDC(thread local map of String → ?).
- 每个类创建一个记录器。
- 如果您有需要Commons Logging 的依赖项(很可能),请使用 slf4j 的Bridgefor Commons Logging。使用 Commons Logging 接口实例化你的记录器(每个类):
private static final Log log = LogFactory.getLog(MyClass.class);
- 使用快捷方式在您的 IDE 中显示此模式。为此,我使用 IDEA 的实时模板。
- 使用NDC(字符串的线程本地堆栈)或MDC(字符串的线程本地映射 → ?)向线程提供上下文信息。
Examples for templates:
模板示例:
private static final Log log = LogFactory.getLog($class$.class); // live template 'log'
if (log.isDebugEnabled())
log.debug(String.format("$string$", $vars$)); // live template 'ld', 'lw', 'le' ...
回答by Bas
When deploying multiple EARs / WARs, it may be better to package the log4j.jar higher up in the classloader hierarchy.
i.e. not in WAR or EAR, but in the System-classloader of your container, otherwise multiple Log4J instances will write to the same file concurrently leading to strange behaviour.
部署多个 EAR/WAR 时,最好将 log4j.jar 打包在类加载器层次结构中的更高位置。
即不是在 WAR 或 EAR 中,而是在容器的 System-classloader 中,否则多个 Log4J 实例将同时写入同一个文件,导致奇怪的行为。
回答by Dean J
I'm certain this isn't a best practice, but I've sacked some startup time on applications before to save lines of code. Specifically, when pasting in:
我确定这不是最佳实践,但我之前已经在应用程序上节省了一些启动时间以节省代码行。具体来说,粘贴时:
Logger logger = Logger.getLogger(MyClass.class);
...developers often forget to change "MyClass" to the current class name, and several loggers always wind up pointing at the wrong place. This Is Bad.
...开发人员经常忘记将“MyClass”更改为当前类名,并且几个记录器总是指向错误的位置。这不好。
I've occasionally written:
我偶尔会写:
static Logger logger = LogUtil.getInstance();
And:
和:
class LogUtil {
public Logger getInstance() {
String callingClassName =
Thread.currentThread().getStackTrace()[2].getClass().getCanonicalName();
return Logger.getLogger(callingClassName);
}
}
The "2" in that code might be wrong, but the gist is there; take a performance hit to (on class load, as a static variable) find the class name, so that a developer doesn't really have a way to mistype this or introduce any error.
该代码中的“2”可能是错误的,但要点就在那里;以性能影响(在类加载时,作为静态变量)找到类名,这样开发人员就没有办法输入错误或引入任何错误。
I'm generally not thrilled with losing performance to prevent developer error at runtime, but if it happens as a singleton, once? Often sounds like a good trade to me.
我通常不会因为性能下降以防止运行时出现开发人员错误而感到兴奋,但是如果它作为单例发生,一次?对我来说,这听起来通常是一笔不错的交易。
回答by baybora.oren
Another Option : You can try AspectJcrosscutting on logging. Check here : Simplify Your Logging. (If you don't want to use AOP, you can look slf4j)
另一种选择:您可以在日志记录中尝试AspectJ横切。在这里查看:简化您的日志记录。(如果不想用AOP可以看slf4j)
//Without AOP
Class A{
methodx(){
logger.info("INFO");
}
}
Class B{
methody(){
logger.info("INFO");
}
}
//With AOP
Class A{
methodx(){
......
}
}
Class B{
methody(){
......
}
}
Class LoggingInterceptor{
//Catched defined method before process
public void before(...xyz){
logger.info("INFO" + ...xyz);
}
//Catched defined method after processed
public void after(...xyz){
logger.info("INFO" + ...xyz);
}
.....
}
P.S :AOPwill be better, it is DRY(Don't Repeat Yourself)way.
PS:AOP会更好,它是DRY(不要重复自己)方式。
回答by Rodislav Moldovan
the best and easiest method to create custom loggers, notlinked to any classname is:
创建自定义记录器的最好和最简单的方法,不链接到任何类名是:
// create logger
Logger customLogger = Logger.getLogger("myCustomLogName");
// create log file, where messages will be sent,
// you can also use console appender
FileAppender fileAppender = new FileAppender(new PatternLayout(),
"/home/user/some.log");
// sometimes you can call this if you reuse this logger
// to avoid useless traces
customLogger.removeAllAppenders();
// tell to logger where to write
customLogger.addAppender(fileAppender);
// send message (of type :: info, you can use also error, warn, etc)
customLogger.info("Hello! message from custom logger");
now, if you need another logger in same class, no problem :) just create new one
现在,如果您需要同一个类中的另一个记录器,没问题:) 只需创建一个新记录器
// create logger
Logger otherCustomLogger = Logger.getLogger("myOtherCustomLogName");
now see the code above and create new fileappender so your output will be sent in other file
现在查看上面的代码并创建新的 fileappender 以便您的输出将在其他文件中发送
This is usefull for (at least) 2 situations
这对(至少)两种情况很有用
when you want separate error from info and warns
when you manage multiple processes and you need output from each process
当您希望将错误与信息分开并发出警告时
当您管理多个流程并且需要每个流程的输出时
ps. have questions ? feel free to ask! :)
附:有问题吗?随时问!:)
回答by Qaiser Habib
If your application is following SOA principles, for every service A you'll have the following components:
如果您的应用程序遵循 SOA 原则,对于每个服务 A,您将拥有以下组件:
- A Controller
- A Service Implementation
- A Executor
- A Persistance
- 控制器
- 服务实现
- 执行者
- 坚持
So it makes life easier to have a aController.log aService.log aExecutor.log and aPersistance.log
因此,拥有 aController.log aService.log aExecutor.log 和 aPersistance.log 让生活更轻松
This is a layer based separation so all your Remoting/REST/SOAP classes will write to the aController.log
这是一个基于层的分离,因此您所有的 Remoting/REST/SOAP 类都将写入 aController.log
All your scheduling mechanism, backend service etc will write to aService.log
您所有的调度机制、后端服务等都将写入 aService.log
And all task executions are written to aExecutor.log and so on.
并且所有任务执行都写入aExecutor.log等。
If you have a multi-threaded executor you might have to use a log accumulator or another technique to properly align log messages for multiple threads.
如果您有一个多线程执行器,您可能必须使用日志累加器或其他技术来正确对齐多个线程的日志消息。
This way you'll always have 4 log files which is not alot and not too less, I'm telling you from experience this makes life really easier.
通过这种方式,您将始终拥有 4 个不会太多也不会太少的日志文件,我从经验中告诉您,这会让生活变得更加轻松。