当前位置: 首页 > news >正文

聊聊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应用的服务时&#xff0c;浏览器访问不了pod服务或linux终端curl http://192.168.138.112:30000即curl http://ip地址:端口号失败&#xff0c;如下图&#xff1a; 在网上找了很久的答案&#xff0c;最后还是没解决&#xff0c;后来突然想起来一直是在k8…...

python-学生管理|汉罗塔

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

python 堆与栈

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

园区规划技术要点

&#xff08;一&#xff09;技术点介绍 1.WLAN&#xff1a;无线局域网WLAN&#xff08;Wireless Local Area Network&#xff09;是一种无线计算机网络&#xff0c;使用无线信道代替有线传输介质连接两个或多个设备形成一个局域网LAN&#xff08;Local Area Network&#xff09…...

深入浅出 Linux 中的 ARM IOMMU SMMU III

系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的 dma_alloc_coherent()/dma_alloc_attrs() 等接口。dma_alloc_coherent()/dma_alloc_attrs() 等接口通过 DMA IOMMU 的回调分配内存&#xff0c;并为经过 IOMMU 的 DMA 内…...

Linux系统---图书管理中的同步问题

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、问题描述 &#xff08;1&#xff09;图书馆阅览室最多能够容纳N&#xff08;N5&#xff09;名学生&#xff0c;若有更多学生想…...

Vue学习笔记-activated和deactivated生命周期

作用 路由组件所独有的2个生命周期 activated生命周期函数用于在路由组件每次由消失到出现时所调用的函数deactivated生命周期函数用于路由组件每次由出现到消失时&#xff08;无论是否缓存&#xff09;所调用的函数 案例 定义一个NewsVue组件&#xff0c;要求&#xff1a;…...

102.套接字-Socket网络编程4(TCP通信流程)

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

spring boot 2 升级到 spring boot 3 后文件上传失败

背景 项目需要&#xff0c;要求升级 spring boot 2.7 到 spring boot 3.2&#xff0c;升级过程中发现很多不兼容问题&#xff0c;下面说明文件上传失败的解决方案。 问题 spring boot 2 中不需要额外的配置&#xff0c;直接在 Controller 中配置 MultipartFile 接收页面传的…...

Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异,并取出不同的对象

Java Stream API 提供了一种非常方便的方式来比较两个 List 的差异&#xff0c;并取出不同的对象。这可以通过使用 distinct() 和 filter() 方法来实现。 假设我们有两个 List&#xff0c;一个是 list1&#xff0c;另一个是 list2&#xff0c;我们想找出 list1 中存在但 list2…...

C语言还会存在多久

一、C语言的生命力 在当前的科技发展和就业市场需求下&#xff0c;可以肯定地说C语言并没有像一些新兴语言&#xff08;如Python、JavaScript等&#xff09;那样受到大量的关注。然而&#xff0c;并不意味着学习C语言的人会越来越少。 首先&#xff0c;C语言作为一种深受尊重…...

手持式安卓主板_PDA安卓板_智能手持终端方案

手持式安卓主板方案是一种智能终端设备&#xff0c;具备自动对焦和闪光灯功能&#xff0c;可以在昏暗的环境下快速扫描二维码并轻松采集数据。该方案还提供多渠道支付和数据采集功能&#xff0c;为用户提供了便捷的体验。 该方案的产品基于手持式安卓主板&#xff0c;并搭载了八…...

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); //判断是否在同一周&#xff0c;原理&#xff1a;求出其中一个时间戳所在周的周一凌晨时间戳和周日24.00时间戳&#xff0c;如果另一个时间戳在这个范围内&#xff0c;则说明在同一周&#xff0c;否则不在同一周 function g…...

单机无锁线程安全队列-Disruptor

Disruptor 1、基本介绍 说到队列&#xff0c;除了常见的mq中间件&#xff0c;java中也自带线程安全的BlockingQueue&#xff0c;但是BlockingQueue通过在入队和出队时加锁的方式避免并发操作&#xff0c;性能上会大打折扣。 而Disruptor是一个线程安全、低延迟、吞吐量高的队…...

好工具知多少:国内外最常用的SCADA软件

随着现代SCADA系统的发展&#xff0c;工业自动化取得了巨大的飞跃。如今&#xff0c;监控和数据采集&#xff08;SCADA&#xff09;系统已成为工业过程的重要组成部分。这些系统使操作员能够实时监控和控制复杂的系统。 SCADA系统正在广泛的行业中发挥着至关重要的作用&#x…...

SQL Server 2016(创建数据库)

1、实验环境。 某公司有一台已经安装了SQL Server 2016的服务器&#xff0c;现在需要新建数据库。 2、需求描述。 创建一个名为"db_class"的数据库&#xff0c;数据文件和日志文件初始大小设置为10MB&#xff0c;启用自动增长&#xff0c;数据库文件存放路径为C:\db…...

Vue学习计划--Vue2(一)简单了解vue

Vue2的终止支持时间为2023年12月31日。 在这个矛盾的时间点&#xff0c;还是决定先把vue2的笔记放出来&#xff0c;在Vue2完结后再把Vue3的笔记补上。这样呢&#xff0c;2和3都不落下&#xff0c;也算是来一个启承的作用吧。在工作中呢&#xff0c;旧的项目可以维护&#xff0c…...

微信小程序生成二维码并保存到本地方法

微信小程序生成二维码请保存到本地方法 官方weapp-qrcode插件 github链接 功能完成样子 wxml <view class"qrcode"><canvas style"width: 275px; height: 275px;" canvas-idmyQrcode></canvas> </view> <view class" …...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...