1 Star 0 Fork 20

shiyifeng / sofa-common-tools

forked from SOFAStack / sofa-common-tools 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

sofa-common-tools

Coverage Status License maven

sofa-common-tools 是 SOFAStack 中间件依赖的一个通用工具包,通过自动感知应用的日志实现,提供中间件与应用隔离的日志空间打印能力。

一、背景

在日常开发中,应用避免不了都会打印日志,可能采用的通用日志接口开发框架 SLF4J,而对于具体的日志实现最常用的是 Logback、Log4j2 或者 Log4j。假设应用依赖的二方包其要使用的日志实现是 Log4j2,而应用一直使用的日志实现是 Log4j,而当应用要集成这个二方包时会发现由于两边依赖的日志实现不同引入的冲突无法解决,从而导致集成失败。

为了解决上面描述的问题,常用的几种办法是:

  1. 二方包修改日志实现依赖,将其改为只依赖 Log4j 的实现类;或者改为面向 SLF4J 的编程接口打印日志,然后在集成应用中配置相应的 appenderlogger 以确定日志输出目录和文件。
  2. 应用修改,修改为使用 Log4j2 的日志打印方式,并同时在集成应用中配置相应的 appenderlogger 以确定日志输出目录和文件。

不管是两种方法中的哪一种,都需要修改相应的日志实现以统一到使用相同的日志实现去打印并同时需要配置日志文件的输出目录。那么有没有一种办法,在同样的一个 class path 下,都是由同一个 ClassLoader 加载的类,保证二方包或者引入的中间件其不用任何配置就可以完成日志文件相对固定目录的输出并能够统一日志实现?或者说引入的二方包遵循一定的标准进行配置后,能够感知到 Logback、Log4j2 或者 Log4j 并能够将日志文件输出在相对固定的目录?

答案是有的,开源的此 sofa-common-tools 就是在框架层面提供了解决方案,即二方包或者引入的中间件也只面向日志编程接口 SLF4J 去编程不直接使用具体日志实现的 API,具体的日志实现的选择权利交给应用开发者去选择,同时二方包或者中间件针对每一个日志实现提供了配置以输出日志到相对固定目录和文件。应用选择哪一个日志实现,这个框架就自动发现并选择应用开发者的日志实现进行打印并输出到相对固定目录和文件。

根据 sofa-common-tools 的规范对常用日志实现(Logback、Log4j2 和 Log4j)均进行配置(配置日志输出文件和格式),当应用引入二方包或者中间件时,根据应用中已有的日志实现并选择该日志实现能够正确解析的配置文件来初始化完成二方包或者中间件的日志配置来完成日志的输出,并同时不会和某一个具体日志实现绑定。从而完成在不用业务配置额外的 appenderlogger 或者业务不用修改任何配置的情况下,完成日志空间打印的隔离能力。

前提:需要统一日志编程接口到 SLF4J

二、使用场景和快速开始

2.1 使用场景和目标

期望达到日志打印隔离的目的:使用此日志打印隔离框架的中间件或者二方库的依赖中不直接使用具体日志实现的 API 或者说不会和某一个日志实现绑定,避免干扰将要接入的应用指定的日志实现,但中间件或者二方库能够自动发现应用环境(或者说 classpath)内引入的日志实现,Logback、Log4j2 或者 Log4j,并按照相应的优先级只使用其中一份配置进行日志输出。

2.2 快速开始

假设 RPC 接入,并定义的 SpaceId 的关键属性是 com.alipay.sofa.rpc

首先,需要根据 SpaceId 和日志打印隔离框架的关键 API 自定义一个 LoggerFactory,如:

public class RpcLoggerFactory {

    private static final String RPC_LOG_SPACE = "com.alipay.sofa.rpc";

    static {
        //SpaceId init properties
        Map spaceIdProperties = new HashMap<String, String>();
        MultiAppLoggerSpaceManager.init(RPC_LOG_SPACE, spaceIdProperties);
    }

    public static org.slf4j.Logger getLogger(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }
        return getLogger(clazz.getCanonicalName());
    }

    public static org.slf4j.Logger getLogger(String name) {
        //From "com/alipay/sofa/rpc/log" get the xml configuration and init,then get the logger object
        return MultiAppLoggerSpaceManager.getLoggerBySpace(name, RPC_LOG_SPACE);
    }
}

定义的 RpcLoggerFactory 主要定义自己的 SpaceId 并通过 MultiAppLoggerSpaceManager.init 完成初始化,同时抽象出一个 RpcLoggerFactory 方便代码中直接复用,初始化参数中可以针对当前的 SpaceId 设置一些属性参数用于在解析配置文件时完成对相应属性占位符的值替换。当然也提供了简化版的 API 即 LoggerSpaceManager 大家也可以使用。

