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

log4j日志配置%X{TransId}

log4j日志配置文件中的%X{TransId}是怎么动态获取值的

在Log4j中,%X{TransId} 是用来从MDC(Mapped Diagnostic Context)中获取值的占位符。MDC 是 Log4j 提供的一种机制,用于在同一个线程的不同日志记录中传递上下文信息。通过 MDC,你可以在日志中添加一些动态的上下文信息,比如事务ID、用户ID等。

要动态设置 TransId 的值,你需要在代码中使用 MDC.put 方法。以下是一个示例:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;public class Log4jExample {private static final Logger logger = LogManager.getLogger(Log4jExample.class);public static void main(String[] args) {// 设置TransId的值ThreadContext.put("TransId", "12345");// 记录日志logger.info("This is a log message with TransId.");// 清除TransId的值ThreadContext.clearMap();}
}

在上面的代码中,我们使用 ThreadContext.put("TransId", "12345") 来设置 TransId 的值。然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值。

例如,log4j2.xml 配置文件可以这样配置:

<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg %X{TransId}%n"/></Console></Appenders><Loggers><Root level="info"><AppenderRef ref="Console"/></Root></Loggers>
</Configuration>

在这个配置中,%X{TransId} 会被替换为 ThreadContextTransId 的值,即 12345

总结:通过在代码中使用 ThreadContext.put("TransId", "value") 方法设置 TransId 的值,然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值,从而实现动态获取和记录 TransId

在Log4j 2中,ThreadContext 是用来替代 Log4j 1.x 中的 MDC 的。对于 Log4j 1.x,你需要使用 MDC.put 方法来设置上下文信息。以下是使用 Log4j 1.x 的示例:

import org.apache.log4j.Logger;
import org.apache.log4j.MDC;public class Log4jExample {private static final Logger logger = Logger.getLogger(Log4jExample.class);public static void main(String[] args) {// 设置TransId的值MDC.put("TransId", "12345");// 记录日志logger.info("This is a log message with TransId.");// 清除TransId的值MDC.clear();}
}

在上面的代码中,我们使用 MDC.put("TransId", "12345") 来设置 TransId 的值。然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值。

例如,log4j.properties 配置文件可以这样配置:

log4j.rootLogger=INFO, Consolelog4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m %X{TransId}%n

在这个配置中,%X{TransId} 会被替换为 MDCTransId 的值,即 12345

总结:对于 Log4j 1.x,通过在代码中使用 MDC.put("TransId", "value") 方法设置 TransId 的值,然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值,从而实现动态获取和记录 TransId。对于 Log4j 2.x,使用 ThreadContext.put 方法来实现相同的功能。

ThreadLocal 是 Java 提供的一种机制,用于在每个线程中存储独立的变量副本。它可以确保变量在多线程环境下的线程安全性,而不需要显式的同步。每个线程都可以独立地修改自己的副本,而不会影响其他线程的副本。

ThreadLocal 的基本原理

  1. 独立副本:每个线程都有一个独立的变量副本,这些副本存储在 ThreadLocal 对象中。每个线程对其副本的修改不会影响其他线程的副本。

  2. 内部存储ThreadLocal 通过 Thread 类中的一个内部 ThreadLocalMap 来存储每个线程的变量副本。ThreadLocalMap 是一个自定义的哈希表,键是 ThreadLocal 对象,值是线程的变量副本。

  3. 访问机制:当线程访问 ThreadLocal 变量时,ThreadLocal 会根据当前线程获取对应的变量副本。如果当前线程没有对应的副本,ThreadLocal 会创建一个新的副本并存储在 ThreadLocalMap 中。

ThreadLocal 的主要方法

  • get():返回当前线程的变量副本。如果当前线程没有对应的副本,则调用 initialValue() 方法创建一个新的副本。
  • set(T value):设置当前线程的变量副本。
  • remove():移除当前线程的变量副本,防止内存泄漏。

示例代码

以下是一个简单的示例,展示了如何使用 ThreadLocal

public class ThreadLocalExample {// 创建一个ThreadLocal变量private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);public static void main(String[] args) {// 创建两个线程Thread thread1 = new Thread(() -> {for (int i = 0; i < 5; i++) {threadLocal.set(threadLocal.get() + 1);System.out.println(Thread.currentThread().getName() + " - " + threadLocal.get());}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 5; i++) {threadLocal.set(threadLocal.get() + 1);System.out.println(Thread.currentThread().getName() + " - " + threadLocal.get());}});thread1.start();thread2.start();}
}

在这个示例中,每个线程都有一个独立的 ThreadLocal 变量副本,互不干扰。

内部实现

ThreadLocal 的内部实现主要依赖于 ThreadLocalMap,这是一个自定义的哈希表,存储在每个线程的 Thread 对象中。以下是一些关键点:

  1. ThreadLocalMapThreadLocalMapThreadLocal 的静态内部类,用于存储每个线程的变量副本。它使用 ThreadLocal 对象作为键,变量副本作为值。

  2. EntryThreadLocalMap 中的每个条目是一个 Entry 对象,包含一个弱引用的 ThreadLocal 键和一个强引用的值。

  3. 垃圾回收:由于 ThreadLocal 键是弱引用,当 ThreadLocal 对象被垃圾回收时,ThreadLocalMap 中对应的条目会被自动清除,防止内存泄漏。

内存泄漏问题

使用 ThreadLocal 时需要注意内存泄漏问题。由于 ThreadLocalMap 中的键是弱引用,但值是强引用,如果不显式调用 remove() 方法,可能会导致内存泄漏。因此,建议在使用完 ThreadLocal 变量后,显式调用 remove() 方法清除变量副本。

threadLocal.remove();

总结ThreadLocal 提供了一种在多线程环境下存储和访问独立变量副本的机制,确保线程安全性。其内部通过 ThreadLocalMap 实现,每个线程都有一个独立的变量副本。使用时需要注意内存泄漏问题,建议在使用完后显式调用 remove() 方法清除变量副本。

ThreadLocalMapThreadLocal 类的一个静态内部类,用于存储每个线程的变量副本。它是 ThreadLocal 实现的核心部分。ThreadLocalMap 通过在每个线程的 Thread 对象中维护一个哈希表来实现这一功能。

ThreadLocalMap 的结构

ThreadLocalMap 是一个自定义的哈希表,包含以下几个关键部分:

  1. EntryThreadLocalMap 中的每个条目是一个 Entry 对象。EntryThreadLocalMap 的静态内部类,包含一个弱引用的 ThreadLocal 键和一个强引用的值。

    static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
    }
    
  2. TableThreadLocalMap 使用一个数组 table 来存储 Entry 对象。数组的大小是2的幂次方,以便于哈希冲突的处理。

    private Entry[] table;
    
  3. ThresholdThreadLocalMap 维护一个阈值 threshold,用于控制何时进行扩容。默认情况下,阈值是数组大小的2/3。

    private int threshold;
    

ThreadLocalMap 的主要方法

  1. set():将值存储到 ThreadLocalMap 中。如果键已经存在,则更新值;如果键不存在,则插入新的条目。

    private void set(ThreadLocal<?> key, Object value) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len - 1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();if (k == key) {e.value = value;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
    }
    
  2. get():从 ThreadLocalMap 中获取值。如果键存在,则返回对应的值;如果键不存在,则返回 null

    private Object getEntry(ThreadLocal<?> key) {int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];if (e != null && e.get() == key)return e.value;elsereturn getEntryAfterMiss(key, i, e);
    }
    
  3. remove():从 ThreadLocalMap 中移除键值对。

    private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len - 1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();expungeStaleEntry(i);return;}}
    }
    

