IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Logback使用学习二(深入Appender) -> 正文阅读

[移动开发]Logback使用学习二(深入Appender)

	在Logback的官方文档中对Appender的标签定义如下。

Logback delegates the task of writing a logging event to components called appenders.
翻译过来就是?Logback 将写入日志记录事件的任务委托给称为追加器的组件?.
LogBack提供了几种常见的Appender,可以开箱即用。

1.控制台输出器ConsoleAppender

ConsoleAppender是logback.core提供的基础Appender
至于是如何实现控制台输出的,且看它的源码

public class ConsoleAppender<E> extends OutputStreamAppender<E> {

  //这里只看它的两个属性,target就是输出目标,这个类型为枚举类型,指定了Systemout的输出
  //方式
  protected ConsoleTarget target = ConsoleTarget.SystemOut;

  //这里的withJansi为是否开启控制台输出可以使用多种颜色,我们在后面会演示
  protected boolean withJansi = false;

......
}

再次进入ConsoleTarget枚举类型的源码,这个枚举类设置的比较巧,即设置了变量,也设计了枚举值,并且在枚举值上调用了枚举类的构造函数

public enum ConsoleTarget {

  SystemOut("System.out", new OutputStream() {
    //重写了输出流,都使用控制台输出
    @Override
    public void write(int b) throws IOException {
      System.out.write(b);
    }
    @Override
    public void write(byte b[]) throws IOException {
      System.out.write(b);
    }
    @Override
    public void write(byte b[], int off, int len) throws IOException {
      System.out.write(b, off, len);
    }
    @Override
    public void flush() throws IOException {
      System.out.flush();
    }
  }),

  SystemErr("System.err", new OutputStream() {
    @Override
    public void write(int b) throws IOException {
      System.err.write(b);
    }
    @Override
    public void write(byte b[]) throws IOException {
      System.err.write(b);
    }
    @Override
    public void write(byte b[], int off, int len) throws IOException {
      System.err.write(b, off, len);
    }
    @Override
    public void flush() throws IOException {
      System.err.flush();
    }
  });

  public static ConsoleTarget findByName(String name) {
    for (ConsoleTarget target : ConsoleTarget.values()) {
      if (target.name.equalsIgnoreCase(name)) {
        return target;
      }
    }
    return null;
  }
  //在枚举值中对下面的两个属性进行了初始化
  private final String name;
  private final OutputStream stream;

  private ConsoleTarget(String name, OutputStream stream) {
    this.name = name;
    this.stream = stream;
  }

  public String getName() {
    return name;
  }

  public OutputStream getStream() {
    return stream;
  }
}

当然,以上得都只是看他如何工作,和实际使用没什么关系。

如果需要使用到控制台Appender,就只要配置个Appender标签即可。

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">	
	<encoder>
		<pattern>
			%date{yyyy-MM-dd hh:mm:ss}| %5level [%thread] - %msg%n
		</pattern>
	</encoder>
</appender>

(PS:这里演示一下设置withJansi属性,前提是安装了jansi包)
如果你在ConsoleAppender的appender标签中设置了属性withJansi为true,则你可以在pattern标签中设置颜色,

<!--jansi的使用非常的简单,只需要使用   %+颜色名(需要改色的地方) 就可以修改-->
<pattern>
	%date{yyyy-MM-dd hh:mm:ss}| %blue(%5level) [%thread] - %msg%n
</pattern>

查看图片效果。

在这里插入图片描述

2.FileAppender文件输出器

FileAppender也是logback.core中的基础Appender组件,它允许我们把日志记录到文件
FileAppender对文件的修改和输出都是线程安全的,这些可以从源码中看出来,

public void openFile(String file_name) throws IOException {
    //使用继承自父类的锁进行上锁
    lock.lock();
    try {
      File file = new File(file_name);
      if (FileUtil.isParentDirectoryCreationRequired(file)) {
        boolean result = FileUtil.createMissingParentDirectories(file);
        if (!result) {
          addError("Failed to create parent directories for ["
              + file.getAbsolutePath() + "]");
        }
      }
      ResilientFileOutputStream resilientFos = new ResilientFileOutputStream(
          file, append);
      resilientFos.setContext(context);
      setOutputStream(resilientFos);
    } finally {
     //最终解锁
      lock.unlock();
    }
  }

同时文件的写入环节也加了锁

 private void safeWrite(E event) throws IOException {
    ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) getOutputStream();
    FileChannel fileChannel = resilientFOS.getChannel();
    if (fileChannel == null) {
      return;
    }
    FileLock fileLock = null;
    try {
      fileLock = fileChannel.lock();
      long position = fileChannel.position();
      long size = fileChannel.size();
      if (size != position) {
        fileChannel.position(size);
      }
      super.writeOut(event);
    } finally {
      if (fileLock != null) {
        fileLock.release();
      }
    }
  }

  @Override
  protected void writeOut(E event) throws IOException {
    if (prudent) {
      safeWrite(event);
    } else {
      super.writeOut(event);
    }
  }

