标准化企业产品中的日志记录

时间:2014-07-04 10:18:28

标签: logging log4j aop slf4j

我所使用的软件具有高度不一致的日志记录。所有日志记录都在一个文件中完成,该文件包含来自不同模块和客户端交互的日志记录详细信息日志文件非常混乱,我想做的最少的事情是在行的开头添加一些模块信息。例如,如下所示,我希望日志中首先打印 MODULE

#|2014-07-02T13:01:51.030+0530|INFO|glassfish3.1.1|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=104;_ThreadName=Thread-3;|3131149 [pool-23-thread-18] [rid=1112 session=f5fc97b0ac1802b000b94819c9518996 user=TTUser13] INFO **[MODULE1]**  com.xxxxx.Manager  - Client manager - getMo(Test) request received |#]

[#|2014-07-02T13:01:51.033+0530|INFO|glassfish3.1.1|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=104;_ThreadName=Thread-3;|3131153 [pool-23-thread-18] [rid=1112 session=f5fc97b0ac1802b000b94819c9518996 user=TTUser13] INFO **[MODULE2]** com.xxxxx.server.CliRmiService  - getMo(f5fc97b0ac1802b000b94819c9518996) - 3ms - com.xxxxx.ManagerObject@10f7afd

我建议在模块之间进行单独的日志记录遇到了许多持怀疑态度的点头(不允许)。所以至少我想做的是能够在每行的开头添加MODULE信息。我在我的软件中使用SPRING,JAVA和log4j(slf4j包装器)。这样做有更简单的方法吗?我不想去每个记录器语句并添加该标头。这将非常不方便。另外,还有其他方法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

解决问题的最佳方法是重构代码并引入所需的日志记录。持怀疑态度只是因为人们想要避免触及遗留代码是一种嗅觉,而不是争论。

现在,回答你的问题:尽管AOP不是为修补糟糕的设计或糟糕的日志记录习惯而发明的,但你可以将AspectJ用于你的目的。 " AOP lite"像Spring AOP这样的框架在这​​里是不合适的,因为Spring AOP只支持方法执行拦截,而不是方法调用拦截,这就是你需要的。

这是一个简单的AspectJ示例。请注意,每当我说" module"时,我的意思是包名的最后一部分(在最后一个"。"之后),例如如果包名称为module1,则de.scrum_master.module1将是模块名称。

不同模块中的两个示例类:

package de.scrum_master.module1;

import java.util.logging.Logger;

public class Person {
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; }
    @Override public String toString() { return "Person[" + firstName + " " + lastName + "]"; }
    public void doSomething() { Logger.getLogger("GLOBAL").info("Doing something with " + this); }
    public void doSomethingElse() { Logger.getLogger("GLOBAL").info("Doing something else with " + this); }
}
package de.scrum_master.module2;

import java.util.logging.Logger;

public class Place {
    private String country;
    private String city;

    public Place(String country, String city) { this.country = country; this.city = city; }
    @Override public String toString() { return "Place[" + city + ", " + country + "]"; }
    public void doSomething() { Logger.getLogger("GLOBAL").info("Doing something with " + this); }
    public void doSomethingElse() { Logger.getLogger("GLOBAL").info("Doing something else with " + this); }
}

使用模块的驱动程序应用程序:

package de.scrum_master.app;

import java.util.logging.Logger;

import de.scrum_master.module1.Person;
import de.scrum_master.module2.Place;

public class Application {
    private static final Logger LOG = Logger.getLogger("GLOBAL");

    public static void main(String[] args) {
        doPersonStuff();
        doPlaceStuff();
    }

    private static void doPersonStuff() {
        LOG.info("Start doing person stuff...");
        Person person = new Person("Albert", "Einstein");
        person.doSomething();
        person.doSomethingElse();
        person = new Person("Werner", "Heisenberg");
        person.doSomething();
        person.doSomethingElse();
        LOG.info("Finished doing person stuff");
    }

    private static void doPlaceStuff() {
        LOG.info("Start doing place stuff...");
        Place place = new Place("Indonesia", "Jakarta");
        place.doSomething();
        place.doSomethingElse();
        place = new Place("Germany", "Berlin");
        place.doSomething();
        place.doSomethingElse();
        LOG.info("Finished doing place stuff");
    }
}

<强>方面:

Aspect为每条日志消息添加了一个大写模块名称前缀,如[MODULE1]。根据类或包名称将方面日志记录到不同的日志文件中会非常简单。这只是一个示范。

package de.scrum_master.aspect;

import java.util.logging.Logger;

public aspect LogModulePrepender {
    void around(String message) :
        call(public void Logger.*(String)) && args(message)
    {
        String packageName = thisJoinPoint.getSourceLocation().getWithinType().getPackage().getName();
        String moduleName = packageName.replaceFirst(".*[.]", "").toUpperCase();
        proceed("[" + moduleName + "] " + message);
    }
}

日志输出:

请注意,为了简单起见,我在将这个小样本混合在一起时使用的是Java日志记录而不是Log4j。应该很容易适应。

Jul 25, 2014 11:11:48 AM de.scrum_master.app.Application info_aroundBody0
Information: [APP] Start doing person stuff...
Jul 25, 2014 11:11:48 AM de.scrum_master.module1.Person info_aroundBody0
Information: [MODULE1] Doing something with Person[Albert Einstein]
Jul 25, 2014 11:11:48 AM de.scrum_master.module1.Person info_aroundBody2
Information: [MODULE1] Doing something else with Person[Albert Einstein]
Jul 25, 2014 11:11:48 AM de.scrum_master.module1.Person info_aroundBody0
Information: [MODULE1] Doing something with Person[Werner Heisenberg]
Jul 25, 2014 11:11:48 AM de.scrum_master.module1.Person info_aroundBody2
Information: [MODULE1] Doing something else with Person[Werner Heisenberg]
Jul 25, 2014 11:11:48 AM de.scrum_master.app.Application info_aroundBody2
Information: [APP] Finished doing person stuff
Jul 25, 2014 11:11:48 AM de.scrum_master.app.Application info_aroundBody4
Information: [APP] Start doing place stuff...
Jul 25, 2014 11:11:48 AM de.scrum_master.module2.Place info_aroundBody0
Information: [MODULE2] Doing something with Place[Jakarta, Indonesia]
Jul 25, 2014 11:11:48 AM de.scrum_master.module2.Place info_aroundBody2
Information: [MODULE2] Doing something else with Place[Jakarta, Indonesia]
Jul 25, 2014 11:11:48 AM de.scrum_master.module2.Place info_aroundBody0
Information: [MODULE2] Doing something with Place[Berlin, Germany]
Jul 25, 2014 11:11:48 AM de.scrum_master.module2.Place info_aroundBody2
Information: [MODULE2] Doing something else with Place[Berlin, Germany]
Jul 25, 2014 11:11:48 AM de.scrum_master.app.Application info_aroundBody6
Information: [APP] Finished doing place stuff