测试并发应用(五) 编写有效的日志

简介:

声明:本文是《 Java 7 Concurrency Cookbook 》的第八章, 作者: Javier Fernández González 译者:郑玉婷

写有效的日志

log工具提供了允许你写信息到一个或者多个目的地的机制。一个Logger是由以下这些组成:

  • 一个或多个处理者: 一个处理者将决定目的地和log信息的格式。你可以把日志信息写入操控台,文档,或者数据库。
  • 名字: 通常Logger使用的名字是基于类名或者它的包名。
  • 等级: 日志信息有等级来表明它的重要性。Logger也有个等级是用来决定写什么样的信息。它只会写和这个等级一样重要的,或者更重要的信息。

为了以下2个主要目的,你应该使用log 系统:

  • 当异常被捕捉,写尽可能多的信息。这个会帮助你定位错误并解决它。
  • 写关于程序正在执行的类和方法的信息。

在这个指南,你将学习如何使用 java.util.logging 包提供的类来添加一个log系统到你的并发应用。

准备

指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。

怎么做呢…

按照这些步骤来实现下面的例子:

001 //1.    创建一个类,名为MyFormatter ,扩展 java.util.logging.Formatter 类。实现抽象方法 format()。它接收一个 LogRecord 对象作为参数,并返回一个有着日志信息 String 对象。
002 public class MyFormatter extends Formatter {
003     @Override
004     public String format(LogRecord record) {
005  
006         StringBuilder sb=new StringBuilder();
007         sb.append("["+record.getLevel()+"] - ");
008         sb.append(new Date(record.getMillis())+" : ");
009         sb.append(record.getSourceClassName()+ "."+record.getSourceMethodName()+" : ");
010         sb.append(record.getMessage()+"\n");
011  
012         return sb.toString();
013     }
014  
015 //2.   创建一个类,名为 MyLogger。
016 public class MyLogger {
017  
018 //3.   声明一个私有 static Handler 属性,名为 handler。
019 private static Handler handler;
020  
021 //4.   实现公共 static 方法 getLogger() 来创建 Logger 对象,你将要使用它来写日志信息。它接收一个String 参数,名为 name。
022 public static Logger getLogger(String name){
023  
024 //5.   使用 Logger 类的getLogger() 方法,获取与 java.util.logging.Logger 相关联的 name 作为参数。
025 Logger logger=Logger.getLogger(name);
026  
027 //6.   使用 setLevel() 方法,确立用来写入全部信息的log级别。
028 logger.setLevel(Level.ALL);
029  
030 //7.    如果处理者属性为null值,创建一个新的 FileHandler 对象在 recipe8.log 文件内写日志信息。使用 setFormatter()对象给处理者分配一个 MyFormatter  对象作为格式。
031 try {
032     if (handler==null) {
033         handler=new FileHandler("recipe8.log");
034         Formatter format=new MyFormatter();
035         handler.setFormatter(format);
036     }
037  
038 //8.   If the 如果 Logger 对象还有一个与之相关联的处理者,使用 addHandler() 方法分配一个处理者。
039     if (logger.getHandlers().length==0) {
040         logger.addHandler(handler);
041     }
042 catch (SecurityException e) {
043     e.printStackTrace();
044 catch (IOException e) {
045     e.printStackTrace();
046 }
047  
048 //9.   返回创建的 Logger 对象。
049 return logger;
050 }
051  
052 //10. 创建一个类,名为Task,它实现Runnable 接口。它将是用来测试你的Logger对象的任务。
053 public class Task implements Runnable {
054  
055 //11. 实现 run() 方法。
056 @Override
057 public void run() {
058  
059 //12. 首先,声明一个 Logger 对象,名为 logger。使用 MyLogger 类的 getLogger() 方法传递这个类的名字为参数来初始它。
060 Logger logger= MyLogger.getLogger(this.getClass().getName());
061  
062 //13. 使用 entering() 方法写日志信息表明执行开始。
063 logger.entering(Thread.currentThread().getName(), "run()");
064 //休眠2秒。
065 try {
066     TimeUnit.SECONDS.sleep(2);
067 catch (InterruptedException e) {
068     e.printStackTrace();
069 }
070  
071 //14.使用 exiting() 方法写日志信息表明执行结束
072 logger.exiting(Thread.currentThread().getName(), "run()",Thread.currentThread());
073 }
074  
075 //15. 创建例子的主类通过创建一个类,名为 Main 并添加 main()方法。
076 public class Main {
077  
078 public static void main(String[] args) {
079  
080 //16. 声明一个 Logger 对象,名为 logger。使用 MyLogger 类的 getLogger() 方法传递字符串 Core 作为参数来初始它
081 Logger logger=MyLogger.getLogger("Core");
082  
083 //17. 使用 entering() 方法写日志信息表明主程序开始执行。
084 logger.entering("Core""main()",args);
085  
086 //18. 创建 Thread array 来保存5个线程。
087 Thread threads[]=new Thread[5];
088  
089 //19. 创建5个Task对象和5个执行他们的线程。写日志信息表明,你将运行一个新的线程和表明你已经创建了线程。
090 for (int i=0; i<threads.length; i++) {
091     logger.log(Level.INFO,"Launching thread: "+i);
092     Task task=new Task();
093     threads[i]=new Thread(task);
094     logger.log(Level.INFO,"Thread created: "+ threads[i]. getName());
095     threads[i].start();
096 }
097  
098 //20. 写日志信息表明你已经创建了线程。
099 logger.log(Level.INFO,"Ten Threads created.""Waiting for its finalization");
100  
101 //21. 使用 join() 方法等待5个线程的终结。在每个线程终结之后,写日志信息表明线程已经结束。
102 for (int i=0; i<threads.length; i++) {
103     try {
104         threads[i].join();
105         logger.log(Level.INFO,"Thread has finished its execution",threads[i]);
106     catch (InterruptedException e) {
107         logger.log(Level.SEVERE, "Exception", e);
108     }
109 }
110  
111 //22. 使用 exiting() 方法写一个日志信息表明主程序运行结束。
112 logger.exiting("Core""main()");
113 }

它是如何工作的…

在这个指南里,你已经使用 Java logging API 提供的Logger类 在并发应用中写日志信息。首先,你实现了 MyFormatter 类来给日志信息一个格式。这个类扩展 Formatter 类,声明了抽象方法 format()。此方法接收 LogRecord 对象的全部日志消息信息,并返回一条格式化的日志信息。在你的类里使用了 LogRecord类的以下这些方法来获取日志信息:

  • getLevel(): 返回的信息的级别。
  • getMillis():返回日期,当一条信息被发送给 Logger 对象。
  • getSourceClassName(): 返回发送信息给Logger的类的名字。
  • getSourceMessageName():返回发送信息给Logger的方法的名字
  • getMessage() 返回日志信息。MyLogger 类实现了静态方法 getLogger(), 创建 Logger 对象并分配 Handler 对象使用MyFormatter的格式在recipe8.log 文件中写入日志信息。你可以使用这个类的静态方法 getLogger() 创建对象。此方法返回每个不同的对象作为参数传递的名字。 你只要创建一个Handler对象,全部的Logger对象都会使用它在同一个文件中写日志信息。你还配置了logger写全部的日志信息,无论信息级别。

最后,你实现了 Task 对象和一个主程序在logfile写入不同的日志信息。你使用了以下的方法:

  • entering():写 FINER 等级的信息,表明方法开始运行
  • exiting(): 写 FINER 等级的信息,表明方法结束运行
  • log(): 写特定级别的信息

更多…

当你使用log类时,你必须考虑2个重要点:

写必需的信息:如果你写过少的信息,那么logger就没有满足它的目的变的不是特别有作用。如果你写过多的信息,那么就会产生很大的日志文件,就不好管理且很难获取必要信息。

对信息使用适当的级别:如果你用高级别写入消息信息(information messages),或者使用低级别来写入报错信息,那么你就会让看logfiles的人很困惑。就会变得很难了解到底发生了什么错误,或者有过多的信息来分析错误的主要原因。

还有很多其他库比 java.util. logging 包提供了更完整的log系统,例如 Log4j 或者 slf4j libraries。但是 java.util.logging 是Java API 的一部分,而且它的全部方法都是 multi-thread safe,所以在并发应用中使用它将不会遇到任何问题。

参见

第六章,并发集: The Using non-blocking thread-safe lists
第六章,并发集: The Using blocking thread-safe lists
第六章,并发集: The Using blocking thread-safe lists ordered by priority
第六章,并发集: The Using thread-safe lists with delayed elements
第六章,并发集: The Using thread-safe navigable maps
第六章,并发集: The Generating concurrent random numbers

文章转自 并发编程网-ifeve.com

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
3天前
|
SQL Oracle 关系型数据库
oracle11g SAP测试机归档日志暴增排查(二)
oracle11g SAP测试机归档日志暴增排查(二)
13 1
|
3天前
|
Oracle 关系型数据库 Shell
oracle11g SAP测试机归档日志暴增排查(一)
oracle11g SAP测试机归档日志暴增排查(一)
11 1
|
3天前
|
Linux 测试技术 Windows
LabVIEW对NI Linux RT应用程序性能进行基准测试
LabVIEW对NI Linux RT应用程序性能进行基准测试
|
5天前
|
Java 测试技术 持续交付
自动化测试框架选型与实战:深入探索与应用
【5月更文挑战第8天】本文探讨了自动化测试框架的选型与实战应用,强调了其在软件质量保障中的重要性。选型原则包括考虑项目需求、技术栈、可扩展性和可维护性,以及社区支持和文档。介绍了Selenium、Appium、JUnit和Pytest等常用框架,并概述了实战应用的步骤,包括明确需求、搭建环境、编写测试用例、执行测试、分析结果、维护代码和持续集成。合理选型与实践能提升测试效率,保障项目成功。
|
6天前
|
JSON 前端开发 JavaScript
快照测试在前端自动化测试中的应用
在前端自动化测试中,快照测试常用于检验组件渲染与布局。
|
7天前
|
监控 安全 数据可视化
中间件应用日志记录和监控
【5月更文挑战第1天】中间件应用日志记录和监控
22 3
中间件应用日志记录和监控
|
8天前
|
敏捷开发 JavaScript 测试技术
深入理解与应用软件测试中的Mock技术
【5月更文挑战第5天】 在现代软件开发过程中,单元测试作为保障代码质量的重要环节,其独立性和可靠性至关重要。Mock技术应运而生,为开发者提供了一种在隔离环境下模拟外部依赖的方法。本文将深入探讨Mock技术的概念、实现方式及其在软件测试中的应用,旨在帮助读者更好地理解和运用这一强大的测试工具,以提升测试效率和软件质量。
|
6天前
|
C++
JNI Log 日志输出
JNI Log 日志输出
14 1
|
6天前
|
存储 运维 大数据
聊聊日志硬扫描,阿里 Log Scan 的设计与实践
泛日志(Log/Trace/Metric)是大数据的重要组成,伴随着每一年业务峰值的新脉冲,日志数据量在快速增长。同时,业务数字化运营、软件可观测性等浪潮又在对日志的存储、计算提出更高的要求。
|
12天前
|
XML Java Maven
Springboot整合与使用log4j2日志框架【详解版】
该文介绍了如何在Spring Boot中切换默认的LogBack日志系统至Log4j2。首先,需要在Maven依赖中排除`spring-boot-starter-logging`并引入`spring-boot-starter-log4j2`。其次,创建`log4j2-spring.xml`配置文件放在`src/main/resources`下,配置包括控制台和文件的日志输出、日志格式和文件切分策略。此外,可通过在不同环境的`application.yml`中指定不同的log4j2配置文件。最后,文章提到通过示例代码解释了日志格式中的各种占位符含义。

热门文章

最新文章