我的应用程序将部署在tcServer和WebSphere 6.1上.此应用程序使用ehCache,因此需要slf4j作为依赖项.结果我将slf4j-api.jar(1.6)jar添加到我的war文件包中.
该应用程序在tcServer中正常工作,但以下错误除外:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Run Code Online (Sandbox Code Playgroud)
但是,当我在WebSphere中部署时,我得到了一个java.lang.NoClassDefFoundError: org.slf4j.impl.StaticLoggerBinder
.
我检查了两个应用程序服务器的类路径,没有其他的slf4j jar.
有没有人有任何想法可能会发生在这里?
这是我生命中的第一次,我发现自己处于一个可以开源的Java API的位置.希望被包括在许多其他项目中.
对于日志记录我(以及与我一起工作的人)总是使用JUL(java.util.logging)并且从未遇到任何问题.但是现在我需要更详细地了解我应该为我的API开发做些什么.我已经对此做了一些研究,并且我得到的信息让我感到更加困惑.因此这篇文章.
由于我来自JUL,我对此持偏见态度.我对其余的知识并不是那么大.
从我所做的研究中我得出了人们不喜欢JUL的原因:
"在Sun发布JUL之前,我开始使用Java进行开发,而且我更容易继续使用logging-framework-X而不是学习新东西".嗯.我不是在开玩笑,这实际上就是人们所说的.有了这个论点,我们都可以做COBOL.(但我当然可以说这是一个懒惰的家伙)
"我不喜欢JUL中日志记录级别的名称".好吧,说真的,这还不足以成为引入新依赖的理由.
"我不喜欢JUL输出的标准格式".嗯.这只是配置.你甚至不需要做任何代码方面的事情.(确实,过去你可能不得不创建自己的Formatter类来实现它).
"我使用其他也使用logging-framework-X的库,所以我觉得使用那个更容易".这是一个循环论证,不是吗?为什么'每个人'都使用logging-framework-X而不是JUL?
"其他人都在使用logging-framework-X".这对我来说只是上面的一个特例.多数并不总是正确的.
所以真正的大问题是为什么不是JUL?.我错过了什么?伐木立面的存在理由(SLF4J,JCL)是历史上存在多种伐木实施,其原因可以追溯到JUL之前的时代,正如我所看到的那样.如果JUL是完美的那么伐木外墙将不存在,或者什么?我们不应该首先质疑为什么它们是必要的而不是拥抱它们?(看看这些原因是否仍然存在)
好吧,到目前为止我的研究已经导致我可以看到的一些事情可能是JUL的真正问题:
表现.有人说SLF4J的表现优于其他表现.在我看来,这是一个过早优化的案例.如果你需要每秒记录数百兆字节,那么无论如何我都不确定你是否在正确的路径上.JUL也在不断发展,你在Java 1.4上做的测试可能不再适用.你可以在这里阅读它,这个修复已经成为Java 7.许多人还谈到了日志记录方法中字符串连接的开销.但是,基于模板的日志记录可以避免这种成本,并且它也存在于JUL中.我个人从来没有真正编写基于模板的日志记录 太懒了.例如,如果我使用JUL执行此操作:
log.finest("Lookup request from username=" + username
+ ", valueX=" + valueX
+ ", valueY=" + valueY));
Run Code Online (Sandbox Code Playgroud)
我的IDE会警告我并请求允许它将其更改为:
log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}",
new Object[]{username, valueX, valueY});
Run Code Online (Sandbox Code Playgroud)
..我当然会接受.许可授予 !谢谢您的帮助.
所以我自己并没有自己编写这样的语句,这是由IDE完成的.
关于性能问题的结论我没有发现任何迹象表明JUL的表现与竞争对手相比并不好.
从类路径配置.开箱即用的JUL无法从类路径加载配置文件.要做到这一点,需要几行代码.我可以看出为什么这可能很烦人,但解决方案简短而简单.
输出处理程序的可用性.JUL带有5个开箱即用的输出处理程序:控制台,文件流,套接字和内存.这些可以扩展或可以编写新的.例如,这可能是写入UNIX/Linux Syslog和Windows事件日志.我个人从来没有这个要求,也没有看过它,但我当然可以说明为什么它可能是一个有用的功能.例如,Logback附带了Syslog的附加程序.我仍然会争辩
我真的很担心我忽略了一些东西.除了JUL之外,使用伐木外墙和伐木实施是如此普遍,我必须得出结论,我只是不明白.那恐怕不是第一次.:-)
那我该怎么办?我希望它成功.我当然可以"顺其自然"并实施SLF4J(这些日子似乎最受欢迎)但是为了我自己的缘故,我仍然需要明白今天的JUL究竟出了什么问题才能保证所有的模糊?我会为我的图书馆选择JUL来破坏自己吗?
(nolan600于2012年7月7日添加的部分)
下面有一篇来自Ceki的参考文献,其中提到SLF4J的参数化比JUL快10倍或更快.所以我开始做一些简单的测试.乍一看,这种说法肯定是正确的.以下是初步结果(但请继续阅读!):
上面的数字是msecs,所以越少越好.因此,10倍的性能差异实际上非常接近.我最初的反应:这是很多!
这是测试的核心.可以看出,整数和字符串是在循环中构造的,然后在log语句中使用:
for …
Run Code Online (Sandbox Code Playgroud) 记录填充消息和异常堆栈跟踪的正确方法是什么?
logger.error(
"\ncontext info one two three: {} {} {}\n",
new Object[] {"1", "2", "3"},
new Exception("something went wrong"));
Run Code Online (Sandbox Code Playgroud)
我想生成类似于此的输出:
context info one two three: 1 2 3
java.lang.Exception: something went wrong
stacktrace 0
stacktrace 1
stacktrace ...
Run Code Online (Sandbox Code Playgroud)
slf4j版本1.6.1
我收到以下错误.似乎有多个日志框架绑定到sl4j.不知道如何解决这个问题.任何帮助是极大的赞赏.
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/admin/.m2/repository/org/slf4j/slf4j-log4j12/1.6.4/slf4j-log4j12-1.6.4.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/admin/.m2/repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
Run Code Online (Sandbox Code Playgroud) 我是log4j
第一次尝试使用SLF4J(带绑定).
我想配置3个不同的名为Logger,它们可以由LoggerFactory返回,它将记录不同的级别并将消息推送到不同的appender:
DailyRollingFileAppender
JmsAppender
JmsAppender
此外,我希望它们以编程方式配置(在Java中,而不是XML或log4j.properties
文件).
我想,通常情况下,我会Logger
在某些引导代码中将它们定义为某个init()
方法,就像方法一样.但是,因为我想使用slf4j-log4j
,我很困惑我可以在哪里定义记录器并使它们可用于类路径.
我不认为这违反了SLF4J的基本目的(作为一个外观),因为我使用SLF4J API的代码永远不会知道这些记录器存在.我的代码只是对SLF4J API进行正常调用,然后将它们转发到它在类路径上找到的log4j Loggers.
但是如何在类路径中配置那些log4j记录器...在Java中?!
api 1.7和slf4j-simple as implementation.我只是找不到如何使用此组合配置日志记录级别.
任何人都可以帮忙吗?
我正在使用logback/slf4j进行日志记录.我想解析我的日志文件来分析一些数据,所以我想要有两个记录器实例,每个记录器实例都记录到一个单独的文件中,而不是解析一个很棒的大文件(主要由调试语句组成); 一个用于分析,一个用于所有目的的日志记录.有没有人知道这是否可以使用Logback或任何其他记录器?
在我们的软件中,我们广泛使用MDC来跟踪会话ID和Web请求的用户名等内容.这在原始线程中运行时工作正常.但是,有很多事情需要在后台处理.为此,我们使用java.concurrent.ThreadPoolExecutor
和java.util.Timer
类以及一些自动异步执行服务.所有这些服务都管理自己的线程池.
这就是Logback的手册在这样的环境中使用MDC所要说的:
映射的诊断上下文的副本不能始终由来自启动线程的工作线程继承.当java.util.concurrent.Executors用于线程管理时就是这种情况.例如,newCachedThreadPool方法创建一个ThreadPoolExecutor,就像其他线程池代码一样,它具有复杂的线程创建逻辑.
在这种情况下,建议在将任务提交给执行程序之前,在原始(主)线程上调用MDC.getCopyOfContextMap().当任务运行时,作为其第一个操作,它应调用MDC.setContextMapValues()以将原始MDC值的存储副本与新的Executor托管线程相关联.
这样会很好,但是很容易忘记添加这些调用,并且没有简单的方法来识别问题,直到为时已晚.Log4j的唯一标志是您在日志中丢失了MDC信息,而使用Logback,您会收到过时的MDC信息(因为胎面池中的线程从其上运行的第一个任务继承其MDC).两者都是生产系统中的严重问题.
我不认为我们的情况有任何特殊之处,但我在网上找不到这个问题.显然,这不是很多人碰到的东西,所以必须有办法避免它.我们在这做错了什么?
我们在我们的项目中使用SLF4J + Logback组合已经有一段时间了,并且对它非常满意,但是我们的日志记录策略相当简单,使用简单的基于类的记录器并且没有像MDC或Markers这样的花哨的东西.
我想知道的是,社区中是否有人实际使用这些功能以及它们如何用于改进日志记录/过滤.
我特别感兴趣的是在哪里,为什么以及如何使用[1]标记进行记录.他们认为这是一个非常简洁的功能,可以在记录中添加语义上下文 - 例如,当一个类可能正在处理多个问题时,可以使用任务/关注特定标记来区分日志语句.
在日志记录中创建和使用标记的最佳实践,约定或策略可能是什么.
更新:我想,我真正追求的不是为什么使用标记,而是如何使用标记- 是否有一些命名标记的好方法(例如使用带空格的明文或短划线/下划线/标点符号分隔的关键字样式名称),是否应该有某种"标准名称"池,根据业务功能命名.我可以为自己解决的问题,但如果我想系统地使用这些功能并将它们介绍给开发人员团队,那么就可以制定一些可正式的指导方针......
[1] - 通过询问如何使用标记我并不是真的问如何使用API(它确实非常直接) - 我更倾向于指出如何设置使用标记一致地记录的更一般级别
为什么人们会使用以下其中一个而不是另一个?