Logging

来源:互联网 发布:淘宝客推广思路 编辑:程序博客网 时间:2024/05/19 01:08

Logging

Logging is a very important dependency for Spring because a) it is the only mandatory external dependency, b) everyone likes to see some output from the tools they are using, and c) Spring integrates with lots of other tools all of which have also made a choice of logging dependency. One of the goals of an application developer is often to have unified logging configured in a central place for the whole application, including all external components. This is more difficult than it might have been since there are so many choices of logging framework.


日志记录是Spring中非常重要的组件,因为
- 他是唯一一个强制的外部依赖
- 每个人都希望从他们使用的工具得到一些输出
- Spring 集成了许多的工具,它们都有对日志系统的依赖
程序员最大的问题之一就是对于整个程序有一个统一的日志配置中心,包括所有的外部依赖。这是非常难以选择的,因为有太多的日志框架。


The mandatory logging dependency in Spring is the Jakarta Commons Logging API (JCL). We compile against JCL and we also make JCL Log objects visible for classes that extend the Spring Framework. It’s important to users that all versions of Spring use the same logging library: migration is easy because backwards compatibility is preserved even with applications that extend Spring. The way we do this is to make one of the modules in Spring depend explicitly on commons-logging (the canonical implementation of JCL), and then make all the other modules depend on that at compile time. If you are using Maven for example, and wondering where you picked up the dependency on commons-logging, then it is from Spring and specifically from the central module called spring-core.


Spring中强制性的日志依赖关系是Jakarta Commons Logging API (JCL) ,我们针对JCL进行了编译,并且使 JCL Log 对象对于 实现了Spring Framework的类是可见的,对用户来说,所有版本的Spring使用相同的日志库是非常重要的:迁移是很简单的,因为Spring的扩展应用保留了向后兼容。我们的做法是,让Spring中的一个模块明确的依赖于commons-logging(JCl 的规范实现),然后其他的模块在编译的时候都依赖于它。如果你使用的Maven 你想知道在什么地方选择 commons-logging的依赖关系。他是来自spring的,来自Spring叫做 Spring-core的中心模块。


The nice thing about commons-logging is that you don’t need anything else to make your application work. It has a runtime discovery algorithm that looks for other logging frameworks in well known places on the classpath and uses one that it thinks is appropriate (or you can tell it which one if you need to). If nothing else is available you get pretty nice looking logs just from the JDK (java.util.logging or JUL for short). You should find that your Spring application works and logs happily to the console out of the box in most situations, and that’s important.


比较nice的是 使用commons-logging的时候你不再需要其他任何东西,你的app就可以正常运行。他有一个运行时检测算法,在意在类路径中检测检测其他的logging 框架,然后选择一个合适的框架(或者你可以指定一个框架)如果没有可用的框架,你可以从JDK(
java.util.logging 或 JUL for short)中得到一个漂亮的日志记录。大多数情况下 你会发现你的app日志很好的输出到了控制台(Console)中,并且这很重要


Not Using Commons Logging

不使用Commons Logging


Unfortunately, the runtime discovery algorithm in commons-logging, while convenient for the end-user, is problematic. If we could turn back the clock and start Spring now as a new project it would use a different logging dependency. The first choice would probably be the Simple Logging Facade for Java ( SLF4J), which is also used by a lot of other tools that people use with Spring inside their applications.


不幸的是,对于终端用户来说 commons-logging 的运行时发现算法是有问题的,我们往回走,然后开始使用Spring新建一个项目,他将会使用不同的日志记录依赖,第一选择可能是SLF4J(simple logging facade for java)。人们在它们的app中使用Spring的很多工具也使用了SLF4J.

There are basically two ways to switch off commons-logging:


这里有两种方式类关闭 commons-logging:

Exclude the dependency from the spring-core module (as it is the only module that explicitly depends on commons-logging)


从Spring core模块中排除依赖关系(因为commons-loggin是唯一明确依赖关系的模块)


Depend on a special commons-logging dependency that replaces the library with an empty jar (more details can be found in the SLF4J FAQ)


因为commons logging 的特殊的依赖关系,可以使用空的jar替换(更多细节可以使用 SLF4J FAQ)


To exclude commons-logging, add the following to your dependencyManagement section:


要排除commons-logging ,需要在 dependencyManagement 部分添加以下内容。

<dependencies>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-core</artifactId>        <version>5.0.0.BUILD-SNAPSHOT</version>        <exclusions>            <exclusion>                <groupId>commons-logging</groupId>                <artifactId>commons-logging</artifactId>            </exclusion>        </exclusions>    </dependency></dependencies>