其次,在指定的 SpaceId 资源路径下编写针对不同日志实现 Logback、Log4j2 和 Log4j 的日志配置文件,具体的文件路径为:

└── com
    └── alipay
        └── sofa
            └── rpc
                └── log
                    ├── log4j
                    │   └── log-conf.xml
                    ├── log4j2
                    │   └── log-conf.xml
                    └──  logback
                        └── log-conf.xml

需要注意的是在每一个日志实现目录标识下的配置文件都编写对应日志实现能够解析的配置,如 logback 目录下的配置 log-conf.xml 应该是 Logback 能够解析的配置文件,否则将会报错。

最后,直接使用并测试验证

public class LoggerSpaceManagerUsage {
    public static void main(String[] args) {
        Logger rpcLogger = RpcLoggerFactory.getLogger("com.alipay.foo");
        rpcLogger.debug("hello world");
    }
}

如果 classpath 中引用的是 Logback 依赖作为日志打印框架,并在 logback/log-conf.xml 日志打印文件配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="UTF-8">
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="com.foo.Bar" level="${logging.level.com.alipay.sofa.rpc}" additivity="false">
        <appender-ref ref="stdout"/>
    </logger>

    <root level="DEBUG">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

控制台中包含如下的日志打印内容:

Sofa-Middleware-Log SLF4J : Actual binding is of type [ com.alipay.sofa.rpc Logback ]
17:42:41.083 [main] DEBUG com.alipay.foo - hello world

三、功能特性

3.1 日志配置的系统属性

变量名 在日志 xml 配置文件中使用样式 默认值 系统属性指定
logging.path ${logging.path} ${user.home} -Dlogging.path=/home/admin/logs
file.encoding ${file.encoding} UTF-8 -Dfile.encoding=UTF-8
logging.level.{spaceName} ,以 RPC 为例:logging.level.com.alipay.sofa.rpc ${logging.level.com.alipay.sofa.rpc} INFO -Dlogging.level.com.alipay.sofa.rpc=WARN
logging.path.{spaceName} ,以 RPC 为例:logging.path.com.alipay.sofa.rpc ${logging.path.com.alipay.sofa.rpc} ${logging.path.com.alipay.sofa.rpc} -Dlogging.path.com.alipay.sofa.rpc=/home/admin/logs/appname

3.2 关闭日志实现打印独立功能

  1. 关闭日志实现独立打印能力:通过系统属性 -Dsofa.middleware.log.disable=true。也许你暂时不希望二方库或者中间件的日志打印到独立目录下,希望集中打印方便本地开发和跑测试用例时集中显示,那么可以借助上面开关,关闭日志独立打印能力,注意这个是全部关闭即禁用掉中间件的独立日志空间功能。

  2. 关闭指定日志开关:作用是可以在大家完成编码,进行单元测试的时候,在所有的日志实现都引入 classpath后(当然都是 scope 为 test 的引入),可以采用这种方法自动化测试用例,如下面这种方式关闭掉 Logback 和 Log4j2,就可以单独测试在独立的日志空间下 Log4j 的正确使用:

//禁用logback
System.setProperty(Constants.LOGBACK_MIDDLEWARE_LOG_DISABLE_PROP_KEY, "true");
//禁用log4j
System.setProperty(Constants.LOG4J_MIDDLEWARE_LOG_DISABLE_PROP_KEY, "true");

对应的几个日志实现独立打印能力的单独系统属性开关分别如下,设置相应的系统属性为 true 机会关闭对应的日志实现单独打印能力:

//Class : com.alipay.sofa.common.log.Constants
//禁用log4j日志实现
String LOG4J_MIDDLEWARE_LOG_DISABLE_PROP_KEY = "log4j.middleware.log.disable";
//禁用log4j2日志实现
String LOG4J2_MIDDLEWARE_LOG_DISABLE_PROP_KEY ="log4j2.middleware.log.disable";
//禁用logback日志实现
String LOGBACK_MIDDLEWARE_LOG_DISABLE_PROP_KEY = "logback.middleware.log.disable";

3.3 提供动态改变日志级别的能力

考虑到主流的日志实现框架 Logback、Log4j2 和 Log4j 定义的日志级别并且没有统一起来,即没有定义一个统一的日志级别管控 API,这样就导致在 slf4j-api 这个接口层面无法提供统一的一个入口作为日志级别标准。但是在某种情形下需要去动态改变日志级别,所以在 sofa-common-toos 中提供了基于SpaceIdLoggerName 的日志级别改变能力。

sofa-common-tools日志级别定义为一个枚举类型,通过这个枚举类型并根据具体的日志实现,映射到具体的日志实现的级别上,通过此适配器方式来屏蔽不同日志实现所定义的级别差异:

具体提供的 API 为:

com.alipay.sofa.common.log.LoggerSpaceManager#setLoggerLevel

