Java 写 Log
. 一个最基本的例子
- 引入loggerg类和logger工厂类
- 声明logger
- 记录日志
下面看一个例子

//1. 引入slf4j接口的Logger和LoggerFactory
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class UserService {
//2. 声明一个Logger,这个是static的方式,我比较习惯这么写。
private final static Logger logger = LoggerFactory.getLogger(UserService.class); public boolean verifyLoginInfo(String userName, String password) {
//3. log it,输出的log信息将会是:"Start to verify User [Justfly]
logger.info("Start to verify User [{}]", userName);
return false;
}
}

- 静态Logger对象相对来说更符合语义,节省CPU,节省内存,不支持注入
- 对象变量Logger支持注入,对于一个JVM中运行的多个引用了同一个类库的应用程序,可以在不同的应用程序中对同个类的Logger进行不同的配置。比如Tomcat上部署了俩个应用,他们都引用了同一个lib。
2. Logger接口的方法
2.1 判断Logger级别是否开启的方法
- public boolean isTraceEnabled();
- public boolean isDebugEnabled();
- public boolean isInfoEnabled();
- public boolean isWarnEnabled();
- public boolean isErrorEnabled();
这 组方法的作用主要是避免没必要的log信息对象的产生,尤其是对于不支持参数化信息的Log框架(Log4j 1, commons-logging)。如下面的例子所示,如果没有加debug级别判断,在Debug级别被禁用的环境(生产环境)中,第二行的代码将没有 必要的产生多个String对象。
if(logger.isDebugEnabled()){
logger.debug("["+resultCount+"]/["+totalCount+"] of users are returned");
}
如果使用了参数信息的方法,在如下代码中,即使没有添加debug级别(第一行)判断,在生产环境中,第二行代码只会生成一个String对象。
if(logger.isDebugEnabled()){
logger.debug("[{}]/[{}] of users in group are returned", resultCount,totalCount);
}
2.2 log信息的方法
2.2.1 方法说明
- public void info(String msg);
无参数的log方法,例子:
logger.info("开始初始化配置文件读取模块");
输出
- public void info(String format, Object arg);
logger.info("开始导入配置文件[{}]","/somePath/config.properties");
输出
- public void info(String format, Object arg1, Object arg2);
支持俩个参数的参数化log方法,例子:
logger.info("开始从配置文件[{}]中读取配置项[{}]的值","/somePath/config.properties","maxSize");
- public void info(String format, Object... arguments);
支持多个参数的参数化log方法,对比上面的俩个方法来说,会多增加构造一个Object[]的开销。例子:
logger.info("在配置文件[{}]中读取到配置项[{}]的值为[{}]","/somePath/config.properties","maxSize", 5);
- public void info(String msg, Throwable t);
logger.info("读取配置文件时出现异常",new FileNotFoundException("File not exists"));
输出
java.io.FileNotFoundException: File not exists
at cn.justfly.training.logging.service.UserServiceTest.testLogResult(UserServiceTest.java:31) ~[test-classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]
参数化说明
2.2.2 如何Log Exception
2.2.2.1 把Exception作为Log方法的最后一个参数
上面讲的参数化Log方法的中的最后一个参数如果是一个Exception类型的对象的时候,logback将会打印该Exception的StackTrace信息。看下面的这个例子:
logger.info("读取配置文件[{}]时出错。","/somePath/config.properties",new FileNotFoundException("File not exists"));
java.io.FileNotFoundException: File not exists
at cn.justfly.training.logging.service.UserServiceTest.testLogResult(UserServiceTest.java:30) [test-classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) [junit.jar:na]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit.jar:na]
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) [junit.jar:na]
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit.jar:na]
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) [junit.jar:na]
2.2.2.2 Exception不会替换log信息中的参数
另外需要注意的时,该Exception不会作为参数化内容中的参数进行替换。比如下面的代码:
logger.info("读取配置文件[{}]时出错。异常为[{}]","/somePath/config.properties",new FileNotFoundException("File not exists"));
java.io.FileNotFoundException: File not exists
at cn.justfly.training.logging.service.UserServiceTest.testLogResult(UserServiceTest.java:30) [test-classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]
2.2.2.3 参数化Exception
- 把Exception的toString()方法的返回值作为参数
logger.info("读取配置文件[{}]时出错。异常为[{}]","/somePath/config.properties",new FileNotFoundException("File not exists").toString());
- 不要让Exception成为最后一个参数
logger.info("读取参数[{}]的时候出错:[{}], 请检查你的配置文件[{}]","maxSize",new FileNotFoundException("File not exists"),"/somePath/config.properties");
3. Log什么
3.1 如何使用不同级别的Log
3.1.1 用户级别
3.1.1.1 Error
- 影响到程序正常运行、当前请求正常运行的异常情况,例如:
- 打开配置文件失败
- 第三方应用网络连接异常
- SQLException
- 不应该出现的情况,例如:
- 某个Service方法返回的List里面应该有元素的时候缺获得一个空List
- 做字符转换的时候居然报错说没有GBK字符集
3.1.1.2 Warn
- 不应该出现但是不影响程序、当前请求正常运行的异常情况,例如:
- 有容错机制的时候出现的错误情况
- 找不到配置文件,但是系统能自动创建配置文件
- 即将接近临界值的时候,例如:
- 缓存池占用达到警告线
3.1.1.3 Info
- 系统运行信息
- Service方法的出入口
- 主要逻辑中的分步骤
- 外部接口部分
- 客户端请求参数和返回给客户端的结果
- 调用第三方时的调用参数和调用结果
3.1.2 开发级别
3.1.2.1 Debug
- 用于记录程序变量,例如:
- 多次迭代中的变量
- 用于替代代码中的注释

