zoukankan      html  css  js  c++  java
  • java日志

    一、日志级别的选择:Debug、Info、Warn、Error还是Fatal

    软件中总免不了要使用诸如 Log4net, Log4j, Tracer 等东东来写日志,不管用什么,这些东东大多是大同小异的,一般都提供了这样5个日志级别:
        × Debug
        × Info
        × Warn
        × Error
        × Fatal
            一个等级比一个高,但是在具体开发中,关于应该如何选择适应的等级,却没有找到好的文章进行说明。记录一下自己的一些看法,以便日后使用吧。

    === Debug ===
            这个级别最低的东东,一般的来说,在系统实际运行过程中,一般都是不输出的。


            因此这个级别的信息,可以随意的使用,任何觉得有利于在调试时更详细的了解系统运行状态的东东,比如变量的值等等,都输出来看看也无妨。


            当然,在每一个 Debug 调用之前,一定要加上 If 判断。

    === Info ===
            这个应该用来反馈系统的当前状态给最终用户的,所以,在这里输出的信息,应该对最终用户具有实际意义,也就是最终用户要能够看得明白是什么意思才行。


            从某种角度上说,Info 输出的信息可以看作是软件产品的一部分(就像那些交互界面上的文字一样),所以需要谨慎对待,不可随便。

    === Warn、Error、Fatal ===
            警告、错误、严重错误,这三者应该都在系统运行时检测到了一个不正常的状态,他们之间的区别,要区分还真不是那么简单的事情。我大致是这样区分的:


            所谓警告,应该是这个时候进行一些修复性的工作,应该还可以把系统恢复到正常状态中来,系统应该可以继续运行下去。


            所谓错误,就是说可以进行一些修复性的工作,但无法确定系统会正常的工作下去,系统在以后的某个阶段,很可能会因为当前的这个问题,导致一个无法修复的错误(例如宕机),但也可能一直工作到停止也不出现严重问题。

            所谓Fatal,那就是相当严重的了,可以肯定这种错误已经无法修复,并且如果系统继续运行下去的话,可以肯定必然会越来越乱。这时候采取的最好的措施不是试图将系统状态恢复到正常,而是尽可能地保留系统有效数据并停止运行。

            也就是说,选择 Warn、Error、Fatal 中的具体哪一个,是根据当前的这个问题对以后可能产生的影响而定的,如果对以后基本没什么影响,则警告之,如果肯定是以后要出严重问题的了,则Fatal之,拿不准会怎么样,则 Error 之。

    二、打印异常的堆栈信息

    让logger语句记录异常的堆栈信息
    前言
    补个日志。

    其实CSND也有类似的文章,但是我也有思考过,所以我也想记录一下。我们直接用logger.info("异常信息为:"+e)或者logger.info(e.getMessage())只能记录到异常的描述信息,却没有其异常具体发生在哪一行代码。这样即使通过日志发现出现了异常,也没法马上定位问题。因此就催生了一个想法,是否能像在idea本地跑程序时出现未捕获的异常时,控制台能打印出完整的错误堆栈信息,把这个信息记录到logger语句中。

    描述
    写接口时,为了方便后期查看日志定位问题,我对service的logger日志进行了改造,将所有的logger语句拼接成一条记录,然后再打印出来。因此会在service层最外层使用try catch finally。这样一个请求的日志就能统一出现,不会由于多个请求导致的日志穿插记录。日志如:

    [2018-06-26 17:09:54.038] -- [http-nio-8079-exec-27] -- [INFO] -- [OrderServiceImpl.java:513 >>>> Method = query] -- [Content =
    ********【1121订单查询】标识:useruuid==d86a732d-2da6-11e8-xxx-xxxx,source==1,phone==135705xxxxx,orderNo==201806260000xxxxx
    ********【1121订单查询】入参:com.uroad.etc.dto.OrderInput@6ab68cb3[useruuid=d86a732d-2da6-11e8-xxx-xxxx,orderNo=2018062600xxxx,source=1]
    ********【1121订单查询】请求:request decode data:1121110802CCF5B968C014E702xxxxx
    ********【1121订单查询】响应:response deceode data:90001A4B0D01060F103136303832323xxxxxx
    ********【1121订单查询】updateTradStateAndPushMsgByCardNo 更新表结果:1,cardNo:1608227140xxx
    ********【1121订单查询】出参:com.uroad.etc.dto.OrderOutput@42879e4b[tradeText=2018-06-26 17:09:31,tradeDate=2018xxx,tradTime=170xxx,orderNo=201806260000003xxx,tradMoney=1,tradState=3,serialNo=<null>,cardNo=160822714xxx,terminalNo=<null>,billState=<null>,orderType=1,cardType=<null>,plateNo=<null>,payChannel=6]]
    1
    2
    3
    4
    5
    6
    7
    但这样做有个不好的地方,就是当出现异常的时候,虽然捕获了,也打印了异常信息,但是异常信息不能准确定位错误信息,会像这样:

    [2018-07-31 21:41:04] -- [main] -- [INFO] -- [TestException.java:17 >>>> Method = main] -- [Content =
    异常信息为:java.lang.NullPointerException]
    1
    2
    假如service层代码简单,那么可以很快就定位出出现异常的地方。可是假如service层稍稍复杂些,代码稍稍多一些,就没法迅速的找处是哪个地方出现异常。

    像我们在本地测试的时候,当出现了意料之外的运行时异常,控制台是能打印出完整的错误信息,像这样:

    public static void main(String[] args) {
    String s = "1";
    if(s.equals("1")){
    s=null;
    }
    s.equals("1");
    }
    1
    2
    3
    4
    5
    6
    7
    控制台是能打印出完整信息的:

    Exception in thread "main" java.lang.NullPointerException
    at TestException.main(TestException.java:14)
    1
    2
    这样我们就能一下子就知道错误是在TestException的第14行,即s.equals("1)这里,那我们就能推出是对象s是空对象。

    但是由于我在service层的最外层使用了try catch,即我的代码是像这样的:

    public static void main(String[] args) {
    try {
    String s = "1";
    if(s.equals("1")){
    s=null;
    }
    s.equals("1");
    }catch (Exception e){
    logger.info("异常信息为:" + e);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    这样,当出现异常,异常信息为:

    [2018-07-31 21:46:04] -- [main] -- [INFO] -- [TestException.java:17 >>>> Method = main] -- [Content =
    异常信息为:java.lang.NullPointerException]
    1
    2
    这样,只能知道是第17行的logger语句打印的信息。但是正如我前面所说我在service层使用了try catch finally来处理日志,所以只有一个logger语句,所以没法知道错误发生在哪里。

    解决方法
    于是思考,是否有这么一个方法,可以打印出完整的堆栈信息,最终还是在网上找到了:
    参考文章:https://blog.csdn.net/wwsscc168/article/details/51837662

    public static String toStackTrace(Exception e)
    {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);

    try
    {
    e.printStackTrace(pw);
    return sw.toString();
    }
    catch(Exception e1)
    {
    return "";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    只是,不知道这样会不会很占内存。很占空间。

    解决方法2
    这样也能打印出错误位置:logger.info(e.getMessage(),e);

    输出如:

    [2018-07-31 21:52:57] -- [main] -- [INFO] -- [TestException.java:17 >>>> Method = main] -- [Content =
    null]
    java.lang.NullPointerException: null
    at TestException.main(TestException.java:15)
    1
    2
    3
    4
    5
    这样也行:

    logger.info("出现异常啦:",e);
    1
    但是这样就必须得一个单独的logger语句。

    可以通过线程号去追踪。。。

    最优解决方法
    找到了个新方法,不需要改JVM配置,也不需要用Write流:

    public static String logClzInfo(Exception e) {
    StringBuffer sb = new StringBuffer();
    sb.append(e.getClass() + " " + e.getMessage() + " ");
    StackTraceElement[] stackTraceElement = e.getStackTrace();
    for (StackTraceElement traceElement : stackTraceElement) {
    sb.append(" at " + traceElement + " ");
    }
    return sb.toString();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    这样,就能在catch中通过参数e获取到完整的错误信息了。这样一来,以后出了问题,通过日志,就能一下找到问题所在了。

    原文:https://blog.csdn.net/weixin_30531261/article/details/81436020

    3.

    在Java中,通常情况下,需要将异常堆栈信息输出到日志中,这样便于纠错及修正Bug,而多数情况下,大家最常用的是使用e.printStackTrace()直接打印堆栈信息完事,这并不是值的推荐的做法。

    1. 当出现异常时,调用e.printStackTrace();其实相当于什么都没做,同时也不会把异常信息输出到日志文件中

    2. 使用log.error(e.getMessage());只能够输出异常信息,但是并不包括异常堆栈,所以无法追踪出错的源点

    3. 使用log.error(e);除了输出异常信息外,还能输出异常类型,但是同样不包括异常堆栈,该方法doc说明为:Logs a message object with the ERROR level.显然并不会记录异常堆栈信息

    4. 当然也可以自己手动写个工具类,来挨个输出e.getStackTrace();获得的堆栈信息,显然繁琐麻烦

    5. 其实在log4j中只需要这样调用,就可以获得异常及堆栈信息log.error(Object var1, Throwable var2);,该方法doc说明为:Logs a message at the ERROR level including the stack trace of the Throwable t passed as parameter.

    原因分析:

    有时候logger.error不能完全地打印出网站的错误堆栈信息,只能打印这个错误是一个什么错误。

    为什么?

    看Logger.error源码

    public void error(String msg, Throwable t);

    public void error(String msg);

    如果只传一个参数e进去,那么e就被认为是String类型(会自动调toString()方法把Exception转成String),而不是Exception类型。

    如果想打印堆栈信息,那么必须传两个或以上参数,实际上就是为了调用public void error(String msg, Throwable t);

    所以我们的写法可以是:

    Logger.error(“xxx出错”,e); //第二个参数是e

    而不是:

    Logger.error(“xxx出错:”+e) 或 logger.error(e) 或logger.error(e.getMessage);

  • 相关阅读:
    【动画技巧】在Flash中自定义鼠标外观
    【动画技巧】GIF动画转SWF小技巧
    SQL Server 2008空间数据应用系列十一:提取MapInfo地图数据中的空间数据解决方案
    SQL Server 2008空间数据应用系列十:使用存储过程生成GeoRSS聚合空间信息
    jQuery的模板与数据绑定插件
    ASP.NET MVC 入门5、View与ViewData
    一个jQuery写的虚拟键盘
    ASP.NET MVC 入门4、Controller与Action
    使用XML文件来动态配置ASP.NET MVC的Route规则
    ASP.NET MVC 入门9、Action Filter 与 内置的Filter实现(介绍)
  • 原文地址:https://www.cnblogs.com/haoyul/p/10819371.html
Copyright © 2011-2022 走看看