前言

一般都会对应用程序日志做回滚处理,本文简要分析 log4j2 日志回滚实现

触发策略

log4j2 使用 TriggeringPolity 接口来抽象日志回滚触发策略,使用了 Strategy + Compose 设计模式

public interface TriggeringPolicy {void initialize(final RollingFileManager manager);boolean isTriggeringEvent(final LogEvent event);
}

initialize 方法用于初始化策略,isTriggeringEvent 方法用于判断是否需要回滚,TriggeringPolicy 接口的不同实现类对应不同的策略

// 组合模式,聚合不同的策略类
public final class CompositeTriggeringPolicy implements TriggeringPolicy {...
}
// 基于时间的回滚策略
public final class TimeBasedTriggeringPolicy implements TriggeringPolicy {...
}
// 基于文件大小的回滚策略
public final class SizeBasedTriggeringPolicy implements TriggeringPolicy {...
}

基于时间的触发策略

回滚策略

log4j2 使用 RolloverStrategy 接口抽象日志回滚策略

public interface RolloverStrategy {RolloverDescription rollover(final RollingFileManager manager)throws SecurityException;
}

rollover 方法并不直接执行回滚操作,而是返回一个 RolloverDescription 接口,该接口用于获取日志回滚需要进行的操作: Action

public interface RolloverDescription {String getActiveFileName();boolean getAppend();Action getSynchronous();Action getAsynchronous();
}

回滚动作

log4j2 使用 Action 接口抽象日志回滚过程中的一系列动作,使用了 Command + Compose 设计模式

public interface Action extends Runnable {boolean execute() throws IOException;void close();boolean isComplete();
}

AbstractAction 类是 Action 接口的抽象实现,使用了 Method template 设计模式,子类通过 override execute 方法执行不同的动作

public synchronized void run() {if (!interrupted) {try {execute();} catch (final IOException ex) {reportException(ex);}complete = true;interrupted = true;}
}public abstract boolean execute() throws IOException;
  • 文件重命名,FileRenameAction

  • 文件删除,DeleteAction

  • 文件压缩,GzCompressAction, ZipCompressAction

  • 聚合,CompositeAction

回滚管理

log4j2 每个 Appender 都有一个 Manager 与之对应(多对一), RollingFileAppender 对应的 Manager 为RollingFileManager, 它管理着日志的写入,回滚 .etc,类层次结构

AbstractManagerOutputStreamManagerFileManagerRollingFileManager

