聊聊logback的ThrowableProxyConverter
序
本文主要研究一下logback的ThrowableProxyConverter
ThrowableHandlingConverter
ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java
/*** Converter which handle throwables should be derived from this class.**/
public abstract class ThrowableHandlingConverter extends ClassicConverter {boolean handlesThrowable() {return true;}
}
ThrowableHandlingConverter继承了ClassicConverter,其handlesThrowable方法返回true
ThrowableProxyConverter
ch/qos/logback/classic/pattern/ThrowableProxyConverter.java
public class ThrowableProxyConverter extends ThrowableHandlingConverter {protected static final int BUILDER_CAPACITY = 2048;int lengthOption;List<EventEvaluator<ILoggingEvent>> evaluatorList = null;List<String> ignoredStackTraceLines = null;int errorCount = 0;@SuppressWarnings("unchecked")public void start() {String lengthStr = getFirstOption();if (lengthStr == null) {lengthOption = Integer.MAX_VALUE;} else {lengthStr = lengthStr.toLowerCase();if ("full".equals(lengthStr)) {lengthOption = Integer.MAX_VALUE;} else if ("short".equals(lengthStr)) {lengthOption = 1;} else {try {lengthOption = Integer.parseInt(lengthStr);} catch (NumberFormatException nfe) {addError("Could not parse [" + lengthStr + "] as an integer");lengthOption = Integer.MAX_VALUE;}}}final List<String> optionList = getOptionList();if (optionList != null && optionList.size() > 1) {final int optionListSize = optionList.size();for (int i = 1; i < optionListSize; i++) {String evaluatorOrIgnoredStackTraceLine = (String) optionList.get(i);Context context = getContext();Map<String, EventEvaluator<?>> evaluatorMap = (Map<String, EventEvaluator<?>>) context.getObject(CoreConstants.EVALUATOR_MAP);EventEvaluator<ILoggingEvent> ee = (EventEvaluator<ILoggingEvent>) evaluatorMap.get(evaluatorOrIgnoredStackTraceLine);if (ee != null) {addEvaluator(ee);} else {addIgnoreStackTraceLine(evaluatorOrIgnoredStackTraceLine);}}}super.start();}//......
}
ThrowableProxyConverter继承了ThrowableHandlingConverter,其start方法会先读取getFirstOption,该参数为lengthOption,为null则取Integer.MAX_VALUE,若为full则取Integer.MAX_VALUE,为short取1,其他的则解析该值,出现异常则取Integer.MAX_VALUE;之后取optionList的其他值,先通过evaluatorMap来取,若EventEvaluator不为null则执行addEvaluator,否则执行addIgnoreStackTraceLine
addEvaluator
private void addEvaluator(EventEvaluator<ILoggingEvent> ee) {if (evaluatorList == null) {evaluatorList = new ArrayList<EventEvaluator<ILoggingEvent>>();}evaluatorList.add(ee);}
addEvaluator则是添加到evaluatorList
addIgnoreStackTraceLine
private void addIgnoreStackTraceLine(String ignoredStackTraceLine) {if (ignoredStackTraceLines == null) {ignoredStackTraceLines = new ArrayList<String>();}ignoredStackTraceLines.add(ignoredStackTraceLine);}
addIgnoreStackTraceLine则是添加到ignoredStackTraceLines
convert
public String convert(ILoggingEvent event) {IThrowableProxy tp = event.getThrowableProxy();if (tp == null) {return CoreConstants.EMPTY_STRING;}// an evaluator match will cause stack printing to be skippedif (evaluatorList != null) {boolean printStack = true;for (int i = 0; i < evaluatorList.size(); i++) {EventEvaluator<ILoggingEvent> ee = evaluatorList.get(i);try {if (ee.evaluate(event)) {printStack = false;break;}} catch (EvaluationException eex) {errorCount++;if (errorCount < CoreConstants.MAX_ERROR_COUNT) {addError("Exception thrown for evaluator named [" + ee.getName() + "]", eex);} else if (errorCount == CoreConstants.MAX_ERROR_COUNT) {ErrorStatus errorStatus = new ErrorStatus("Exception thrown for evaluator named [" + ee.getName() + "].", this, eex);errorStatus.add(new ErrorStatus("This was the last warning about this evaluator's errors."+ "We don't want the StatusManager to get flooded.", this));addStatus(errorStatus);}}}if (!printStack) {return CoreConstants.EMPTY_STRING;}}return throwableProxyToString(tp);}
convert方法先从event获取IThrowableProxy,若为null则返回空字符串;之后判断evaluatorList是否为null,不为null则遍历挨个执行evaluate(event),若为true则printStack设置为false,跳出循环,当printStack为false时,返回空字符串,否则通过throwableProxyToString转为字符串返回
throwableProxyToString
protected String throwableProxyToString(IThrowableProxy tp) {StringBuilder sb = new StringBuilder(BUILDER_CAPACITY);recursiveAppend(sb, null, ThrowableProxyUtil.REGULAR_EXCEPTION_INDENT, tp);return sb.toString();}private void recursiveAppend(StringBuilder sb, String prefix, int indent, IThrowableProxy tp) {if (tp == null)return;subjoinFirstLine(sb, prefix, indent, tp);sb.append(CoreConstants.LINE_SEPARATOR);subjoinSTEPArray(sb, indent, tp);IThrowableProxy[] suppressed = tp.getSuppressed();if (suppressed != null) {for (IThrowableProxy current : suppressed) {recursiveAppend(sb, CoreConstants.SUPPRESSED, indent + ThrowableProxyUtil.SUPPRESSED_EXCEPTION_INDENT, current);}}recursiveAppend(sb, CoreConstants.CAUSED_BY, indent, tp.getCause());}
throwableProxyToString主要是递归执行recursiveAppend,它先执行subjoinFirstLine、再执行subjoinSTEPArray、最后继续递归
subjoinSTEPArray
protected void subjoinSTEPArray(StringBuilder buf, int indent, IThrowableProxy tp) {StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();int commonFrames = tp.getCommonFrames();boolean unrestrictedPrinting = lengthOption > stepArray.length;int maxIndex = (unrestrictedPrinting) ? stepArray.length : lengthOption;if (commonFrames > 0 && unrestrictedPrinting) {maxIndex -= commonFrames;}int ignoredCount = 0;for (int i = 0; i < maxIndex; i++) {StackTraceElementProxy element = stepArray[i];if (!isIgnoredStackTraceLine(element.toString())) {ThrowableProxyUtil.indent(buf, indent);printStackLine(buf, ignoredCount, element);ignoredCount = 0;buf.append(CoreConstants.LINE_SEPARATOR);} else {++ignoredCount;if (maxIndex < stepArray.length) {++maxIndex;}}}if (ignoredCount > 0) {printIgnoredCount(buf, ignoredCount);buf.append(CoreConstants.LINE_SEPARATOR);}if (commonFrames > 0 && unrestrictedPrinting) {ThrowableProxyUtil.indent(buf, indent);buf.append("... ").append(tp.getCommonFrames()).append(" common frames omitted").append(CoreConstants.LINE_SEPARATOR);}}
subjoinSTEPArray遍历StackTraceElementProxy数组,然后挨个判断isIgnoredStackTraceLine,若为false才执行printStackLine
isIgnoredStackTraceLine
private boolean isIgnoredStackTraceLine(String line) {if (ignoredStackTraceLines != null) {for (String ignoredStackTraceLine : ignoredStackTraceLines) {if (line.contains(ignoredStackTraceLine)) {return true;}}}return false;}
isIgnoredStackTraceLine主要是判断指定line是否包含了ignoredStackTraceLines,包含其中一个即返回true
小结
logback的ThrowableProxyConverter继承了ThrowableHandlingConverter,它定义了evaluatorList、ignoredStackTraceLines属性,它将继承自DynamicConverter的optionList做了划分,第一个option为打印异常堆栈的数,之后的option优先作为evaluatorList,若解析为evaluator为null则作为ignoredStackTraceLines参数。evaluatorList用于evaluate(event),若有个返回true则返回空字符串,而ignoredStackTraceLines则用于过滤包含这些的异常堆栈。
相关文章:
聊聊logback的ThrowableProxyConverter
序 本文主要研究一下logback的ThrowableProxyConverter ThrowableHandlingConverter ch/qos/logback/classic/pattern/ThrowableHandlingConverter.java /*** Converter which handle throwables should be derived from this class.**/ public abstract class ThrowableHa…...

Kubernetes(k8s)访问不了Pod服务
在k8s集群部署java web应用的服务时,浏览器访问不了pod服务或linux终端curl http://192.168.138.112:30000即curl http://ip地址:端口号失败,如下图: 在网上找了很久的答案,最后还是没解决,后来突然想起来一直是在k8…...

python-学生管理|汉罗塔
1.编写程序,实现学生信息管理系统。 运行程序,在控制台输入“1”之后的结果如下所示: 学生管理系统 1.添加学生信息 2.删除学生信息 3.修改学生信息 4.显示所有学生信息 0.退出系统 请选择功能:1 请输入新学生的姓名:小红 请输入…...

python 堆与栈
【一】堆与栈 【 1 】简介 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素、访问元素、删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标,英语:top&a…...

园区规划技术要点
(一)技术点介绍 1.WLAN:无线局域网WLAN(Wireless Local Area Network)是一种无线计算机网络,使用无线信道代替有线传输介质连接两个或多个设备形成一个局域网LAN(Local Area Network)…...

深入浅出 Linux 中的 ARM IOMMU SMMU III
系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的 dma_alloc_coherent()/dma_alloc_attrs() 等接口。dma_alloc_coherent()/dma_alloc_attrs() 等接口通过 DMA IOMMU 的回调分配内存,并为经过 IOMMU 的 DMA 内…...

Linux系统---图书管理中的同步问题
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、问题描述 (1)图书馆阅览室最多能够容纳N(N5)名学生,若有更多学生想…...
Vue学习笔记-activated和deactivated生命周期
作用 路由组件所独有的2个生命周期 activated生命周期函数用于在路由组件每次由消失到出现时所调用的函数deactivated生命周期函数用于路由组件每次由出现到消失时(无论是否缓存)所调用的函数 案例 定义一个NewsVue组件,要求:…...

102.套接字-Socket网络编程4(TCP通信流程)
目录 TCP编程流程 套接字函数 1.创建套接字 2.绑定地址 3.监听连接请求 4.接受连接 5. 连接到服务器 6. 发送数据 7. 接收数据 8.关闭套接字 服务器端通信流程 示例代码 客户端通信流程 代码示例 TCP编程流程 TCP是一个面向连接的,安全的,流…...

spring boot 2 升级到 spring boot 3 后文件上传失败
背景 项目需要,要求升级 spring boot 2.7 到 spring boot 3.2,升级过程中发现很多不兼容问题,下面说明文件上传失败的解决方案。 问题 spring boot 2 中不需要额外的配置,直接在 Controller 中配置 MultipartFile 接收页面传的…...
Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异,并取出不同的对象
Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异,并取出不同的对象。这可以通过使用 distinct() 和 filter() 方法来实现。 假设我们有两个 List,一个是 list1,另一个是 list2,我们想找出 list1 中存在但 list2…...
C语言还会存在多久
一、C语言的生命力 在当前的科技发展和就业市场需求下,可以肯定地说C语言并没有像一些新兴语言(如Python、JavaScript等)那样受到大量的关注。然而,并不意味着学习C语言的人会越来越少。 首先,C语言作为一种深受尊重…...

手持式安卓主板_PDA安卓板_智能手持终端方案
手持式安卓主板方案是一种智能终端设备,具备自动对焦和闪光灯功能,可以在昏暗的环境下快速扫描二维码并轻松采集数据。该方案还提供多渠道支付和数据采集功能,为用户提供了便捷的体验。 该方案的产品基于手持式安卓主板,并搭载了八…...
LeetCode103. Binary Tree Zigzag Level Order Traversal
文章目录 一、题目二、题解 一、题目 Given the root of a binary tree, return the zigzag level order traversal of its nodes’ values. (i.e., from left to right, then right to left for the next level and alternate between). Example 1: Input: root [3,9,20,n…...
PHP 判断给定两个时间是否在同一周,月,年
判断是否在同一周 date_default_timezone_set(PRC); //判断是否在同一周,原理:求出其中一个时间戳所在周的周一凌晨时间戳和周日24.00时间戳,如果另一个时间戳在这个范围内,则说明在同一周,否则不在同一周 function g…...

单机无锁线程安全队列-Disruptor
Disruptor 1、基本介绍 说到队列,除了常见的mq中间件,java中也自带线程安全的BlockingQueue,但是BlockingQueue通过在入队和出队时加锁的方式避免并发操作,性能上会大打折扣。 而Disruptor是一个线程安全、低延迟、吞吐量高的队…...
好工具知多少:国内外最常用的SCADA软件
随着现代SCADA系统的发展,工业自动化取得了巨大的飞跃。如今,监控和数据采集(SCADA)系统已成为工业过程的重要组成部分。这些系统使操作员能够实时监控和控制复杂的系统。 SCADA系统正在广泛的行业中发挥着至关重要的作用&#x…...

SQL Server 2016(创建数据库)
1、实验环境。 某公司有一台已经安装了SQL Server 2016的服务器,现在需要新建数据库。 2、需求描述。 创建一个名为"db_class"的数据库,数据文件和日志文件初始大小设置为10MB,启用自动增长,数据库文件存放路径为C:\db…...
Vue学习计划--Vue2(一)简单了解vue
Vue2的终止支持时间为2023年12月31日。 在这个矛盾的时间点,还是决定先把vue2的笔记放出来,在Vue2完结后再把Vue3的笔记补上。这样呢,2和3都不落下,也算是来一个启承的作用吧。在工作中呢,旧的项目可以维护,…...

微信小程序生成二维码并保存到本地方法
微信小程序生成二维码请保存到本地方法 官方weapp-qrcode插件 github链接 功能完成样子 wxml <view class"qrcode"><canvas style"width: 275px; height: 275px;" canvas-idmyQrcode></canvas> </view> <view class" …...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...