如何使此应用程序中的Apache Log4J日志记录有用?

时间:2015-04-21 18:15:33

标签: java logging log4j

我有一个简单networked knock-knock joke app的应用程序。我将一些Log4J(版本2)登录到其中。这是服务器类:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Level;

import java.net.*;
import java.io.*;

public class MessageResponseServer extends Thread /* added in the T just now*/{   /* REPLACED */

   private static final Logger logger = LogManager.getLogger("MessageResponseServer");
        logger.info("MessageResponseServer.java :  INFO message");
    public static void main(String[] args) throws IOException {

        logger.debug("MessageResponseServer.java : DEBUG  message");

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(4444);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 4444.");
            logger.fatal("MessageResponseServer.java :  FATAL  message - Could not listen on port: 4444.");

            System.exit(1);
        }

        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
                    logger.debug("MessageResponseServer.java :   , debug message");
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }

        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(
                new InputStreamReader(
                clientSocket.getInputStream()));
        String inputLine, outputLine;
        MessageResponseProtocol mrp = new MessageResponseProtocol();  /* REPLACED */

        outputLine = mrp.processInput(null);
        out.println(outputLine);

        while ((inputLine = in.readLine()) != null) {
             outputLine = mrp.processInput(inputLine);
             out.println(outputLine);
             if (outputLine.equals("Bye."))
             logger.debug("MessageResponseServer.java : , Exiting. DEBUG Message"); 
                break;
        }
        out.close();
        in.close();
        clientSocket.close();
        serverSocket.close();
    }
}

以下是XML文件:

<?xml version="1.0" encoding="UTF-8"?>


<Configuration status="WARN">
  <Appenders>

    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
    <File name="MyFile" fileName="OutputLogFile.log" immediateFlush="false" append="true">
            <PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </File>

  </Appenders>

  <Loggers>
    <Root level="ALL">
      <Appender-Ref ref="Console"/>
      <Appender-Ref ref="MyFile"/>  

    </Root>


  </Loggers>
</Configuration>

我想做的是弄清楚如何使日志记录更有用。您是否添加了特殊if语句来决定是否记录某些内容(即,如果用户输入&#34;退出&#34;我可以对其进行特定登录)。

是否有可能将性能指标纳入日志记录?这对我来说真的很有用。我的目标是让代码演示一些可能有助于使其在以后显示故障安全功能的东西(例如,如果它被中止,我们可能会利用日志重新启动客户端)。

感谢

4 个答案:

答案 0 :(得分:4)

首先,您的代码无法编译。第一个logger.info()调用需要在static {}块内,或者移动到main();而你的while()循环将首次退出 - 你需要在debug和break语句周围使用{}括号。

但我需要陈述我的偏见:)

  1. 就个人而言,我发现logger.debug()调用几乎没用。现代IDE(我使用Eclipse)提供了出色的调试支持,而不会使用logger.debug()语句使代码混乱。 @rmalchow已经指出了不需要的调试语句的缺点 - 我已经看到一旦一些if语句放在logger.debug()调用之后性能增加超过100%的情况。
  2. 因此,在我的世界中,日志记录适用于我无法使用IDE调试的生产系统。这带来了许多责任。
  3. 应该用logger.error()调用替换对System.err()的调用。默认情况下,这些将转到System.err,但您可以根据需要重定向。
  4. 如果您无法增加价值,只需让异常渗透。我倾向于把它们变成RuntimeExceptions,但是一些纯粹主义者讨厌这个。
  5. 如果可以添加值,请不要吞下堆栈跟踪。例如,你的logger.fatal应该是logger.fatal(“.. msg ...”,例外)。这将节省许多欢乐时间的代码。
  6. 对于指标,您可以随时自行推送 - 例如时间后端调用完成和登录信息级别所需的时间。我没有针对有用框架的具体建议,但其他人可能会这样做。

答案 1 :(得分:3)

许多日志记录框架的核心思想之一就是您不会决定在应用程序中执行哪些操作,而是在配置中。所以,基本上,你的应用程序记录了所有内容,并且你的配置&#34;过滤器&#34;并将输出发送到正确的位置(即不同的文件,系统日志,甚至完全忽略它)