Now this application is probably broken because there is no implementation of the JCL API on the classpath, so to fix it a new one has to be provided. In the next section we show you how to provide an alternative implementation of JCL using SLF4J as an example.


先在这个app已经被破坏了,因为在classpath中没有了JCL API的 实现了。所以必须提供一个新的JCL API 实现需要修复它。下一部分我们将想你展示 使用 SLF4J 来替代实现 JCL.

Using SLF4J

使用SLF4J

SLF4J is a cleaner dependency and more efficient at runtime than commons-logging because it uses compile-time bindings instead of runtime discovery of the other logging frameworks it integrates. This also means that you have to be more explicit about what you want to happen at runtime, and declare it or configure it accordingly. SLF4J provides bindings to many common logging frameworks, so you can usually choose one that you already use, and bind to that for configuration and management.


SLG4J依赖更清洁,并且运行时相比于commons-logging 小类更高,因为它采用的是 编译时绑定,而并不是在运行的时候发现并绑定其他logging框架,这也意味这你必须明确的指出你项在运行的时候得到什么并且相应的声明以及配置。SLF4J支持对多数常见的logging框架的绑定,所以你可以使用你已经使用的日志框架,绑定到SLF4J到用来进行配置以及管理。


SLF4J provides bindings to many common logging frameworks, including JCL, and it also does the reverse: bridges between other logging frameworks and itself. So to use SLF4J with Spring you need to replace the commons-logging dependency with the SLF4J-JCL bridge. Once you have done that then logging calls from within Spring will be translated into logging calls to the SLF4J API, so if other libraries in your application use that API, then you have a single place to configure and manage logging.


SLF4J支持帮到多数logging框架。包括JCL,同时SLF4J也是其他logging框架于SLF4J本身的桥梁,所以要在Spring使用SLF4J必必须使用SLFGJ-JCL桥来替代commons-logging依赖。完成替换后,Spring中对日志系统的调用,将会替换成对SLF4J API的调用,如果应用中的其它库使用了这个API,然后将需要一个统一的地方用于配置和管理日志。


A common choice might be to bridge Spring to SLF4J, and then provide explicit binding from SLF4J to Log4j. You need to supply several dependencies (and exclude the existing commons-logging): the bridge, the SLF4J implementation for Log4j, and the Log4j implementation itself. In Maven you would do that like this:


通常的选择是使用SLF4J 桥接到Spring,然后显式的绑定Log4j到SLF4J中。你需要提供几个依赖(且排除掉commons-logging) 桥接器(jcl-over-slf4j), Log4j 的 SLF4J 实现(log4j-slf4j-impl)以及Log4j本身(log4j-core,log4j-api).使用Maven你需要如下这样处理。

<dependencies>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-core</artifactId>        <version>5.0.0.BUILD-SNAPSHOT</version>        <exclusions>            <exclusion>                <groupId>commons-logging</groupId>                <artifactId>commons-logging</artifactId>            </exclusion>        </exclusions>    </dependency>    <dependency>        <groupId>org.slf4j</groupId>        <artifactId>jcl-over-slf4j</artifactId>        <version>1.7.22</version>    </dependency>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-slf4j-impl</artifactId>        <version>2.7</version>    </dependency>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-api</artifactId>        <version>2.7</version>    </dependency>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-core</artifactId>        <version>2.7</version>    </dependency></dependencies>

That might seem like a lot of dependencies just to get some logging. Well it is, but it is optional, and it should behave better than the vanilla commons-logging with respect to classloader issues, notably if you are in a strict container like an OSGi platform. Allegedly there is also a performance benefit because the bindings are at compile-time not runtime.


那么看起来这么多的依赖只是仅仅用于获取一些日志。是得没错,但是他是可选的,在类加载器问题上,它应该表现得比commons-logging更好,尤其是在像OSGi这样严格的容器中。同时还有另外一个有事,他的绑定实在编译过程中,而非运行时。

A more common choice amongst SLF4J users, which uses fewer steps and generates fewer dependencies, is to bind directly to Logback. This removes the extra binding step because Logback implements SLF4J directly, so you only need to depend on two libraries not four ( jcl-over-slf4j and logback). If you do that you might also need to exclude the slf4j-api dependency from other external dependencies (not Spring), because you only want one version of that API on the classpath.


对于使用SLF4J的用户来说直接绑定到 Logback貌似更加普遍。使用要更少的步骤,生成更少的依赖。这样移除了额外的绑定因为Logback直接实现了SLF4J,所以仅仅需要两个库即可(jcl-over-slf4j和logback)而不用四个库。如果这样做的化,还需要把slf4j-api依赖从其它外部依赖中排除掉(不是Spring),因为在classpath下仅仅需要该API的一个版本。


