1.日志的概念

  在调试有问题的代码时,经常需要插入一些System.out.println方法来观察程序运行的操作过程。但是,一旦发现了问题并且解决了问题,就需要将这些System.out.println语句从代码中删除或者注释。如果接下来又出现了问题,就还要再插入几个System.out.println方法。日志API可以很好地解决这个问题。

  日志API的优点:

  • 可以很容易地取消全部日志记录,或者仅仅取消某个级别的日志,而且打开和关闭这个操作也很容易。
  • 可以很简单地禁止日志的输出,因此,将这些日志代码留在程序中的开销很小。
  • 日志记录器和处理器都可以对记录进行过滤。过滤器可以根据过滤实现其指定的标准丢弃无用的记录项。
  • 日志记录可以采用不同的方式格式化,例如,纯文本或XML。
  • 应用程序可以使用多个日志记录器,它们使用类似包名的具有层次结构的名字。
  • 在默认情况下,日志系统的配置由配置文件控制。如果需要的话,应用程序可以替换配置文件。

  

  2.基本日志

  使用全局日志记录器(global logger)并调用info方法可以输出指定的信息。

  输出有两行信息,第一行是调用日志方法的时间戳,包名,类名,方法名,第二行是用户指定的info信息。

package packageName;

import java.util.logging.Logger;

public class ClassName {

    public static void main(String[] args) {
int x = 100;
Logger.getGlobal().info("x的值为: " + x);
}
} 输出:
七月 20, 2018 9:11:20 上午 packageName.ClassName main
信息: x的值为: 100

  同时,使用其setLevel方法可以很容易地取消日志的显示。

package packageName;

import java.util.logging.Level;
import java.util.logging.Logger; public class ClassName { public static void main(String[] args) {
int x = 100;
Logger.getGlobal().setLevel(Level.OFF);
Logger.getGlobal().info("x的值为: " + x);
}
} 输出:

  全局日志记录就是所有的日志都记录到一个日志记录器中:

package packageName;

import java.util.logging.Logger;

public class ClassName {

    public static void main(String[] args) {
int x = 100;
Logger.getGlobal().info("x的值为: " + x);
int y = 101;
Logger.getGlobal().info("y的值为: " + y);
}
} 输出:
七月 20, 2018 9:32:16 上午 packageName.ClassName main
信息: x的值为: 100
七月 20, 2018 9:32:16 上午 packageName.ClassName main
信息: y的值为: 101

  3.高级日志

  在一个专业的应用程序中,不要把所有的日志都记录到一个全局日志记录器中,而是可以自定义多个记录器。

  使用Logger.getLogger方法来生成指定记录器名称的记录器,例如,下面的语句定义了两个日志记录器,日志记录器的名字之间有着很强的关联性,iplab就是school的子记录器。未被任何变量引用的日志记录器可能会被垃圾回收,为了防止这种情况,用一个静态变量存储日志记录器的引用。

private static Logger logger = Logger.getLogger("com.school");
private static Logger logger = Logger.getLogger("com.school.iplab");

  如果对父记录器设置了日志级别,那么它的子记录器也会继承这个级别,级别一共有七种,SEVERE、WARNING、INFO、CONFIFG、FINE、FINER、FINEST在默认的情况下,只记录前三个级别,如果设置FINE,则FINE和更高的级别都可以记录下来。另外,还可以使用Level.ALL开启所有级别,以及Level.OFF关闭所有级别。

logger.setLevel(Level.FINE);

  前面的info就是制定了日志级别,将记录信息指定成不同的级别可以使用下面的方法

logger.warning(message);
logger.fine(message);
logger.log(Level.FINE, message);

  例如:由于main方法本身就是静态方法,所以logger就已经是静态的了。

package packageName;

import java.util.logging.Logger;

public class ClassName {

    public static void main(String[] args) {

        Logger logger = Logger.getLogger("com.school.iplab");
int x = 100;
logger.warning("The value of x is " + x);
}
} 输出:
七月 20, 2018 9:56:01 上午 packageName.ClassName main
警告: The value of x is 100

  默认的日志记录将显示包含日志调用的类名和方法名,为了得到调用类和方法的确切位置,可以使用logp方法,指定日志记录器所在的包名和方法名以及记录信息。

package packageName;

import java.util.logging.Level;
import java.util.logging.Logger; public class ClassName { public static void main(String[] args) { Logger logger = Logger.getLogger("com.school.iplab");
int x = 100;
logger.logp(Level.INFO, "包名", "方法名", "记录信息x=" + x);
}
} 输出:
七月 20, 2018 10:06:49 上午 包名 方法名
信息: 记录信息x=100

  还可以跟踪执行流的方法,例如:entering方法记录一个进入read方法的日志,exiting方法记录一个退出read方法的日志。

    int read(String file, String pattern) {
Logger logger = Logger.getLogger("com.school.iplab");
logger.entering("packageName.ClassName", "read", new Object[] {file, pattern});
   ...
logger.exiting("packageName.ClassName", "read", count);
return count; }

  日志常见的用途值记录那些不可预料的异常,典型的用法是:

  • 在try-catch语句块中,用来记录捕捉到的异常对象的日志。
  • 在if语句中,用来记录抛出的异常对象的日志。
         try
{
      ...
}
catch (IOException e)
{
Logger.getLogger("com.horstmann.corejava").log(Level.SEVERE,
"Can't create log file handler", e);
}       if(...)
{
IOException exception = new IOException("...");
logger.throwing("类名", "方法名", exception);
throw exception;
}

  4.修改日志管理器的配置

  可以在jre/lib/logging.properties中修改配置文件,使得指定自己的日志记录级别:

com.xyz.foo.level = SEVERE

  5.日志处理器

  (1)ConsoleHandler处理器

  在默认的情况下,日志记录器将记录发送到ConsoleHandler日志处理器中,并由它输出到System.err流中。另外,日志记录器还会将记录发送到父处理器中。与日志记录器一样,日志处理器也有日志记录级别,对于一个要被记录的日志,它的日志记录级别必须高于日志记录器和日志处理器的阈值。

  配置文件中日志处理器的日志级别为:

java.util.logging.ConsoleHandler.level = INFO

  要想记录比INFO低级别的日志,例如FINE级别的日志,就必须要修改配置文件的默认日志记录器级别和处理器级别,除了这个方法,还可以自己定义自己的处理器:步骤就是,首先创建一个日志记录器logger并设置日志记录器的记录级别,然后由于原始日志记录器将会把所有等于或高于INFO级别的记录发送到控制台,为了不让原始日志记录器发送而只让自己定义的日志记录器发送记录到控制台,调用setUseParentHandlers方法并传递参数false,然后创建自己的日志处理器,并将处理器的处理级别设置为FINE,最后将日志记录器发送到定义的日志处理器。

package packageName;

import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger; public class ClassName {     public static void main(String[] args) {
        Logger logger = Logger.getLogger("com.school.iplab");
        logger.info("info0");
        logger.fine("fine0");
        logger.setLevel(Level.FINE);
        logger.setUseParentHandlers(false);
        Handler handler = new ConsoleHandler();
        handler.setLevel(Level.FINE);
        logger.addHandler(handler);
        logger.info("info1");
        logger.fine("fine1");
    }
} 输出:
七月 20, 2018 11:08:34 上午 packageName.ClassName main
信息: info0
七月 20, 2018 11:08:34 上午 packageName.ClassName main
信息: info1
七月 20, 2018 11:08:34 上午 packageName.ClassName main
详细: fine1

  (2)FileHandler处理器用来本地化

package packageName;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger; public class ClassName { public static void main(String[] args) throws SecurityException, IOException {
Logger logger = Logger.getLogger("com.school.iplab");
logger.info("info0");
logger.fine("fine0");
logger.setLevel(Level.FINE);
logger.setUseParentHandlers(false);
Handler handler = new FileHandler("myapp.log");
handler.setLevel(Level.FINE);
logger.addHandler(handler);
logger.info("info1");
logger.fine("fine1");
}
}

  在项目的文件夹下会生成一个myapp.log文件,文件内容是XML格式的:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2018-07-20T11:23:21</date>
<millis>1532057001808</millis>
<sequence>1</sequence>
<logger>com.school.iplab</logger>
<level>INFO</level>
<class>packageName.ClassName</class>
<method>main</method>
<thread>1</thread>
<message>info1</message>
</record>
<record>
<date>2018-07-20T11:23:21</date>
<millis>1532057001808</millis>
<sequence>2</sequence>
<logger>com.school.iplab</logger>
<level>FINE</level>
<class>packageName.ClassName</class>
<method>main</method>
<thread>1</thread>
<message>fine1</message>
</record>
</log>

  6.过滤器

  在默认情况下,过滤器根据日志记录的级别进行过滤。每个日志记录器和处理器都可以有一个可选的过滤器来完成附加的过滤。

  7.格式化器

  ConsoleHandler类和FileHandler类可以生成文本和XML格式的日志记录。但是也可以自定义格式。继承Formatter类并使用setFormatter方法将格式化器安装到处理器中即可。

  8.日志总结

  (1)在创建应用程序的日志记录器时,最好和主程序的包名一致,为了方便起见,最好设置成静态域:

private static Logger logger = Logger.getLogger(包名);

  (2)默认的日志配置文件将级别等于或高于INFO级别的所有日志消息输出到控制台,用户可以覆盖默认的配置文件,但是最好还是安装一个更加适合的自己定义的日志处理器,下面的代码确保将所有的消息记录到应用程序特定的文件中。

      if (System.getProperty("java.util.logging.config.class") == null
&& System.getProperty("java.util.logging.config.file") == null)
{
try
{
Logger.getLogger("com.horstmann.corejava").setLevel(Level.ALL);
final int LOG_ROTATION_COUNT = 10;
Handler handler = new FileHandler("%h/LoggingImageViewer.log", 0, LOG_ROTATION_COUNT);
Logger.getLogger("com.horstmann.corejava").addHandler(handler);
}
catch (IOException e)
{
Logger.getLogger("com.horstmann.corejava").log(Level.SEVERE,
"Can't create log file handler", e);
}
}

  (3)必须牢记的是,如果没有修改默认配置,那么所有级别为INFO、WARNING和SEVERE的消息都将被记录,因此最好只将对程序用户有意义的消息设置为这几个级别,将程序员想要的日志记录,设置为低级别的FINE是一个很好的选择。

  (4)还要牢记的是,日志最大的用处是来记录异常,可以记录捕获的异常对象和抛出的异常对象。