内存泄漏问题

由于 ThreadLocalMap 中的键是弱引用,当 ThreadLocal 对象被垃圾回收时,键会变成 null,但值仍然存在。这可能导致内存泄漏。因此,建议在使用完 ThreadLocal 变量后,显式调用 remove() 方法清除变量副本。

threadLocal.remove();

总结

  • ThreadLocalMapThreadLocal 的静态内部类,用于存储每个线程的变量副本。
  • EntryThreadLocalMap 的静态内部类,包含一个弱引用的 ThreadLocal 键和一个强引用的值。
  • ThreadLocalMap 使用一个数组 table 来存储 Entry 对象,并通过哈希算法和线性探测解决哈希冲突。
  • 主要方法 包括 set()get()remove(),用于存储、获取和移除键值对。
  • 内存泄漏问题:由于键是弱引用,值是强引用,建议在使用完 ThreadLocal 变量后显式调用 remove() 方法清除变量副本。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

相关文章:

log4j日志配置%X{TransId}

log4j日志配置文件中的%X{TransId}是怎么动态获取值的 在Log4j中&#xff0c;%X{TransId} 是用来从MDC&#xff08;Mapped Diagnostic Context&#xff09;中获取值的占位符。MDC 是 Log4j 提供的一种机制&#xff0c;用于在同一个线程的不同日志记录中传递上下文信息。通过 M…...