//2. 获取用户休假情况

//3. 计算用户应得薪资


logger.debug("开始获取员工[{}] [{}]年基本薪资",employee,year);
logger.debug("获取员工[{}] [{}]年的基本薪资为[{}]",employee,year,basicSalary);
logger.debug("开始获取员工[{}] [{}]年[{}]月休假情况",employee,year,month);
logger.debug("员工[{}][{}]年[{}]月年假/病假/事假为[{}]/[{}]/[{}]",employee,year,month,annualLeaveDays,sickLeaveDays,noPayLeaveDays);
logger.debug("开始计算员工[{}][{}]年[{}]月应得薪资",employee,year,month);
logger.debug("员工[{}] [{}]年[{}]月应得薪资为[{}]",employee,year,month,actualSalary);

3.1.2.2 Trace
3.2 Log中的要点
3.2.1 Log上下文
- "开始导入配置文件"
- "开始导入配置文件[/etc/myService/config.properties]"
3.2.2 考虑Log的读者
- "开始执行getUserInfo 方法,用户名[jimmy]"
- "开始获取用户信息,用户名[jimmy]"
- "无法解析参数[12 03, 2013],birthDay参数需要符合格式[yyyy-MM-dd]"
3.2.3 Log中的变量用[]与普通文本区分开来
- 在你阅读Log的时候容易捕捉到有用的信息
- 在使用工具分析Log的时候可以更方便抓取
- 在一些情况下不容易混淆
- "获取用户lj12月份发邮件记录数"
- "获取用户[lj1][2]月份发邮件记录数"
3.2.4 Error或者Warn级别中碰到Exception的情况尽量log 完整的异常信息
- 你是在做什么事情的时候出错了
- 你是在用什么数据做这个事情的时候出错了
- 出错的信息是什么
- log.error("获取用户[{}]的用户信息时出错",userName,ex);
- log.error("获取用户[{}]的用户信息时报错,错误信息:[{}]",userName,ex.getMessage());
- log.error("获取用户信息时出错");
3.2.5 对于Exception,要每次都Log StackTrace吗?
在一些Exception处理机制中,我们会每层或者每个Service对应一个RuntimeException类,并把他们抛出去,留给最外层的异常处理层处理。典型代码如下:

try{
}catch(Exception ex){
String errorMessage=String.format("Error while reading information of user [%s]",userName);
logger.error(errorMessage,ex);
throw new UserServiceException(errorMessage,ex);
}

