登录样式:log4j 2,上下文,自动清理…全部不附带任何字符串!

日志记录-保持操作的时间跟踪-对于任何关键任务系统,无论大小,都至关重要。 我们的Project-X框架也是如此 ,这就是为什么我们希望从一开始就正确地做到这一点。

基于我们在传奇的UltraESB上的登录经验, 上下文日志记录(每条日志行自动记录其原始逻辑上下文,例如它来自特定单元还是来自基础框架)是我们一直期待的事情 。

我们已经知道log4j2通过其CloseableThreadContext实现提供了上下文日志记录 ,几乎包含了我们所需要的一切。 但我们需要更多:

  1. 我们需要一个合适的日志代码管理机制,其中每个日志行包含一个唯一的日志代码,分别表示子系统,模块(包),甚至是特定的日志语句的准确“指标”,这样我们就不再需要grep通过整个代码库,以找出bugger的来源。
  2. 我们需要注入具有特定前缀的环境变量和系统属性,以将其自动注入到日志记录上下文中,以便特定的应用程序可以将其运行时参数注入日志(例如,对于我们的Integration Platform ,为集群ID )。

我们还需要独立于log4j2的API,因为我们应该保留与log4j2分离的自由,并在需要时利用其他日志记录框架(例如logback )。 尽管我们可以利用第三方包装器(例如SLF4J),但找不到适合所有需求的包装器。

因此,与以前的UltraESB一样,我们用x-logging封装了log4j2,这是我们自己的日志记录实现。 x-logging由一个API和一组到实际日志框架(例如log4j2和logback)的绑定组成,其中一个可以在服务器启动时使用Java宝贵的旧ServiceLoader机制动态地插入。 这可以帮助我们避免将log4j2特定内容泄漏到我们的实现中,因为可以将基于log4j2的实现(以及因此log4j2本身)从编译时依赖项集合中完全删除。

来自我们团队的Ruwan (也是Project-X的发起者)用log4j2破解了一段时间,最后提出了一个很酷的设计,可以自动传播日志行的当前上下文,即日志行是否源自平台(系统(又名engine )或已部署的项目 (如果是后者),则是该项目的其他元数据(例如版本)。 最酷的部分是,一旦执行离开特定上下文,该上下文将自动清理。

如果您熟悉CloseableThreadContext ,这听起来可能很简单。 对于其他人来说,只要提及CloseableThreadContext便可以将键值对注入到日志记录上下文中就足够了,这样在关闭上下文时,仅清除在当前上下文中注入的那些值。 注入的值将自动提供给调用线程的日志记录上下文( ThreadContext ); 或者用英语,该线程打印的每条日志行都会在其线程上下文中看到该参数(或者用老式的行话中的MDC )。

好的,我承认以上内容可能有点难以理解。 也许一个示例代码片段可能会做得更好:

// assume we are walking in, with nothing useful inside the contexttry (CloseableThreadContext.Instance level1 = CloseableThreadContext.put("level", "1")) {// now the context has "1" as "level"logger.debug("Commencing operation"); // will see {level=1} as the context// let's also put in a "clearance" valuelevel1.put("clearance", "nypd");// now, any log lines would see {level=1,clearance=nypd}// let's go deepertry (CloseableThreadContext.Instance level2 = CloseableThreadContext.put("level", "2").put("clearance", "fbi")) {// now both of the above "level" and "clearance" values are "masked" by the new ones// and yes, you can chain together the context mutationslogger.debug("Commencing investigation"); // will see {level=2,clearance=fbi}// putting in some morelevel2.put("access", "privileged");// now context is {level=2,clearance=fbi,access=privileged}// still deeper...try (CloseableThreadContext.Instance level3 = CloseableThreadContext.put("level", "3").put("clearance", "cia")) {// "level" and "clearance" are overridden, but "access" remains unchangedlogger.debug("Commencing consipracy"); // {level=3,clearance=cia,access=privileged}}// cool thing is, once you're out of the level3 block, the context will be restored to that of level2 (thanks to the AutoCloseable nature of CloseableThreadContext.Instance)logger.debug("Back to investigation"); // {level=2,clearance=fbi,access=privileged}}// same for exiting level 2logger.debug("Back to operation"); // {level=1,clearance=nypd}; access is gone!}logger.debug("Back to square one"); // {}; oh no, all gone!

该机制非常适合我们使用,因为我们需要包括线程的当前执行上下文以及该线程生成的每个日志行:

  1. 在Project-X ( UltraESB-X的基础引擎)中,维护在基本框架级别的辅助 线程池负责代表属于特定项目的集成流处理入站消息。
  2. 仅在将消息注入到特定集成流的入口连接器之后,我们才认为该线程位于项目的上下文中。 在此之前,工作线程应该做很多工作,所有这些工作都被认为属于system上下文。
  3. 我们会在整个过程中生成日志,因此应自动为它们添加适当的上下文标记。
  4. 而且,由于每个日志行都有特定的错误代码,因此,每次实际输出日志行时,我们都需要打开一个新的上下文,该日志行除了包含其他上下文参数外,还包含所需的日志代码。

因此,池中线程的生命周期将是一个无休止的循环,例如:

// wake up from thread pool// do system level stuffloggerA.debug(143, "Now I'm doing this cool thing : {}", param);try (CloseableThreadContext.Instance projectCtx = CloseableThreadContext.put("project", project.getName()).put("version", project.getVersion())) {// do project level stuffloggerM.debug(78, "About to get busy : {}", param);// more stuff, tra la la la
}// back to system level, do still more stuff// jump back to thread pool and have some sleep