同样使用起来也很简单

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
	<file>{可以设置一个变量}</file>
	<!--是否追加输出-->
	<append>true</append>
	<!--输出模式-->
	<prudent>false</prudent>
	<encoder>
		<!--这里有一个人小细节,在FileAppender中不推荐使用layout标签,否则会出现警告-->
		<pattern>
			%date{yyyy-MM-dd hh:mm:ss}|%5level [%thread] - %msg%n
		</pattern>
	</encoder>
</appender>

警告如下,但是还是能完成向文件输出日志的功能

16:05:04,387 |-WARN in ch.qos.logback.core.FileAppender[FILE] - This appender no longer admits a layout as a sub-component, set an encoder instead.
16:05:04,387 |-WARN in ch.qos.logback.core.FileAppender[FILE] - To ensure compatibility, wrapping your layout in LayoutWrappingEncoder.
16:05:04,387 |-WARN in ch.qos.logback.core.FileAppender[FILE] - See also http://logback.qos.ch/codes.html#layoutInsteadOfEncoder for details
16:05:04,387 |-INFO in ch.qos.logback.core.FileAppender[FILE] - File property is 

3.RollingFileAppender滚动文件输出器

这个Appender继承了FileApppender,可以实现比FileAppender更加高级的行为。
体现在源码中为多出了两个属性可以设置。

public class RollingFileAppender<E> extends FileAppender<E> {

  File currentlyActiveFile;
  //触发滚动策略接口,可以自定义
  TriggeringPolicy<E> triggeringPolicy;
  //滚动策略接口,可以自定义
  RollingPolicy rollingPolicy;
  
........
}

RollingPolicy滚动策略

在Logback也提供了现成的滚动策略,像
请添加图片描述

请添加图片描述

1.TimeBasedRollingPolicy时间基准滚动策略

在实际的工作中可能用的比较多的就是TimeBasedRollingPolicy了,
TimeBasedRollingPolicy有一个必要属性和一些非必要属性。

属性名类型描述
fileNamePattern(必要)String滚动生成文件名的模式
maxHistoryint最大保留周期
totalSizeCapint最大空间占用
cleanHistoryOnStartboolean是否在开始运行时清除历史纪录

这里需要再介绍一下fileNamePattern属性了,其他的属性基本见名知意。

这里的fileNamePattern为滚动生成文件名的模式,
必须包含%d字符用来描述
且必须在其后追加一个日期格式用来生成文件名
同时该日期格式的精度也是日志生成的频率
这里看一个例子:

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- 将生成日志的日期精确到秒 -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd_HH-mm-ss}.log</fileNamePattern>
      <!--最多保存30秒的数据-->
      <maxHistory>30</maxHistory>
      <!--最多占用3GB空间-->
      <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

测试代码:

public class MyLogTest {
	

	final static Logger logger = LoggerFactory.getLogger(MyLogTest.class);
	
	public static void main(String[] args) throws InterruptedException {
		
		logger.warn("DoBefore");
		DoSomething();
		logger.debug("helloshit");
		logger.error("helloshit");
		logger.trace("helloshit");
		logger.info("helloshit");
		logger.debug("helloshit");
		Thread.sleep(2000);
		logger.info("ThisTimeBasedRollingFile");
	}
	
	public static void DoSomething() {
		System.out.println("This method will do something");
	}

}

结果:
请添加图片描述
更详细的细节可以看
https://logback.qos.ch/manual/appenders.html

2.FixedWindowRollingPolicy固定窗口滚动策略

它有三个属性

属性名类型描述
minIndex最小索引i的开始
maxIndex最大索引i的结束
fileNamePatternString文件名模式

这个策略的使用非常的简单,只需要你指定一个%i,
i会在miIndex到maxindex中自增,形成一串连续的日志文件

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  	<file>logTest.log</file>
  	<!--窗口滚动策略-->
  	<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
  		<fileNamePattern>logTest_%i.log</fileNamePattern>
  		<minIndex>1</minIndex>
  		<maxIndex>5</maxIndex>
  	</rollingPolicy>
  	<!--滚动触发器,以日志大小为条件-->
  	<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
  		<maxFileSize>1KB</maxFileSize>
  	</triggeringPolicy>
  	
  	<encoder>
  		<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  	</encoder>
  </appender>

测试代码

public static void main(String[] args){
    //只要你认为产生的日志文件一定会大于1KB就行
	logger.debug("FixedWindowRollingPolicyTest");X99
}

刷新,查看生成的日志
请添加图片描述
logback成功的按大小生成了三份日志。

TriggeringPolicy触发滚动策略

