关于日志记录的总结

  前段时间,公司的一个项目,需要做很多的数据接口和同步程序,于是就遇到了日志记录的问题,何时记录,如何记录,哪些要记哪些不用记等问题。针对日志记录的问题,经过一系列讨论,终于达成了统一的处理办法。解决了各个模块系统,不同的开发人员,日志记录不统一,随意的问题。今天终于抽出时间把这个问题总结并结合网络上的资料,进行整理。

  为什么要记录日志

  记录日志是调试程序,监视程序运行的一种重要的方式,主要有两个目的:bug的及时发现和定位,显示程序运行状态。正确详细的日志记录能够快速的定位问题。同样,通过查看日志,可以看出程序正在做什么,是不是按预期的设计在执行,所以记录下程序的运行状态是必要的。

  哪些地方需要记日志

  1. 调用或封装外部程序或接口
    程序中对外部系统与模块的依赖调用前后都应该记下日志,方便接口调试。出问题时也可以很快查出是哪里出的问题

    LOG.debug(“Calling external system:” + parameters);
    Object result = null;
    try {
      result = callRemoteSystem(params);
      LOG.debug(“Called successfully. result is ” + result);
    } catch (Exception e) {
      LOG.warn(“Failed at calling xxx system . exception : ” + e);
    }

  2.对重要对象或变量被修改,要以INFO记录修改前的信息和修改后的状态。
    程序中重要的状态信息的变化应该记录下来,方便查问题时还原现场,推断程序运行过程

    boolean isRunning;
    isRunning = true;
    LOG.info(“System is running”);
    //…
    isRunning = false;
    LOG.info(“System was interrupted by ” + Thread.currentThread().getName());

  3.系统入口与出口:
    系统的入口和出口,重要方法或模块的执行。记录它的输入与输出,方便定位。

  4.业务异常或者重要的业务处理:
    任何业务异常都应该记下来,还有系统中一些重要的业务,比如结算等业务,也最好能记录下来。

  5.非预期执行:
    为程序在“有可能”执行到的地方打印日志。如果我想删除一个文件,结果返回成功。但事实上,那个文件在你想删除之前就不存在了。最终结果是一致的,但程序得让我们知道这种情况,要查清为什么文件在删除之前就已经不存在

    int myValue = xxxx;
    int absResult = Math.abs(myValue);
    if (absResult < 0) {
      LOG.info(“Original int ” + myValue + “has nagetive abs ” + absResult);
    }
  6.很少出现的else情况:
    代码中,一定要有完整的if else,如果else 里面没有要执行的,记录日志,这样避免else吞掉你的请求,或是返回给你难以理解的结果。

    Object result = null;
    if (running) {
      result = xxx;
    } else {
      result = yyy;
      LOG.debug(“System does not running, we change the final result”);
    }

  7. 批量数据的执行进度:

    LOG.debug(“current progress: ” + (currentPos * 100 / totalAmount) + “%”);

  日志记录的方式

  1. 日志信息应该包含记录程序运行时间和错误发生的时间.

  2. 日志信息清晰准确有意义
    日志应该是清晰准确的: 当看到日志的时,就能准确的知道错误是因为连接池取不到连接导致的问题。

    Connection connection = ConnectionFactory.getConnection();
    if (connection == null) {
      LOG.warn(“System initialized unsuccessfully”);
    }
  3. 记录错误的位置
    代码中,一定要记录下错误所在的文件名和函数名(必须能区分开重载函数),有行数最好。

  4. 区分日志级别
    在程序中Log进行分级是很重要的,通常可以分为6 级:TRACE DEBUG用来输出调试信息,一般是在程序中不是非常重要的地方;INFO代表一些比较重要的信息,比如程序初始化完毕,ERROR一般指程序本身引起的,可以恢复的错误;FATAL一般指程序所依赖的环境出现错误,使的程序不恢复。其中常用的是DEBUG和 ERROR。

  5. 信息详细准确
一定要记录下完整准确的信息,否则还不如记录,因为错误的信息可能会误导开发人员。所以最简单的办法就是记录完整的stack trace.

  6. 最好能给log带上上下文
    没有相应的上下文的log,不过是噪音,它们不会对调试过程中有意义的数值或是空间起作用。
    Transaction failed 这样的log信息比没有记录更让人抓狂。

tomcat 无法加载js和css 等静态文件的问题

 

  前段时间做了个网站,在本地tomcat测试都没有问题,但是部署到阿里云上之后,系统样式全没了。jsp等动态页面访问正常。

  打开浏览器监控发现所有的css 和js 文件返回都是404 。直接访问单个的css 文件也同样是404。以为是路径错了,于是一一对了一遍各个文件的路径和服务器上 tomcat路径方面的设置

  发现路径没有问题。在网站更目录创建一个css文件和html文件均不能访问。确认不是网站路径的问题。

  然后怀疑是tomcat 和 Apache 冲突了,或者可能是Apache 的设置不对。因为阿里云是默认的镜像,里面已经装了Apache和tomcat。也没有做什么设置。

  于是直接把Apache 服务停止。但是还是没有用,依然无法访问css 和html 页面。

  然后怀疑是不是服务器js 和css 这两个文件的目录权限有问题,查看了这两个文件夹的权限。没有问题,

  而且在jsp文件能访问的目录,直接创建一个js 文件,同样不能访问。于是权限的怀疑被排除。

  想了半天还是不知道到底是哪配置不对。然后突然想到所有的请求都是nginx 分发的。 是不是nginx 的配置不对。但是一想nginx 配置不对的话,那网站都不能访问啊。为什么jsp 页面能访问而静态文件不行。 带着这个疑问,去查看下nginx的配置,打开nginx conf文件夹中的nginx.conf,果然发现了nginx配置可疑的地方。

  server
  {
    listen 80;
    server_name localhost;
    index index.html index.htm index.jsp;
    root /var/www/web/ROOT;

    location ~ .*.jsp$
    {
      index index.jsp;
      proxy_pass http://localhost:8080;
    }

    locattion *.jsp$ 的意思就是所有jsp的页面均交由tomcat处理。
    root 就是网站的资源存放路径。

    终于清楚了,服务器把所有的请求都是由nginx 转发。nginx 会把 jsp 的请求转给tomcat 来处理,

    至于静态资源的请求 nginx 直接就处理了,直接把资源文件返回给客户端,无需tomcat 处理。

    于是修改root 的设置, 将地址指向实际的网站资源文件的地址。 回到页面重新测试,果然好了。

    刚开始不知道原因,各种测试,各种改代码,服务器相关的设置都改了一遍。知道真相之后,其实要解决非常简单。