非常经典的 面向对象 设计,单一职责. AbstractManager 保存 Manager 基本信息,例如 name(名字),count(引用计数),并提供静态工厂方法根据名字获取 Manager,这个方法同样值得学习和借鉴

    public static <M extends AbstractManager, T> M getManager(final String name,final ManagerFactory<M, T> factory, final T data) {// 获取锁LOCK.lock();try {@SuppressWarnings("unchecked")M manager = (M) MAP.get(name);if (manager == null) {// 使用工厂类创建具体的 Managermanager = factory.createManager(name, data);if (manager == null) {throw new IllegalStateException("ManagerFactory [" + factory + "] unable to create manager for ["+ name + "] with data [" + data + "]");}MAP.put(name, manager);} else {manager.updateData(data);}// 增加引用计数manager.count++;return manager;} finally {// 释放锁LOCK.unlock();}}

RollingFileAppender 在 append LogEvent 时会先调用 RollingFileManager 的 checkRollover 方法尝试进行日志回滚,然后再调用父类的 append 方法,这种子类通过 override 方法 "拦截" 父类默认实现增加自己的处理逻辑的方法很常见

// RollingFileAppender.java@Override
public void append(final LogEvent event) {getManager().checkRollover(event);super.append(event);
}

RollingFileManager 的 checkRollover 方法使用上文提到的 触发策略类 TriggeringPolicy 判断是否符合触发条件,如果符合调用 rollover 方法

public synchronized void checkRollover(final LogEvent event) {if (triggeringPolicy.isTriggeringEvent(event)) {rollover();}
}

不带参数的 rollover 方法最终调用带 RolloverStrategy(回滚策略)类型参数的版本,为了代码显示更加紧凑特意省略掉了日志输出和异常处理逻辑,有几个地方值得品味

  • 使用信号量进行同步,所以不要太频繁打 log 触发回滚,会 block 线程

  • 同步 Action 在当前线程立即执行,异步 Action 则启动一个线程执行

  • 如果异步 Action 很可执行完毕(某些极端情况),finally 语句块会释放 semaphore

    private boolean rollover(final RolloverStrategy strategy) {semaphore.acquire();boolean success = false;Thread thread = null;try {final RolloverDescription descriptor = strategy.rollover(this);if (descriptor != null) {writeFooter();close();if (descriptor.getSynchronous() != null) {success = descriptor.getSynchronous().execute();}if (success && descriptor.getAsynchronous() != null) {thread = new Log4jThread(new AsyncAction(descriptor.getAsynchronous(), this));thread.start();}return true;}return false;} finally {if (thread == null || !thread.isAlive()) {semaphore.release();}}}

总结

Log42j 源代码分析:日志回滚相关推荐

  1. linux 日志回滚,Linux 下的日志回滚机制探讨

    在linux下的日志会定期进行回滚,控制系统执行日志回滚操作的配置文件主要有:/etc/logrotate.conf以及/etc/logrotate.d/这个目录下的明细配置文件. /etc/logr ...

  2. Nginx源代码分析 - 日志处理

    我看Nginx源代码的时候,感觉整个系统都在传递log指针.log在nginx里是比较关键的.日志和内存分配是最基础的两个起点代码,最好是在自己写的程序框架中早点完善并实现.以免未来要用大量的精力调整 ...

  3. Log42j 源代码分析:plugin(插件)机制

    前言 log4j2 使用插件机制加载各种组件:appender, logger .etc,本文简要分析 log4j2 插件机制实现 Plugin Annotation(注解) Plugin 注解提供了 ...

  4. Linux自定义日志文件设置回滚(避免信息溢出)

    文章目录 一.概述 二.代码实现 三.所用函数说明 (1)C库函数ftell() (2)C库函数fseek() (3)C库函数rewind() (4)Linux系统函数truncate() 一.概述 ...

  5. python logging模块-写日志、log回滚

    python包/模块,专栏总目录: 1.python自定义模块 2.python模块调用顺序 3.python logging模块 4.python定义跨模块的全局变量 1.logging模块简介 l ...

  6. 代码回滚,你真的理解吗?

    什么是代码回滚? 在我正式开始今天的分享前,先给你讲两个核心概念: 1. 包回滚是指,线上运行的系统,从现在的版本回滚到以前稳定的老版本. 2. 代码回滚是指,Git 分支的指针(游标),从指向当前有 ...

  7. Spring 事务提交回滚源码解析

    2019独角兽企业重金招聘Python工程师标准>>> 前言 在上篇文章 Spring 事务初始化源码分析 中分析了 Spring 事务初始化的一个过程,当初始化完成后,Spring ...

  8. binlog回滚mysql误操作数据

    记录mysql误操作 删除或者修改数据后如何回滚 线上数据库中的数据不像测试数据库那样,需要严谨的使用,如果因为误操作导致数据失真,是比较严重的线上事件 以下举例如何通过mysql binlog日志回 ...

  9. mysql数据库回滚日志_超干货!为了让你彻底弄懂 MySQL 事务日志,我通宵搞出了这份图解...

    作者 | Amazing10 责编 | 屠敏 本文为业余码农投稿,已获授权 还记得刚上研究生的时候,导师常挂在嘴边的一句话,"科研的基础不过就是数据而已."如今看来,无论是人文社科 ...

  10. 事务回滚什么意思 try_分布式事务 TCC-Transaction 源码分析——事务恢复

    1. 概述 本文分享 TCC 恢复.主要涉及如下二个 package 路径下的类: org.mengyun.tcctransaction.recover RecoverConfig,事务恢复配置接口 ...

最新文章

  1. Java面试之Java基础下册(含答案)
  2. 转 使用putty从linux主机上面往windows主机下面拷贝文件
  3. mysql 安装手册(转)
  4. JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器
  5. 发掘VS2005 SP1 (一)
  6. 【ArcGIS遇上Python】从入门到精通系列之第一章:ArcGIS Python简介
  7. webform计算某几列结果_WebForm获取checkbox选中的值(几个简单的示例)
  8. js(javascript)之浏览器控制台使用
  9. shell脚本和linux命令,Linux shell脚本全面学习(一)
  10. 微服务升级_SpringCloud Alibaba工作笔记0002---理解反应式编程中的背压(Backpressure)机_流的逆向压力
  11. java cache system_JCS(Java Cache System)基本结构分析和使用
  12. C++数据结构——栈
  13. CentOS7搭建邮件服务器+Roundcube webMail
  14. HTML+CSS期末网页课设——游戏宣传网页(全部源码)
  15. 电脑开机计算机配置,电脑开机显示正在配置更新请勿关闭计算机 重新启动之后,电脑里的数...
  16. 数据分析报告这样写,才算真正读懂了数据
  17. var foo = 11+2+1; console.log(foo); //1121 好多文章答案写错了,我发下给初学的朋友看到,以免一开始就学错了...
  18. Android系统安全 — 3.1-展锐平台secureboot安全启动流程和使用
  19. poj 3975hdu 1850 (nim)
  20. Coders @ Work

热门文章

  1. HMM:隐马尔科夫模型 - 学习
  2. numpy教程:数组操作
  3. POJ读书笔记6.1 - 约瑟夫问题 2746
  4. 力扣-605 种花问题
  5. linux实现设备在uboot状态下利用TFTP和NFS加载内核镜像和根文件系统
  6. Android的Wifi系统框架分析第一篇
  7. 给spring容器注册组件
  8. 解决局域网共享时提示:你没有权限访问,请与网络管理员联系
  9. git命令的理解与扩展
  10. Hash算法入门指南(聊点不一样的算法人生)