- 这个信息很重要,我不确认再往上的异常处理层中是否会正常的把它的StackTrace打印出来。
- 如果这个异常信息在往上传递的过程中被多次包装,到了最外层打印StackTrace的时候最底层的真正有用的出错原因有可能不会被打印出来。
- 如果有人改变了LogbackException打印的配置,使得不能完全打印的时候,这个信息可能就丢了。
- 就算重复了又怎么样?都Error了都Warning了还省那么一点空间吗?
Java 写 Log的更多相关文章
- kafka集群搭建和使用Java写kafka生产者消费者
1 kafka集群搭建 1.zookeeper集群 搭建在110, 111,112 2.kafka使用3个节点110, 111,112 修改配置文件config/server.properties ...
- Java的Log系统介绍和切换(转)
Java的log系统比较繁杂.在这里梳理一下.本文只涉及log系统介绍和处理log系统之间的切换.不涉及如何配置和使用. 具体的log系统 Log4j:准确的说是log4j 1.x版.是之前使用最广泛 ...
- Flume学习应用:Java写日志数据到MongoDB
概述 Windows平台:Java写日志到Flume,Flume最终把日志写到MongoDB. 系统环境 操作系统:win7 64 JDK:1.6.0_43 资源下载 Maven:3.3.3下载.安装 ...
- 关于Quartz.NET作业调度框架的一点小小的封装,实现伪AOP写LOG功能
Quartz.NET是一个非常强大的作业调度框架,适用于各种定时执行的业务处理等,类似于WINDOWS自带的任务计划程序,其中运用Cron表达式来实现各种定时触发条件是我认为最为惊喜的地方. Quar ...
- 基于.Net Framework 4.0 Web API开发(3):ASP.NET Web APIs 异常的统一处理Attribute 和统一写Log 的Attribute的实现
概述: ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是项目,总有异常发生,本节就来谈谈API的异常 ...
- Java写的斗地主游戏源码
源码下载在最后 我们的前年的课设要求做一个斗地主程序,当时正在愁如何做界面,当时刚好在学习C#,于是就用C#完成了这个程序.一方面,当时我C#功底还很差(其实现在也不怎么样),很多地方用了“笨办法”, ...
- [Android] 解析android framework下利用app_process来调用java写的命令及示例
reference to :http://bbs.9ria.com/thread-253058-1-1.html 在android SDK的framework/base/cmds目录下了,有不少目录, ...
- hdu 1063(java写高精度)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1063 思路:最近刚学了java,然后就迫不及待想试试java写大数的好处了,呵呵,果然是很方便啊! i ...
- java写的web服务器
经常用Tomcat,不知道的以为Tomcat很牛,其实Tomcat就是用java写的,Tomcat对jsp的支持做的很好,那么今天我们用java来写一个web服务器 //首先得到一个server, S ...
随机推荐
- Linux下PAM模块学习总结
在Linux中执行有些程序时,这些程序在执行前首先要对启动它的用户进行认证,符合一定的要求之后才允许执行,例如login, su等.在Linux中进行身份或是状态的验证程序是由PAM来进行的,PAM( ...
- 浅谈Google Chrome浏览器(操作篇)(上)
开篇概述 在上篇博客中详解Google Chrome浏览器(理论篇)一文中,主要讲解了Chrome 搜索引擎使用.Chrome安装和基本操作.Chrome 基本架构.多线程等原理性问题,这篇将重点讲解 ...
- 以太坊工作原理之txpool详解
txpool详解 交易池txpool作为区块链系统的重要组成部分,对系统的安全性和稳定性具有重要作用.功能可归纳为:交易缓存.交易验证和交易过滤. 基本介绍 交易分类和缓存 txpool主要包含两个重 ...
- DS控件库 DS开放式下拉列表
在一些场合中,需要使用组合式下拉列表控件,比如带treeivew的combobox,但是代码较多,使用不便.为此,本人制作了一个超级易用的DS开放式下拉列表. 以下演示使用过程. Private Su ...
- MySQL 笔记整理(18) --为什么这些SQL语句逻辑相同,性能却差异巨大?
笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 18) --为什么这些SQL语句逻辑相同,性能却差异巨大? 本篇我们以三 ...
- 使用curl制作简易百度搜索
这几天研究了一下php中的curl类库,做了一个简单的百度搜索,先上代码 <div style="width:200px;height:100px;"> <div ...
- Java 工厂模式(一)— 抽象工厂(Abstract Factory)模式
一.抽象工厂模式介绍: 1.什么是抽象工厂模式: 抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态,抽象工厂模式向客户端提供一个接口,使得客户端在不知道具体产品的情类型的情况下,创建 ...
- MySQL数据连表查询思路
我们在网站开发中,涉及MySQL数据库查询时,常常需要将两个表或多个表联合起来进行查询数据,这就用到了MySQL中的JOIN函数. JOIN函数有三种,分别是: LEFT JOIN 左连接查询: 查 ...
- 【升鲜宝】生鲜配送管理系统_升鲜宝 V2.0 按客户商品分类分开打印配送与按客户商品分类导出相关订单商品相关说明(一)
[升鲜宝]生鲜配送管理系统_升鲜宝 V2.0 按[客户]的商品分类分开打印(配送单)与按[客户]商品分类[对账单]导出相关销售订单商品功能相关说明(一) 业务场景概述与痛点 1.中小学校食堂的客户,每 ...
- Android为TV端助力:intent传递消息
我们都知道一个activity向另外一个activity传递消息可以用intent来传递 现在需求如下,一个不断接收消息服务的service,一个收到消息进行处理的activity service第一 ...