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

如何在logback.xml中自定义动态属性

原文地址:http://blog.jboost.cn/trick-logback-prop.html

当使用logback来记录Web应用的日志时,我们通过在logback.xml中配置appender来指定日志输出格式及输出文件路径,这在一台主机或一个文件系统上部署单个实例没有问题,但是如果部署多个实例(比如通过容器的方式),多个实例同时往同一文件写日志可能就会引起问题。这时可以将每个实例的日志文件加以区分,如IP或UUID,或两者结合的形式。这其实就涉及如何在logback.xml中自定义动态属性的问题。

可以有4种方式来实现logback.xml中获取自定义变量值:

  1. 通过设置环境变量或传递系统属性(比如在程序启动时通过-D传递)的方式,两者是可以直接在logback.xml中通过 ${变量名} 获取的。
  2. 自定义logback.xml的加载时机,在其加载前将需要设置的属性注入到logback的context中,这种方式相对复杂,本文不讨论。
  3. 通过实现PropertyDefiner接口来提供属性值设置
  4. 通过实现LoggerContextListener接口来设置属性值

第一种方式简单,但不能通过程序生成属性值

需要在spring-boot启动类中加入设置环境变量的代码,如下:
在这里插入图片描述
修改logback.xml中的代码如下:

在这里插入图片描述

第二种方式稍显复杂,本文主要介绍后两种方式

PropertyDefiner方式

首先定义一个类,实现PropertyDefiner接口,可以通过继承PropertyDefinerBase会更方便

import ch.qos.logback.core.PropertyDefinerBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.UUID; /\*\*\*\* 将本地IP拼接到日志文件名中,以区分不同实例,避免存储到同一位置时的覆盖冲突问题\* @Author ronwxy\* @Date 2019/8/20 16:17 \*/
public class IPLogDefiner extends PropertyDefinerBase { private static final Logger LOG = LoggerFactory.getLogger(IPLogDefiner.class); private String getUniqName() {String localIp \= null; try {localIp \= InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) {LOG.error("fail to get ip...", e);}String uniqName \= UUID.randomUUID().toString().replace("-", ""); if (localIp != null) {uniqName \= localIp + "-" + uniqName;} return uniqName;}@Override public String getPropertyValue() { return getUniqName();}
}

然后在logback.xml中,添加 <define> 配置,指定属性名(本例中为localIP)及获取属性值的实现类,这样就可以在配置中通过 ${localIP}来引用该属性值了。在实现方法 getPropertyValue 中返回你需要生成的值,本例中是返回 本地IP-UUID 的形式。

<configuration><define name="localIP" class="cn.jboost.common.IPLogDefiner"/><appender name="interfaceLogFile"class\="ch.qos.logback.core.rolling.RollingFileAppender"><encoding>UTF-8</encoding><File>D:\\\\logs\\\\elk\\\\interface\-${localIP}.log</File><filter class\="ch.qos.logback.classic.filter.ThresholdFilter"><level>INFO</level></filter> # 省略了其它配置

LoggerContextListener方式

定义一个实现LoggerContextListener接口的类,在start方法中,将需要设置的属性设置到logback的Context中,