Using Log4j

使用LOG4J

注意Log4j 1.x i 是 EOL (end of life),以下方法适用于 to Log4j 2.x

Many people use Log4j as a logging framework for configuration and management purposes. It’s efficient and well-established, and in fact it’s what we use at runtime when we build and test Spring. Spring also provides some utilities for configuring and initializing Log4j, so it has an optional compile-time dependency on Log4j in some modules.


许多热使用Log4j 作为日志配置管理框架,他本身也是高效成熟的产品。我们在构建 和测试Spring 的时候就使用的是Log4j,Spring也提供了一些工具用于配置和初始化Log4J,所以某些模块在编译期可以选择依赖于Log4J。


To use Log4j with JCL, all you need to do is put Log4j on the classpath and provide it with a configuration file (log4j2.xml, log4j2.properties, or other supported configuration formats). For Maven users, the minimal dependencies needed are:


要在JCL上使用Log4j你需要将Log4j放在classpath中,并且创建一个配置文件(log4j2.xml, log4j2.properties, 或者其他支持的格式),对于Maven用户来说,所需的最小依赖关系如下。、

<dependencies>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-core</artifactId>        <version>2.7</version>    </dependency>    <dependency>        <groupId>org.apache.logging.log4j</groupId>        <artifactId>log4j-jcl</artifactId>        <version>2.7</version>    </dependency></dependencies>

If you also wish to use SLF4J, the following dependencies are also needed:


如果你还想使用SlF4J,还需要以下的依赖。

<dependencies>  <dependency>    <groupId>org.apache.logging.log4j</groupId>    <artifactId>log4j-slf4j-impl</artifactId>    <version>2.7</version>  </dependency></dependencies>

Here is an example log4j2.xml for logging to the console:
如下是 log4j2.xml的一个例子,用于输出日志到控制台

<?xml version="1.0" encoding="UTF-8"?><Configuration status="WARN">  <Appenders>    <Console name="Console" target="SYSTEM_OUT">      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>    </Console>  </Appenders>  <Loggers>    <Logger name="org.springframework.beans.factory" level="DEBUG"/>    <Root level="error">      <AppenderRef ref="Console"/>    </Root>  </Loggers></Configuration>

Runtime Containers with Native JCL

带有Native JCL的运行容器。

Many people run their Spring applications in a container that itself provides an implementation of JCL. IBM Websphere Application Server (WAS) is the archetype. This often causes problems, and unfortunately there is no silver bullet solution; simply excluding commons-logging from your application is not enough in most situations.


很多人在本身提供了JCL的容器中运行它们的程序。 IBM Websphere 应用服务器(WAS)就是这种框架。这通常会有一些问题,不幸的是并没有解决这个问题的银弹,多数情况下,紧紧移除 commons-logging 是不够的。

To be clear about this: the problems reported are usually not with JCL per se, or even with commons-logging: rather they are to do with binding commons-logging to another framework (often Log4j). This can fail because commons-logging changed the way they do the runtime discovery in between the older versions (1.0) found in some containers and the modern versions that most people use now (1.1). Spring does not use any unusual parts of the JCL API, so nothing breaks there, but as soon as Spring or your application tries to do any logging you can find that the bindings to Log4j are not working.


要清楚这点,问题的本身于JCL或者 commons-logging都没有关系,而是于绑定commons-logging 搭配去哦呀框架有关(Log4j),这可能会出问题,因为commons-logging 在1.0 版本到1.1 版本中改变了 运行时检测的方式,Spring 没有使用JCL API的其他部分所以不出出现问题,但是一旦Spring或者你的应用程序尝试做日志记录是,,你会发现绑定到log4j无效了。

In such cases with WAS the easiest thing to do is to invert the class loader hierarchy (IBM calls it “parent last”) so that the application controls the JCL dependency, not the container. That option isn’t always open, but there are plenty of other suggestions in the public domain for alternative approaches, and your mileage may vary depending on the exact version and feature set of the container.

在WAS这个案例中,最简单的方法就是倒置类加载器的继承(IBM称作“parent last”,即把父类放后面),以便应用程序而不是容器控制JCL依赖。这种选择并不总是管用的,在公共领域有很多其它建议的替代方案,且你的里程可能会随着确切的版本和容器的特性而改变。(译者注:此处的意思是上面介绍的方法并不是唯一的,需要根据不同的版本和容器作出相应的方案)

原创粉丝点击