PHP模拟高并发异步请求测试+redis的setnx处理并发和防止死锁处理

/** PHP并发异步请求测试* /test/curlMulti*/public function curlMultiAction(){$urls ["http://localhost:801/api/order/create","http://localhost:801/api/order/create","http://localhost:801/api/order/create","http://localhos…...

访问网站出现“此站点不安全”如何解决

在网络浏览中&#xff0c;我们经常会遇到浏览器地址栏出现“此站点不安全”的警告。这通常意味着网站没有使用SSL&#xff08;安全套接层&#xff09;加密来保护用户数据的安全。那么&#xff0c;如何通过获得并安装SSL证书来消除这一警告&#xff0c;确保网站的安全可靠呢&…...

同一台电脑同时连接使用Gitee(码云)和Github

1、添加对应的密钥 ssh-keygen -t rsa -C "your_emailexample.com" -f ~/.ssh/github_id-rsa //生成github秘钥 ssh-keygen -t rsa -C "your_emailexample.com" -f ~/.ssh/gitee_id-rsa //生成码云秘钥 2、在 ~/.ssh 文件里会生成对应的文件 文件夹里会…...

GORM 插入和批量插入操作介绍

GORM 是一个功能强大的 Go 语言 ORM 库&#xff0c;它提供了简单易用的 API 来执行数据库操作。本文将介绍如何使用 GORM 进行单条记录插入和批量插入操作。 单条记录插入 在 GORM 中&#xff0c;插入一条记录非常简单。首先&#xff0c;你需要定义一个模型&#xff0c;该模型…...

企业CAD图纸加密软件推荐!2024年好用的10款CAD图纸加密软件排行

在现代企业中&#xff0c;CAD图纸作为重要的设计和工程数据&#xff0c;其安全性和保密性至关重要。为了防止图纸被非法获取、篡改或滥用&#xff0c;选择一款高效的CAD图纸加密软件显得尤为重要。本文将为您推荐2024年市场上十款好用的CAD图纸加密软件&#xff0c;帮助企业保护…...

智能电梯标志新时代:墨水屏电子标签引领变革

电梯安全墨水屏标签的智能设备悄然出现在各大写字楼和住宅区的电梯中&#xff0c;引发了广泛关注。这款设备替代了传统的纸质电梯标志&#xff0c;通过手机蓝牙标签APP直接进行编辑刷新内容&#xff0c;并具备Type-C接口充电功能。 本文将深入探讨这一创新技术的应用前景及其对…...

使用nvm下载nodejs版本报错

这里写自定义目录标题 使用nvm下载nodejs版本报错&#xff1a;Error retrieving "http://npm.taobao.org/mirrors/node/latest/SHASUMS256.txt": HTTP Status 404问题原因解决办法 使用nvm下载nodejs版本报错&#xff1a;Error retrieving “http://npm.taobao.org/m…...

深入理解CSS的:valid和:invalid伪类:增强表单验证的艺术

在现代网页设计中&#xff0c;用户输入验证是一个重要的环节&#xff0c;它不仅关乎用户体验&#xff0c;也是数据准确性和安全性的保障。CSS3引入了两个强大的伪类选择器&#xff1a;:valid和:invalid&#xff0c;它们允许开发者通过CSS来增强表单输入的验证过程&#xff0c;而…...

稚晖君发布5款全能人形机器人,开源创新,全能应用

8月18日&#xff0c;智元机器人举行“智元远征 商用启航” 2024年度新品发布会&#xff0c;智元联合创始人彭志辉主持并发布了“远征”与“灵犀”两大系列共五款商用人形机器人新品——远征A2、远征A2-W、远征A2-Max、灵犀X1及灵犀X1-W&#xff0c;并展示了在机器人动力、感知、…...

【总结】冲击偶的概念与性质

冲击偶的概念与性质...

Hbase图形化界面

分享一个好用的hbase图形化界面 安装包&#xff1a;链接: https://pan.baidu.com/s/11Y2cDlme-P2xe--pYqy6MQ?pwdguag 提取码: guag 1、上传项目到linux 2、修改数据库配置信息 application-druid.yml 修改url、username、password为数据库连接信息 3、创建数据库(注意字符集…...

PhalApi:在宝塔一键安装部署PHP开源接口框架的教程

如何在宝塔上&#xff0c;一键安装部署PhalApi开源接口框架&#xff1f; 第一步&#xff0c;进入你的宝塔 - 软件商店。 第二步&#xff0c;切换到&#xff1a;一键部署&#xff1b; 第三步&#xff0c;搜索 phalapi&#xff1b; 第四步&#xff0c;点击 一键部署&#xff1…...

什么是BERT?工程快速入门

基本介绍 全称是Bidirectional Encoder Representations from Transformers。BERT翻译成中文通常被称为“双向编码器表征法”或简单地称为“双向变换器模型” Bidirectional&#xff1a;是双向神经网络&#xff0c;这个在学习 RNN 时候我们就了解到如何使用双向 RNN 让每一个…...

SQL - 事务

事务是代表单个工作单元的一组SQL语句&#xff0c;当我们需要对数据库进行多次更改的情况下&#xff0c;要使用事务&#xff0c;我们希望所有这些更改作为一个单元一起成功或失败事务属性 (ACID) 原子性(Atomicity)&#xff1a;事务中的所有操作要么全部完成&#xff0c;要么全…...

系统, 安装完以后只能进ubuntu

1.问题 在已经安装了Windows10系统的情况下&#xff0c;用U盘安装Ubuntu 16.04双系统&#xff0c; 安装完以后只能进ubuntu&#xff0c;在grub系统选择界面&#xff0c;Windows10操作系统的选项都没有。 2.解决办法 进入ubuntu系统&#xff0c;打开终端输入: sudo update-g…...

闲鱼功能全解析:闲置物品快速变现

咸鱼&#xff08;现已更名为闲鱼&#xff09;作为一款闲置交易平台&#xff0c;其功能设计旨在提供一个方便、安全的环境&#xff0c;让用户能够轻松地买卖二手物品。以下是对咸鱼&#xff08;闲鱼&#xff09;功能的详细分析 1. 商品发布与管理 商品发布&#xff1a;用户可以…...

牛客网SQL进阶129 :月均完成试卷数不小于3的用户

月均完成试卷数不小于3的用户爱作答的类别_牛客题霸_牛客网 0 问题描述 基于试卷作答记录表exam_record、试卷信息表examination_info &#xff0c;统计出 “月均完成试卷数”不小于3的用户作答的类别及作答次数&#xff0c;按次数降序输出。 1 数据准备 drop table if exis…...

Astro + Cloudflare Pages 快速搭建个人博客

目录 1 选择 Astro 模板2 使用代码3 修改代码4 上传 Github5 部署 Cloudflare Pages6 后续修改 最近我搭建完了我的个人网站&#xff0c;很多人问是怎么做的&#xff0c;今天就来写一篇教程吧。 全部干货&#xff0c;看完绝对能成功搭建自己的网站&#xff01;&#xff08;还不…...

Vue中<style scoped>与<style module>的深入解析与应用

在Vue开发中&#xff0c;样式管理是一个重要的环节。Vue提供了多种方式来帮助开发者更有效地管理组件样式&#xff0c;其中<style scoped>和<style module>是两个非常实用的特性。本文将深入探讨这两个属性的作用、原理以及使用场景&#xff0c;帮助读者更好地理解…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...