而对应的日志枚举级别为:com.alipay.sofa.common.log.adapter.level.AdapterLevel,提供如下几种级别的适配:

public enum AdapterLevel {

    /**
     * An error in the application, possibly recoverable.
     */
    ERROR("error"),

    /**
     * An event that might possible lead to an error.
     */
    WARN("warn"),

    /**
     * An event for informational purposes.
     */
    INFO("info"),

    /**
     * A general debugging event.
     */
    DEBUG("debug"),

    /**
     * A fine-grained debug message, typically capturing the flow through the application.
     */
    TRACE("trace");
}

四、配置说明

sofa.middleware.log.disable

默认配置为 false, 禁止所有 logback/log4j/log4j2 日志打印. 日志默认打印在 ROOT Appender.

注: 该配置项只支持通过 -D 作为 VM 参数传入,例如 -Dsofa.middleware.log.disable=true

logback.middleware.log.disable

默认配置为 false, 禁止使用 logback 日志实现

注: 该配置项只支持通过 -D 作为 VM 参数传入,例如 -Dlogback.middleware.log.disable=true

log4j2.middleware.log.disable

默认配置为 false, 禁止使用 log4j2 日志实现

注: 该配置项只支持通过 -D 作为 VM 参数传入,例如 -Dlog4j2.middleware.log.disable=true

log4j.middleware.log.disable

默认配置为 false, 禁止使用 log4j 日志实现

注: 该配置项只支持通过 -D 作为 VM 参数传入,例如 -Dlog4j.middleware.log.disable=true

自身日志级别配置

sofa-common-tools 在初始化绑定日志实现类时,会使用 System.out 打印详情信息,例如:

Sofa-Middleware-Log:DEBUG  Actual binding is of type [ test.space Logback ]

可以通过 sofa.middleware.log.internal.level=debug 设置改日志类型打印级别,默认为 INFO.

注: 该配置项只支持通过 -D 作为 VM 参数传入,例如 -Dsofa.middleware.log.internal.level=debug

配置日志级别

  • 全局配置:支持使用 * 通配符配置,例如 logging.level.com.* = info, 则 logging.levle.com.alipay.sofa.rpc 日志空间的级别为 info
  • 单个日志空间配置:logging.level.${spaceid}=info,例如 logging.levle.com.alipay.sofa.rpc=info。则 RPC 日志空间级别为 info

支持通过 -D 作为 VM 参数传入以及在 Spring Boot 的 application.yml 配置文件传入(依赖 log-sofa-boot-starter)

自定义日志配置文件

每个人日志空间中,logback/log4j2/log4j 都会提供一份默认的日志配置文件,可以使用 logging.config.{space id}=log-conf-xx.xml 覆盖默认配置文件。

支持通过 -D 作为 VM 参数传入以及在 Spring Boot 的 application.yml 配置文件传入(依赖 log-sofa-boot-starter)

日志打印控制台

  • 全局配置
    • 开关 sofa.middleware.log.console 将所有日志空间均打印在 console 端, 默认为 false.
    • 日志级别控制 sofa.middleware.log.console.level 配置所有打印在 console 端的日志空间级别,默认为 INFO.
  • 日志空间独立配置
    • 开关 sofa.middleware.log.${spaceid}.console 指定 space id 日志空间打印在 console 端,默认为 false. 优先级高于全局配置。
    • 日志级别控制 sofa.middleware.log.{space id}.console.level 配置 space id 日志空间打印在 console 的日志级别,默认为 INFO. 优先级高于全局配置。

支持通过 -D 作为 VM 参数传入以及在 Spring Boot 的 application.yml 配置文件传入(依赖 log-sofa-boot-starter)

控制台日志格式

  • logback: sofa.middleware.log.console.logback.pattern 配置打印在 console 端的 logback 日志格式. 默认为 %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n
  • log4j2: sofa.middleware.log.console.log4j2.pattern 配置打印在 console 端的 log4j 日志格式. 默认为 %d{yyyy-MM-dd HH:mm:ss.SSS} %5p %X{PID} --- [%15.15t] %-40.40logger{39} : %m%n

支持通过 -D 作为 VM 参数传入以及在 Spring Boot 的 application.yml 配置文件传入(依赖 log-sofa-boot-starter)

五、编译

Maven 3.2.5+, JDK Version 1.7+

六、LICENSE

Apache 2.0

七、Contribution

Contribution Guide

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

sofa-common-tools 是 SOFAStack 中间件依赖的一个通用工具包,通过自动感知应用的日志实现,提供中间件与应用隔离的日志空间打印能力 展开 收起
Java
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/shiyifeng/sofa-common-tools.git
git@gitee.com:shiyifeng/sofa-common-tools.git
shiyifeng
sofa-common-tools
sofa-common-tools
master

搜索帮助