在内部, loggerAloggerM等将最终调用logImpl(code, message, params)方法:

// context already has system/project info,
// logger already has a pre-computed codePrefixtry (CloseableThreadContext.Instance logCtx = CloseableThreadContext.put("logcode", codePrefix + code)) {// publish the actual log line
}// only "logcode" cleared from the context, others remain intact

我们通过引入一个CloseableContext接口来模拟这种行为,而不绑定到log4j2,该接口的log4j2变体(显然是Log4j2CloseableContext )将以相同的方式操作CloseableThreadContext实例:

import java.io.Closeable;public interface CloseableContext extends Closeable {CloseableContext append(final String key, final String value);void close();
}

和:

import org.adroitlogic.x.logging.CloseableContext;
import org.apache.logging.log4j.CloseableThreadContext;public class Log4j2CloseableContext implements CloseableContext {private final CloseableThreadContext.Instance ctx;/* Creates an instance wrapping a new default MDC instance*/Log4j2CloseableContext() {this.ctx = CloseableThreadContext.put("impl", "project-x");}/* Adds the provided key-value pair to the currently active log4j logging (thread) context** @param key   the key to be inserted into the context* @param value the value to be inserted, corresponding to {@code key}* @return the current instance, wrapping the same logging context*/@Overridepublic CloseableContext append(String key, String value) {ctx.put(key, value);return this;}/* Closes the log4j logging context wrapped by the current instance*/@Overridepublic void close() {ctx.close();}
}

现在,我们要做的就是通过一个不错的管理界面LogContextProvider打开一个适当的上下文:

// system context is active by default...try (CloseableContext projectCtx = LogContextProvider.forProject(project.getName(), project.getVersion())) {// now in project context}// back to system context

logImpl

try (CloseableContext logCtx = LogContextProvider.overlayContext("logcode", codePrefix + code)) {// call the underlying logging framework
}

由于我们将CloseableContext实现与记录器绑定一起加载(通过ServiceLoader ),因此我们知道LogContextProvider最终将最终调用正确的实现。

这就是我们的x-logging框架中的上下文日志记录的故事。

也许我们将来也可以解释我们的日志代码治理方法; 在那之前,祝您伐木愉快!

翻译自: https://www.javacodegeeks.com/2017/09/logging-style-log4j-2-contextuality-auto-cleanup-no-strings-attached.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/350548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java date加一天_Java日期时间API系列15-----Jdk8中API类,java日期计算2,年月日时分秒的加减等...

通过Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析 ,可以看出java8设计非常好,实现接口Temporal, TemporalAdjuster, ChronoLocalDate等,有非常丰富的方法。例如:LocalDateTime&#xff1…

霍夫变换(Hough Transform)

一、直线检测相关算法   1.1 霍夫变换(Hough Transform)  霍夫变换(Hough Transform)换于1962年由Paul Hough 首次提出,后于1972年由Richard Duda和Peter Hart推广使用,是图像处理中从图像中检测几何形…

JDK 9是某些功能的终结

几天前宣布JDK 9是Feature Complete! 进行剪切的许多“功能”都是添加项,但有些是删除项。 这篇文章介绍了从OpenJDK和/或Oracle的JDK Java 9中删除的一些项目。 JEP 220 (“模块化运行时图像”)的一部分是删除了Java认可标准覆盖…

一种table超出高度自动出滚动条的解决方案

参考链接: http://www.cnblogs.com/xiaoafei1991/archive/2015/09/30/4781592.html转载于:https://www.cnblogs.com/ziyoublog/p/10870048.html

最近邻插值、双线性插值、双三次插值

1.最近邻插值 越是简单的模型越适合用来举例子,我们就举个简单的图像:3X3 的256级灰度图,也就是高为3个象素,宽也是3个象素的图像,每个象素的取值可以是 0-255,代表该像素的亮度,25…

java map转json字符串_Java-Gso-json字符串解析-php后台返回字段类型可能为字符串(/空字符串)或者对象的情况...