import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.LoggerContextListener; import ch.qos.logback.core.Context; import ch.qos.logback.core.spi.ContextAwareBase; import ch.qos.logback.core.spi.LifeCycle; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.UUID; /\*\*\*\* 第二种实现方式\* @Author ronwxy\* @Date 2019/8/20 18:45 \*/
public class LoggerStartupListener extends ContextAwareBase implements LoggerContextListener, LifeCycle { private boolean started = false;@Override public void start() { if (started) { return;}Context context \= getContext();context.putProperty("localIP", getUniqName());started \= true;} private String getUniqName() {String localIp \= null; try {localIp \= InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) { //LOG.error("fail to get ip...", e);}String uniqName \= UUID.randomUUID().toString().replace("-", ""); if (localIp != null) {uniqName \= localIp + "-" + uniqName;} return uniqName;} //省略了其它函数

然后在logback.xml中,配置如上监听器类,这样就可以通过 ${localIP} 获取到上面 context.putProperty("localIP", getUniqName()); 设置的值了。

<configuration><!--<define name="localIP" class\="com.cnbot.common.IPLogDefiner"/>--><contextListener class="cn.jboost.common.LoggerStartupListener"/><define name="localIP" class\="com.cnbot.common.IPLogDefiner"/><appender name="interfaceLogFile"class\="ch.qos.logback.core.rolling.RollingFileAppender"><encoding>UTF-8</encoding><File>D:\\\\logs\\\\elk\\\\interface\-${localIP}.log</File><filter class\="ch.qos.logback.classic.filter.ThresholdFilter"><level>INFO</level></filter> # 省略了其它配置

这种方式能设置任意个数的属性值,比前一种方式灵活。

总结

在logback.xml中获取自定义属性值,主要是需要在加载前将对应的属性值进行设置,这样加载时才能有效获取。本文虽是自定义日志文件名称,但不局限于此,所有需要动态获取的变量都可以按这种方式实现。

相关文章:

如何在logback.xml中自定义动态属性

原文地址&#xff1a;http://blog.jboost.cn/trick-logback-prop.html 当使用logback来记录Web应用的日志时&#xff0c;我们通过在logback.xml中配置appender来指定日志输出格式及输出文件路径&#xff0c;这在一台主机或一个文件系统上部署单个实例没有问题&#xff0c;但是…...

嵌入式系统硬件设计与实践(第一步下载eda软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 现实生活中&#xff0c;我们经常发现有的人定了很多的目标&#xff0c;但是到最后一个都没有实现。这听上去有点奇怪&#xff0c;但确实是实实在在…...

Portraiture4免费磨皮插件支持PS/LR

Portraiture 4免去了繁琐的手工劳动&#xff0c;选择性的屏蔽和由像素的平滑&#xff0c;以帮助您实现卓越的肖像润色。智能平滑&#xff0c;并删除不完善之处&#xff0c;同时保持皮肤的纹理和其他重要肖像的细节&#xff0c;如头发&#xff0c;眉毛&#xff0c;睫毛等。 一键…...

Python学习笔记202302

1、numpy.empty 作用&#xff1a;根据给定的维度和数值类型返回一个新的数组&#xff0c;其元素不进行初始化。 用法&#xff1a;numpy.empty(shape, dtypefloat, order‘C’) 2、logging.debug 作用&#xff1a;Python 的日志记录工具&#xff0c;这个模块为应用与库实现了灵…...

2023年大数据面试开胃菜

1、kafka的message包括哪些信息一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成&#xff0c;header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成。当magic的值为1的时候&#xff0c;会在magic和crc32之间多一个字节…...

优雅的controller层设计

controller层设计 Controller 层逻辑 ​ MVC架构下&#xff0c;我们的web工程结构会分为三层&#xff0c;自下而上是dao层&#xff0c;service层和controller层。controller层为控制层&#xff0c;主要处理外部请求。调用service层&#xff0c;一般情况下&#xff0c;contro…...

同步、通信、死锁

基础概念竞争资源引起两个问题死锁&#xff1a;因资源竞争陷入永远等待的状态饥饿&#xff1a;一个可运行程序由于其他进程总是优先于它&#xff0c;而被调用程序总是无限期地拖延而不能执行进程互斥&#xff1a;若干进程因相互争夺独占型资源而产生的竞争关系进程同步&#xf…...

【聚类】谱聚类解读、代码示例

【聚类】谱聚类详解、代码示例 文章目录【聚类】谱聚类详解、代码示例1. 介绍2. 方法解读2.1 先验知识2.1.1 无向权重图2.1.2 拉普拉斯矩阵2.2 构建图&#xff08;第一步&#xff09;2.2.1 ϵ\epsilonϵ 邻近法2.2.2 k 近邻法2.2.3 全连接法2.3 切图&#xff08;第二步&#xf…...

最牛逼的垃圾回收期ZGC(1),简介

1丶什么是ZGC? ZGC是JDK 11中引入的一种可扩展的、低延迟的垃圾收集器。ZGC最主要的特点是&#xff1a;在非常短的时间内&#xff08;一般不到10ms&#xff09;&#xff0c;就可以完成一次垃圾回收&#xff0c;而且这个时间是与堆的大小无关的。另外&#xff0c;ZGC支持非常大…...

微服务的Feign到底是什么

Feign是什么 分区是一种数据库优化技术&#xff0c;它可以将大表按照一定的规则分成多个小表&#xff0c;从而提高查询和维护的效率。在分区的过程中&#xff0c;数据库会将数据按照分区规则分配到不同的分区中&#xff0c;并且可以在分区中使用索引和其他优化技术来提高查询效…...

JavaScript 正则表达式

正则表达式&#xff08;英语&#xff1a;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09;使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。搜索模式可用于文本搜索和文本替换。什么是正则表达式&#xff1f;正则表达式是由一…...

【批处理脚本】-1.15-文件内字符串查找命令find

"><--点击返回「批处理BAT从入门到精通」总目录--> 共7页精讲(列举了所有find的用法,图文并茂,通俗易懂) 在从事“嵌入式软件开发”和“Autosar工具开发软件”过程中,经常会在其集成开发环境IDE(CodeWarrior,S32K DS,Davinci,EB Tresos,ETAS…)中,…...

【手撕面试题】JavaScript(高频知识点二)

目录 面试官&#xff1a;请你谈谈JS的this指向问题 面试官&#xff1a;说一说call apply bind的作用和区别&#xff1f; 面试官&#xff1a;请你谈谈对事件委托的理解 面试官&#xff1a;说一说promise是什么与使用方法&#xff1f; 面试官&#xff1a;说一说跨域是什么&a…...

Web学习1_HTML

在学校期间学的Web知识忘了一些&#xff0c;很多东西摸棱两可&#xff0c;现重新系统的学习一下。 首先下载安装完vsc后并下载拓展文件live server&#xff08;模拟一个服务器&#xff09; Auto Rename Tag&#xff08;在写网页时&#xff0c;自动对齐前后标签&#xff09;在设…...

华为OD机试真题Java实现【靠谱的车】真题+解题思路+代码(20222023)

靠谱的车 题目 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。 比如: 23再多一块钱就变为25; 39再多一块钱变…...

【C++入门(下篇)】C++引用,内联函数,auto关键字的学习

前言&#xff1a; 在上一期我们进行了C的初步认识&#xff0c;了解了一下基本的概念还学习了包括&#xff1a;命名空间&#xff0c;输入输出以及缺省参数等相关的知识。今天我们将进一步对C入门知识进行学习&#xff0c;主要还需要大家掌握我们接下来要学习的——引用&#xf…...

基于合作型Stackerlberg博弈的考虑差别定价和风险管理的微网运行策略研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

2023年全国最新保安员精选真题及答案8

百分百题库提供保安员考试试题、保安职业资格考试预测题、保安员考试真题、保安职业资格证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 81.以下各组情形都属于区域巡逻中异常情况的是&#xff08;&#xff09;。 A&#x…...

JavaScript高级程序设计读书分享之6章——MapSet

JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 Map 作为 ECMAScript 6 的新增特性&#xff0c;Map 是一种新的集合类型&#xff0c;为这门语言带来了真正的键/值存储机制。Map 的大多数特性都可以通过 Object 类型实现&#xff0c;但二者之间还是存在…...

改进的 A*算法的路径规划(路径规划+代码+毕业设计)

引言 近年来&#xff0c;随着智能时代的到来&#xff0c;路径规划技术飞快发展&#xff0c;已经形成了一套较为成熟的理论体系。其经典规划算法包括 Dijkstra 算法、A算法、D算法、Field D算法等&#xff0c;然而传统的路径规划算法在复杂的场景的表现并不如人意&#xff0c;例…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

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 &…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...