一般情况下,在开发环境中,您希望记录更多内容,因此您可以将所有内容设置为&#34; DEBUG&#34;,在生产时,您将其设置为&#34; INFO&#34;。< / p>

有时,做这样的模式可能是有益的:

 if(log.isDebug()) {
       log.debug("some formatting");
 }

避免执行格式化(在这种情况下)并立即将其丢弃。

您的模式布局也有点问题 - 例如,检索行号是不可靠的(它基本上取决于使用debug = true编译的代码)并且非常昂贵(它必须检索堆栈跟踪并提取行信息)从它)。

对于实际执行时间指标,您可能希望在其他地方寻找 - 一个提供计数器和时间测量的优秀库,包括最大值,最小值,平均值等指标 - 核心:

https://dropwizard.github.io/metrics/3.1.0/manual/core/

如果您使用spring,您可能希望根据此库查看我的方面:

https://github.com/rmalchow/metrics

答案 2 :(得分:2)

对于您的应用程序,我认为您所做的就足够了。你不需要更多。

调试调试/异常和错误的错误。可以为启动和停止服务器添加信息。

现在,如果你有一个更大的应用程序,你应该这样做:

  1. 更改Log4J for Logback,请参阅logback vs log4j
  2. 调试参数传递并使用AOP返回每个方法的值。它将在开发过程中节省大量时间。我个人使用Jcabi loggable

答案 3 :(得分:1)

您可以使用AOP(面向方面​​编程)来获得更好的日志记录体验。如果你想要非常细粒度的日志,你应该去使用Aspectj。但是如果开始学习AOP,那就好了。以下是spring-aop方面的一个例子:

@Aspect
public class CalculatorLoggingAspect {

private Logger logger = Logger.getLogger(this.getClass());

@Before("execution(* ArithmeticCalculator.add(..))")
public void logBefore(){
    logger.info("The method add() begins");
}

@Before("execution(* *.*(..))")
public void logBefore(JoinPoint joinPoint){
    logger.info("The method " + joinPoint.getSignature().getName()
            + "() begins with " + Arrays.toString(joinPoint.getArgs()));
}

@After("execution(* *.*(..))")
public void logAfter(JoinPoint joinPoint){
    logger.info("The method " + joinPoint.getSignature().getName() + "() ends.");
}

@AfterReturning("execution(* *.*(..))")
public void logAfterReturning(JoinPoint joinPoint){
    logger.info("The method " + joinPoint.getSignature().getName() + "() ends successfully.");
}

@AfterReturning(pointcut="execution(* *.*(..))", returning="result")
public void logAfterReturning(JoinPoint joinPoint, Object result){
    logger.info("The method " + joinPoint.getSignature().getName() + "() ends with "+result);
}

@AfterThrowing("execution(* *.*(..))")
public void logAfterThrowing(JoinPoint joinPoint){
    logger.info("The method "+joinPoint.getSignature().getName()+"() throws an exception.");
}

@AfterThrowing(pointcut = "execution(* *.*(..))", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e){
    logger.debug("The method "+joinPoint.getSignature().getName()+"() throws an exception : "+ e);
}

@Around("execution(* *.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable{
    logger.info("The method "+joinPoint.getSignature().getName()+"() begins with "
            +Arrays.toString(joinPoint.getArgs()));
    try{
        Object result = joinPoint.proceed();
        logger.info("The method "+joinPoint.getSignature().getName()
                +"() ends with "+result);
        return result;
    }catch(IllegalArgumentException e){
        logger.error("Illegal argument "+Arrays.toString(joinPoint.getArgs())
                +" in "+joinPoint.getSignature().getName()+"()");
        throw e;
    }
}

@Before("execution(* *.*(..))")
public void logJoinPoint(JoinPoint joinPoint){
    logger.info("Join point kind : "+joinPoint.getKind());
    logger.info("Signature declaring type : "+joinPoint.getSignature().getDeclaringTypeName());
    logger.info("Signature name : "+joinPoint.getSignature().getName());
    logger.info("Arguments : "+Arrays.toString(joinPoint.getArgs()));
    logger.info("Target class : "+joinPoint.getTarget().getClass().getName());
    logger.info("This class : "+joinPoint.getThis().getClass().getName());
}

}