其实本来android前端定义的对象类型是对象,如果后台没有值的情况下,理论上给null,如果是数组给[]或者null都可以的。这样Gson再解析转换的时候就不会出问题!但是最近重构发现后台如果没有字段值给的是""空字符串&#x…

oracle中时间加减一年的写法

select add_months(date2019-5-15,-12) from dual; -- 2018-5-15 通过add_months(x,y)函数,在给定的时间x固定的月份y select date2019-5-15 interval -1 year from dual; --2018-5-15 通过interval函数,这个用来表示一段时间间隔,有固定的格式,这里用来加一年&a…

'fopen' This function or variable may be unsafe

1>...error C4996: fopen: This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 1> 正在生成代码... 生成: 成功 0 个,失败 1 个,最…

python3捕获异常_python中异常捕获方法详解

在Python中处理异常使用的是try-except代码块,try-except代码块放入让python执行的操作,同时告诉python程序如果发生了异常该怎么办,try-except这个功能其实很多入门书籍中都放到了高级篇幅里,在入门的时候一般不会讲这个使用&…

自定义java线程池_我的Java自定义线程池执行器

自定义java线程池ThreadPoolExecutor是Java并发api添加的一项功能,可以有效地维护和重用线程,因此我们的程序不必担心创建和销毁线程,也不必关注核心功能。 我创建了一个自定义线程池执行程序,以更好地了解线程池执行程序的工作方…

es6方法过滤掉两个数组中对象id值相等的项

let arr1[{id:1,name:张三},{id:2,name:李四}] let arr2[{id:1,name:张三},{id:3,name:王五},{id:44,name:王柳},{id:45,name:王琦},] let addarr2.filter(item>!arr1.some(ele>ele.iditem.id)) console.log(add) const arr1 [{ id: 1, name: 网 }, { id: 2, name: 二位…

大尾和小尾

字节存放有大尾和小尾之分。如果对应数据的高字节存放在低地址就是大尾,反之,高字节存放在高地址的就是小尾。 比如 short int a 0x1234 大尾存放时: 偏移地址 存放内容 0x0000 0x12 0x0001 0x34 小尾存放: 偏移…

jedis使用_Redis的三个框架:Jedis,Redisson,Lettuce

Jedis api 在线网址:http://tool.oschina.net/uploads/apidocs/redis/clients/jedis/Jedis.htmlredisson 官网地址:https://redisson.org/redisson git项目地址:https://github.com/redisson/redissonlettuce 官网地址:https://le…

端到端BPM(带有DMN标记)

下周的红帽峰会即将成为有史以来最好的峰会之一! 而且,如果您是Drools或jBPM的狂热者,您会很忙 :Signavio和Red Hat之间的合作伙伴关系是我们为您准备的另一个顶级演讲。 邓肯道尔(Duncan Doyle)和汤姆德贝…

pycharm写python字典_pythonpycharm安装基础语法

1.python安装安装python3,建议安装python3.7,不要安装python2安装时需要注意的地方:安装完成后,验证python是否安装成功,在cmd下输入python,出现python的版本则表明安装成功验证pip是否安装成功&#xff0c…

模板库 | 销售管理类报表,邀您提反馈

“葡萄城报表模板库是一款免费的报表制作、学习和参考工具,包含了超过 200 张高质量报表模板,涵盖了 16 大行业和 50 多种报表类型,为 30 余万报表开发者提供价值参考。” 近期,葡萄城推出了“寻找真正的报表大师”活动&#xff0…

矩阵的逆、伪逆

1、矩阵的逆 定义: 设A是数域上的一个n阶方阵,若在相同数域上存在另一个n阶矩阵B,使得: ABBAI。 则我们称B是A的逆矩阵,而A则被称为可逆矩阵。 可逆条件: A是可逆矩阵的充分必要条件是,即可…

PLSQL登录报错ORA-12154

https://blog.csdn.net/naomi_qing/article/details/79583453 转载于:https://www.cnblogs.com/2016-cxp/p/10878952.html

python将dataframe导出为csv_python将dataframe转换为csv,为每列导出一个格式独特的文本文件...

我正在Win7 64位上使用Python2.7.7和熊猫。我的输入数据最初是以空格分隔的,右对齐的。我现在有数据作为熊猫数据帧,我导出为一个csv。我想写一个空格分隔的右对齐文本文件。列有字符串、int和float。我试图用这个来格式化其中一个列:df_fg[M…

jax-rs/jersey_在Oracle Cloud上的Prime-UI,JAX-RS和Jersey和Gson

jax-rs/jersey如今,Oracle云无处不在。 最初,拉里(Larry)否认在很长一段时间内都需要云,并且在去年的开放世界(Open World)之后就发布了一些非常早的公告,而且可用性很差&#xff0c…