登录样式: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/349345.shtml

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

相关文章

python37安装失败_Linux 安装Python37

1、下载python3.7.0https://www.python.org/downloads/release/python-370/2、创建Linux的python37目录mkdir /usr/local/python373、解压python3.7.0源码tar zxvf python3.7.0.tar.zg4、配置编译参数./configure --prefix/usr/local/python375、make6、make install注意&#…

python string模块template_Python标准库笔记(1) — string模块

String模块包含大量实用常量和类,以及一些过时的遗留功能,并还可用作字符串操作。1. 常用方法常用方法描述str.capitalize()把字符串的首字母大写str.center(width)将原字符串用空格填充成一个长度为width的字符串,原字符串内容居中str.count…

注意力机制可视化_目标跟踪中的(STAM)时空注意力机制

目标跟踪分为单目标跟踪和多目标跟踪,单目标跟踪较为简单,这里我们只讨论多目标跟踪。多目标跟踪的遮挡问题多目标跟踪时特别容易发生目标间的相互遮挡,从而导致严重的预测偏移问题,如下图所示:红色框的行人在和蓝色框…

byteman_使用Byteman和JUnit进行故障注入

byteman我们的应用程序独立存在的时间已经很久了。 如今,应用程序是一种非常复杂的野兽,它们使用无数的API和协议相互通信,将数据存储在传统或NoSQL数据库中,通过网络发送消息和事件……例如,您多久考虑一次例如数据库…

java动态扩展_java栈内存动态扩展要怎么理解?要如何实现?

小伙伴们知道如何在java栈中内存动态扩展吗?这是虚拟机中的一个概念,下面让我们一起来看看该如何实现吧。一、内存概念在java中,我们一般会简单把java内存区域划为两种:堆内存与栈内存。其实这种划分是比较粗粒度的。其中栈内存就是指的是虚…

python 爬虫热搜_Python网络爬虫之爬取微博热搜

微博热搜的爬取较为简单,我只是用了lxml和requests两个库1.分析网页的源代码:右键--查看网页源代码.从网页代码中可以获取到信息(1)热搜的名字都在的子节点里(2)热搜的排名都在的里(注意置顶微博是没有排名的!)(3)热搜的访问量都在的子节点里…

优盘复制进来为空_为何电脑上的文件夹一复制到U盘里就变成空文件夹了?

(格式化后的卡在恢复前千万不要往里面存东西,因为这样会覆盖你想恢复的内容,如果你不小心存东西了也不要放弃,只不过恢复的机率会变小),下面开始:::在百度里输入Easy recover 软件找到后下载安装到电脑上,然后将内存卡与电脑连接,打开Easy recover 软件,首次打开时软件会分析系…

Spring Cloud教程–使用Spring Cloud Bus自动刷新配置更改

问题 在上一篇文章Spring Cloud Config Server简介 ( http://sivalabs.in/2017/08/spring-cloud-tutorials-introduction-to-spring-cloud-config-server/ )中,我们已经了解了如何使用Spring Cloud配置服务器。 但是,问题是要重新…

js给标签添加属性和值_jquery节点属性

一.节点操作1.DOM内容节点操作:​ ①innerHTML属性:设置或获取文本的内容(普通文本和标签)。​ ②innerText属性:设置或获取文本的内容(普通文本),存在兼容性问题。2.jQuery内容节点…

sci translate好用吗_228个学科分类对应12000+本SCI和SSCI期刊,总有你要的那款!

最近有很多小伙伴询问选刊的问题,而且都是非常具体的学科方向,我们的小编虽然非常热心且礼貌的回答“近期安排”,但其实我们也感觉到鸭梨山大:根据WOS最新一期(2020/9/21)名单公布,WOS目前总共收录了12266本…

java 反射 属性顺序_java反射得到的方法数组的顺序

展开全部看了下你好像需要set和get方法,如果你知道属性的名字的话不需要遍历可以这样获取,这个是我以前的demo的一个32313133353236313431303231363533e58685e5aeb931333332633561片段:Class clazzClass.forName("com.demo.reflectdemo.Student&quo…

arrays.sort(._Arrays.sort与Arrays.parallelSort

arrays.sort(.我们都使用Arrays.sort对对象和原始数组进行排序。 此API在下面使用合并排序或Tim排序对内容进行排序,如下所示: public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sor…

python冒泡排序函数_python冒泡排序-Python,冒泡排序

arr[7,4,3,67,34,1,8].defbubble_sort:最近在学习Python,下面是我的一些笔记冒泡排序实现思路: 使用双重for循环,内层变量为i, 外层为j,在内层循环中不断的比较相邻的两个值(i, i1)的大小,如果i1的值大于i的…

适用于Idea的面向现代TDD的Java 8 JUnit测试模板(带有Mockito和AssertJ)

使用类似BDD的语法,Java 8和Mockito-AssertJ二重奏为Idea调整JUnit测试类模板。 本文涵盖的主题似乎很简单。 但是,根据我的培训师经验,我知道(不幸的是)这不是常见的做法。 因此,我决定写这篇简短的博客文…

python编程的基本方法有哪些_Python编程中常用的基础知识有哪些?

今天小编要跟大家分享的文章是关于Python编程中常用的基础知识有哪些?正在从事Python相关工作的小伙伴们,来和小编一起看一看本篇文章,希望本篇文章能够对大家有所帮助。1、正则表达式替换目标: 将字符串 line 中的 overview.gif 替换成其他字符串>&…

java取网页源码_Java获取任意http网页源代码的方法

本文实例讲述了JAVA获取任意http网页源代码。分享给大家供大家参考,具体如下:JAVA获取任意http网页源代码可实现如下功能:1. 获取任意http网页的代码2. 获取任意http网页去掉HTML标签的代码Webpage类:/*** 网页操作相关类*/packag…

python数据结构算法优势_Python数据结构与算法(一)----- 算法效率

一.引入先来看一道题:如果abc1000, 且a2b2c^2(a,b,c为自然数),如何求出所有a,b,c可能的组合?(1) 枚举法import timestart_time time.time()for a in range(0,1001):for b in range(0,1001):for c in range(1,1001):if abc1000 and a**2b**2 …

Java编程字符逆序输出_用JAVA编写一程序:从键盘输入多个字符串到程序中,并将它们按逆序输出在屏幕上。...

展开全部代码如下:import java.util.Scanner;public class ScannerDemo{public static void main(String[] args) throws Exception{Scanner scannew Scanner(System.in);System.out.println("请输入内容:");String strscan.nextLine();char[]…

glassfish 4配置_自己构建GlassFish 4.0快照

glassfish 4配置这篇文章是关于自己发布GlassFish 4.0快照的,其中包括一些黑客。 我找到了GlassFish FullBuild的官方说明,然后决定自己构建服务器。 有时,您可能不想等待团队升级GlassFish构建文件。 在本条目中,我将Artifactory…

julia与python对比_有人说Julia比Python好,还给出了5个理由

选自medium作者:Emmett Boudreau机器之心编译参与:杜伟、张倩、肖清本文作者从速度、通用性、多重派发、适用于 ML 的程度和包管理器 5 个方面阐述了 Julia 语言相较于 Python 的优势所在。Julia 是一种多范式的函数式编程语言,用于机器学习和…