Java基础(十七)日志(Log)的更多相关文章

  1. java基础(十七)----- 浅谈Java中的深拷贝和浅拷贝 —— 面试必问

    假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...

  2. java基础学习日志---File方法分析

    package FunDemo; import java.io.File; import java.io.IOException; import java.util.Arrays; public cl ...

  3. java基础学习日志--String、StringBuffer方法案例

    package StringDemo; import java.util.Arrays; /* * 常用String.StringBufer类的方法 */ public class Demo1 { p ...

  4. java基础学习日志--异常案例

    package test7; public class InvalidScroreException extends Exception { public InvalidScroreException ...

  5. Java基础加强-日志

    /*日志*/ 从功能上来说,日志API本身所需求的功能非常简单,只需要能够记录一段文本即可 API的使用者在需要记录时,根据当前的上下文信息构造出相应的文本信息,调用API完成记录.一般来说,日志AP ...

  6. java基础学习日志--Stirng内存案例

    案例一: public class test1 { public static void mb_swap(String Str1,String Str2) { String temp=Str1; St ...

  7. 《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)

    1.简介 前面宏哥一连几篇介绍如何通过开源jar包Log4j.jar.log4j2.jar和logback实现日志文件输出,Log4j和logback确实很强大,能生成三种日志文件,一种是保存到磁盘的 ...

  8. Java基础学习总结(40)——Java程序员最常用的8个Java日志框架

    作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...

  9. 第二十七节:Java基础面向对象-静态,单例模式,继承详情知识点

    前言 Java基础面向对象-静态,单例模式,继承详情知识点.静态-static关键字,static变量,静态代码块,代码块(不加静态),对象创建过程,单例模式,继承. 静态-static关键字 // ...

  10. 7.20实习培训日志-Java基础程序设计结构

    Java基础程序设计结构 在 Math 类中,为了达到最快的性能,所有的方法都使用计算机浮点单元中的例程,如果得到一个完全可预测的结果比运行速度更重要的话,那么就应该使用StrictMath类,它使用 ...

随机推荐

  1. Find the Multiple POJ-1426

    题目链接:Find the Multiple 题目大意 找出一个只由0和1组成的能整除n的数. 思路 所有由0和1组成的数可以看作是某个只由0.1组成的数a经过以下两种变化得到 1.a * 10 2. ...

  2. (七十八)c#Winform自定义控件-倒影组件

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  3. 【PCIE-1】---Pcie基本概念普及(扫盲篇--巨适合新手)

    PCIE由早期得PCI扩展衍生而来并且对兼容PCI,两者得主要区别在于并行到串行得切换,且速率更快.目前主板上越来越多得设备都挂载到PCI总线下面,甚至部分硬盘也会挂载PCI总线下面,可见PCIE得应 ...

  4. Android self_adaption of screen

    以下是Demo首页的预览图 demo下载:http://www.eoeandroid.com/forum.php?mod=attachment&aid=NjE0Njh8ZTIyZDA2M2N8 ...

  5. 快学Scala 第一课 (变量,类型,操作符)

    Scala 用val定义常量,用var定义变量. 常量重新赋值就会报错. 变量没有问题. 注意:我们不需要给出值或者变量的类型,scala初始化表达式会自己推断出来.当然我们也可以指定类型. 多个值和 ...

  6. python 3.7 使用MP3play 模块

    因工作需要,做了一个QQ机器人语音播报程序.主要思路 是通过 酷Q 获取QQ消息取出有效信息. 根据信息在百度AI上合成语音,然后本地播放. 在播放语音的时候用了好几个模块  pygame .pyme ...

  7. Java-Thread00之多线程知识准备

    ------ ![](https://img2018.cnblogs.com/blog/1822322/201910/1822322-20191012170014292-1661101986.jpg) ...

  8. 04、JDBC范例

    范例:JDBC查询 package com.hsp; import java.sql.Connection; import java.sql.DriverManager; import java.sq ...

  9. 某CTF平台一道PHP代码注入

    这道题以前做过但是没有好好的总结下来.今天又做了一下,于是特地记录于此. 首先就是针对源码进行审计: 关于create_function这个函数可以看一下这个:http://www.php.cn/ph ...

  10. A Deep Neural Network Approach To Speech Bandwidth Expansion

    题名:一种用于语音带宽扩展的深度神经网络方法 作者:Kehuang Li:Chin-Hui Lee 2015年出来的 摘要 本文提出了一种基于深度神经网络(DNN)的语音带宽扩展(BWE)方法.利用对 ...