`
deepinmind
  • 浏览: 450791 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41551
社区版块
存档分类
最新评论

日志打印的5点建议

阅读更多
最近我们介绍了几款日志分析的工具,比如Scribe和LogStash这类的开源项目,以及Splunk这样的企业级工具,还有像SumoLogic和PaperTrail这样的托管服务。你可以使用这些工具从海量的日志数据提取到一些有价值的信息。

不过还有一件事它们是帮不了你的。它们都依赖于你实际输出到日志文件里面的数据。日志数据保质保量的重任就落到你肩上了。因此万一情况不妙,你又得在日志文件不全的情况下自己去调试代码,那估计你只好赶紧把原先订好的晚餐取消掉了。

为了减少出现类似的情况,我这里想分享5点日志打印的心得,希望能对你有所帮助:

1. 线程名

就像Ringo一样,线程名应该是Java里最被低估的功能之一了。因为其实它的表述性很强。那又怎样?就像我们的名字一样,我们会给它赋予一个含义。

线程名最有用的时候应该就是多线程的情况下了。许多日志框架都会记录当前方法调用所在线程的名字。不幸的是,一般看起来都是这样的:“http-nio-8080-exec-3″,这是线程池或者容器自动分配的线程名。

我经常听到有谣传称线程名是不可变的。当然不是。线程名就是你日志中最优质的不动产,你得确保自己能正确的使用它们。通常给它赋值会带上上下文的详细信息,比如说Servlet或者任务的名字之类的,以及一些动态的上下文信息比如用户ID。

这么做的话,你的代码看起来应该是这样的:

Thread.currentThread().setName(ProcessTask.class.getName() + “: “+ message.getID);


更高级的做法是引入一个ThreadLocal的变量,然后配置一个appender,自动把里面的信息输出到日志中。

当多个线程同时在往文件中写入日志而你需要关注其中某个线程的时候,这个功能尤其有用。如果你在一个分布式或者SOA环境中运行的话,这么做还会有一个额外的好处,下面我们很快就会看到。

2. 分布式标识符

在SOA或者消息驱动的架构中,某个任务的执行可能会涉及到多台机器。这种架构下如果出了错要进行处理的话,要想知道到底发生了什么,这里所牵涉到的相关机器以及它们的状态就显得至关重要。很多日志分析器只是帮你把这些日志收集起来,它们假设你已经有一个唯一的标志符,可以用它来进行过滤。

从设计的角度来看,这意味着系统中每一个入站操作都需要有一个唯一的ID,处理过程中会一直携带着这个ID直到处理结束。这里如果使用持久性标识比如说用户ID之类的可能并不适合,因为在一个日志文件中一个用户可能会有多个请求在同时进行处理,这就很难提取出具体的某个处理流。UUID是个不错的选择,你可以把它存储到线程名或者TLS——ThreadLocal Storage里面。

3. 不要使用循环

你经常会看到有在循环体中进行日志打印,这么做的前提是循环的次数是有限的。

如果不出什么问题的话当然还好。不过如果代码碰到一些异常的输入导致循环无法退出的话,这就不妙了。这可不止是循环无法结束的问题了,你的程序还一直在往磁盘或者网络中写入数据。

如果只是写到自己的设备中,结果可能就只是挂了一台服务器,但如果是一个分布式的环境,就可能就是一整个集群都瘫了。所以最好还是不要在循环里面打印日志,尤其是当涉及到异常处理的时候。

我们来看一个例子,这里是在循环中来打印异常的信息:

void read() {
    while (hasNext()) {
        try {
            readData();
        } catch {Exception e) {
            // this isn’t recommend
            logger.error(“error reading data“, e);
        }
    }
}


如果readData()抛出异常并且hasNext()返回true,这段代码就会不停在打印日志。一个解决方法就是不要每次都打印出来:

void read() {
    int exceptionsThrown = 0;
    while (hasNext()) {
        try {
            readData();
        } catch {Exception e) {
            if (exceptionsThrown < THRESHOLD) {
                logger.error(“error reading data", e);
                exceptionsThrown++;
            } else {
                // Now the error won’t choke the system.
            }
        }
    }
}


还有一个方法就是把日志操作从循环中去掉,在另外的地方进行打印,只记录第一个或者最后一个异常就好了。

4. 未捕获的异常

维斯特洛有一道最后的防御墙,而你有Thread.uncaughtExceptionHandler。请确认你已经用上它们了。如果没有的话,你的异常可能这么没了,而你只能拿到很少的一些上下文信息,同时这些异常在哪打印,是否打印,你也不好控制。

如果你的代码出现异常却没有记录下来,或者记录下来了却没有相关的状态信息,那真是非常失败。

尽管在uncaughtExceptionHandler里面看似已经访问不了线程里面的任何变量了(它已经挂了),但你至少还有一个当前线程的引用。如果结合刚才提到的第一条建议的话,至少日志中还能打印出一个有意义的thread.getName()的值。

5. 捕获外部调用的异常

只要你调用到了JVM以外的接口,那么发生异常的概率就大大提升了。这包括WEB服务,HTTP,数据库,文件系统,操作系统或者其它的一些JNI调用。你得非常小心地处理每一个调用。

大多数情况下,外部调用之所以会失败是因为传入了错误的参数。为了修复这些问题,把这些请求参数记录到日志中是非常有必要的。

你可能不想记录错误信息,而是直接去抛出异常,这样做也没有问题。不过这么做的话,你要尽可能把相关的参数都收集起来,放到异常信息里面去。

你得确保在上一层调用中捕获了异常并且记录到了日志里。



try {
    return s3client.generatePresignedUrl(request);
} catch (Exception e) {
    String err = String.format(“Error generating request: %s bucket: %s key: %s. method: %s", request, bucket, path, method);
    log.error(err, e); //这里你也可以抛出一个异常,记得把ERR信息带上。
}




原创文章转载请注明出处:http://it.deepinmind.com

英文原文链接

3
0
分享到:
评论

相关推荐

    安卓app实时日志打印工具,安装后可以打印app系统日志,需要集成在自己应用中

    在安卓应用开发中,日志打印工具扮演着至关重要的角色,它们可以帮助开发者追踪应用程序的运行状态,定位并解决潜在的问题。本文将详细讲解一个专用于安卓app的实时日志打印工具,该工具允许开发者集成到自己的应用...

    Android-XLog一个简易的日志打印框架

    **Android-XLog简易日志打印框架详解** 在Android应用开发中,日志打印是一个不可或缺的环节,它能帮助开发者在调试、排错时快速定位问题。`XLog`是一个轻量级的日志打印框架,其设计目标是提供简单易用且功能强大...

    java打印日志的10个建议.doc

    Java 打印日志的 10 个建议 一、选择合适的日志 API 在 Java 中,选择合适的日志 API 非常重要。Slf4j 是一个非常优秀的日志 API,因为它支持模式注入的方式,可以避免字符串拼接,提高效率。Slf4j 并不是一个具体...

    很好用的打印日志模块的源码

    好用的打印日志的源码,因为该源码商未用在具体工程上,但是经过了严格的测试。所以有什么问题及好的建议请联系 QQ915566420,感激不尽。

    解决华为系列手机调试时不能打印Logcat日志信息

    ### 解决华为系列手机调试时不能打印Logcat日志信息 在进行Android应用开发的过程中,开发者经常需要通过Logcat(Log Catcher)工具来获取应用运行时的日志信息,这对于定位问题、调试程序有着至关重要的作用。然而...

    网络日志拦截器输入格式化打印工具类.rar

    然而,原始的日志打印往往信息混乱,不易于理解和排查问题。针对这一需求,"网络日志拦截器输入格式化打印工具类.rar" 提供了一个解决方案,通过自定义OkHttp的拦截器实现网络请求日志的清晰格式化打印。 首先,...

    日志事件 解释文件制作

    例如,对于MessageDLL.dll中定义的一个特定事件ID,解释文件可能会说明这个事件表示什么问题,可能由哪些操作或异常触发,以及建议的解决步骤。接着,将这些信息整理成结构化的文档,方便查阅和引用。 在实际操作中...

    c++输出日志的 方法

    在C++编程环境中,日志记录是软件开发中不可或缺的一部分,它可以帮助开发者追踪程序的运行状态、调试错误以及监控性能等。本篇文章将详细介绍如何在C++中实现日志输出功能,并探讨相关的技术和最佳实践。 ### 一、...

    xxxx有限公司业务软件日志规范V1.0.docx

    - **appName**:业务软件的名称,这是必填项,并建议与公司的服务树保持一致。 - **subName**:可选的二级名称,用于进一步细分日志类别,比如子系统、模块或中间件的名称。 - **class**:可选项,用于标识日志的...

    Qt实现简单的qDebug输出到日志文件

    默认情况下,这些信息会被打印到控制台(stdout)或者调试器中。但在某些场景下,如桌面应用或嵌入式系统,我们可能希望将这些信息保存到日志文件,以便后续分析。 实现这个功能的关键在于自定义一个日志处理器。...

    Log4j 配置日志打印时区的实现方法

    在某些情况下,我们可能需要确保日志打印出的时间与本地时区一致,或者根据特定需求调整时区。在本文中,我们将深入探讨如何在Log4j中配置日志打印时区,以解决类似标题中描述的问题。 在Log4j 2.x版本中,配置日志...

    android log打印

    8. **性能影响**:频繁的日志打印会影响应用的性能,因此在生产环境中,建议删除或限制日志的输出,仅在调试阶段使用。 9. **第三方库和调试**:许多第三方库也会输出日志,这对于了解库的内部工作原理很有帮助。但...

    安卓开发框架工具类相关-常用开发工具类文件复制日志打印图片处理toast.rar

    本压缩包"安卓开发框架工具类相关-常用开发工具类文件复制日志打印图片处理toast.rar"包含了几个关键领域的工具类:文件操作、日志记录、图片处理和Toast提示。以下将详细讲解这些知识点。 1. 文件操作: 在安卓中...

    Mac 下 Android Studio 不打印日志的解决办法

    在开发Android应用的过程中,日志打印是调试代码和定位问题的关键工具。然而,有时在Mac环境下使用Android Studio,开发者可能会遇到日志不显示的问题。针对这种情况,本文将提供三种有效的解决办法。 首先,最简单...

    logger日志

    日志记录器(Logger)是日志处理的核心组件。log4j具有5种正常级别(Level)。...比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来,也是说大于等于的级别的日志才输出。

    Unity移动端打印输出信息

    本篇文章将深入探讨如何在Unity中实现移动端的日志打印输出。 首先,Unity提供了内置的日志系统,主要通过`Debug.Log`,`Debug.LogWarning`和`Debug.LogError`三个方法来实现。这些方法分别用于输出普通信息、警告...

    python logging日志打印过程解析

    最后,对于日志模块的使用,建议不要在生产环境中记录大量的DEBUG或INFO级别的日志,因为这可能会增加日志文件的大小,影响系统性能。根据实际需求和日志策略合理配置日志级别和处理器,可以更加高效地使用日志功能...

    打印到PDF输出,打印跑了。

    7. **错误日志**:当打印出现问题时,查看错误日志可以帮助定位问题。许多打印软件会记录错误信息,这些信息对于诊断问题非常有用。 8. **第三方工具**:如果内置的PDF打印功能不起作用,可以尝试使用第三方工具,...

Global site tag (gtag.js) - Google Analytics