在上一个例子中我使用了TriggeringPolicy的一个现成的实现
SizedTriggeringPolicy
这是按日志文件大小触发的触发滚动策略
它只有MaxFileSize一个属性,在其中你可以设置触发的阈值。
在logback中提供两种现成的TriggeringPolicy,
SizeBasedTriggeringPolicy空间触发器
TimeBasedFileNamingAndTriggeringPolicy时间和文件名除雾器
在上面的TimeBasedRollingPolicy的例子中其实是使用的第二个触发器。
当然了,它也可以继承TriggeringPolicyBase进行自定义

自定义TriggeringPolicy

//自定义TiggeringPolicy,关键词触发器
//定义的方法很简单,继承TriggeringPolicyBased即可
public class MyTriggeringPolicy<E> extends TriggeringPolicyBase<E>{

	private String KeyWord;
	
	public String getKeyWord() {
		return KeyWord;
	}
    
	//可以尝试去读取文件,但笔者的水平不足,总会造成EOF错误,望得到提示
	//public DataInputStream fin;
	
	public void setKeyWord(String keyWord) {
		KeyWord = keyWord;
	}

	@Override
	public boolean isTriggeringEvent(final File activeFile,final E event) {
		
		if(event.toString().contains(KeyWord))
			return true;
		else
			return false;
	}

}

在XML中配置你的自定义的TriggeringPolicy即可

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  	<file>logTest.log</file>
  	<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
  		<fileNamePattern>logTest_%i.log</fileNamePattern>
  		<minIndex>1</minIndex>
  		<maxIndex>5</maxIndex>
  	</rollingPolicy>
  	<!--很简单,只需要在Class属性上天上自己的类-->
  	<triggeringPolicy class="TestPack.MyTriggeringPolicy">
  		<keyWord>ASSHOLE</keyWord>
  	</triggeringPolicy>

测试一下

public static void main(String[] args) throws InterruptedException {
		//这里我们以关键词ASSHOLE进行触发滚动
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("ASSHOLE");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("ASSHOLE");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
		logger.debug("FixedWindowRollingPolicyTest");
	}

请添加图片描述
成功的按照设置的关键词滚动生成了日志文件

4.日志事件过滤器Filter标签

有些appender中也许为了节省空间,干脆不记录一些DEBUG一下的记录,你可以使用Filter过滤掉,
也可以像本文的第一篇的方法,直接设置高等级的logger的level属性
当然你也可以指定一些特殊的规则,这里展示一个简单的例子

/**
 * 自定义Filter,直接继承Filter类然后实现Decide方法即可,关于返回值的意义同上篇文章所讲
 * @author Sultan OF Rome
 * @Time 2022年5月6日
 * @ClassName MyFilter
 * @param <E>
 */
public class MyFilter<E> extends Filter<E>{
	
	private String FilterMark;
	
	public String getFilterMark() {
		return FilterMark;
	}

	public void setFilterMark(String filterMark) {
		FilterMark = filterMark;
	}

	@Override
	public FilterReply decide(E event) {
		if(event.toString().contains(FilterMark))
			return FilterReply.DENY;
		else
			return FilterReply.ACCEPT;
	}

}

配置到XML中去(这里偷个懒,直接加到上一个配置文件中去)

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  	<!--添加自定义的Filter-->
  	<filter class="Filters.MyFilter">
  		<FilterMark>Sultan</FilterMark>
  	</filter>
  	<file>logTest.log</file>
  	<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
  		<fileNamePattern>logTest_%i.log</fileNamePattern>
  		<minIndex>1</minIndex>
  		<maxIndex>5</maxIndex>
  	</rollingPolicy>
  	<triggeringPolicy class="TestPack.MyTriggeringPolicy">
  		<keyWord>ASSHOLE</keyWord>
  	</triggeringPolicy>
  	
  	<encoder>
  		<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
  	</encoder>
  </appender>

测试:

public static void main(String[] args) throws InterruptedException {
		
		
		logger.debug("FilterTest");
		logger.debug("FilterTest");
		logger.debug("FilterTest");
		logger.debug("Sultan");
		logger.debug("FilterTest");
		logger.debug("FilterTest");
		logger.debug("FilterTest");
		logger.debug("Sultan");
		
		
	}

结果(日志文件中):

467  [main] DEBUG TestPack.MyLogTest - FilterTest
470  [main] DEBUG TestPack.MyLogTest - FilterTest
470  [main] DEBUG TestPack.MyLogTest - FilterTest
471  [main] DEBUG TestPack.MyLogTest - FilterTest
471  [main] DEBUG TestPack.MyLogTest - FilterTest
471  [main] DEBUG TestPack.MyLogTest - FilterTest

可见,我们设置的filter已经将我们的指定的日志事件过滤了。

好了这里都是些日常可能会用到的Appender,希望对读者有一些帮助,谢谢观看

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 08:15:26  更:2022-05-08 08:15:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 0:46:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码