【问题标题】:How do I make the Apache Log4J logging in this application useful?如何使此应用程序中的 Apache Log4J 日志记录有用?
【发布时间】:2015-04-21 18:15:33
【问题描述】:

我有一个简单的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 语句来决定是否记录某些内容(即,如果用户输入“退出”,我可以对其进行特定的登录)。

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

谢谢

【问题讨论】:

  • 好的,我找到了 XML 文件的方法:&lt;PatternLayout pattern="%d{yyy-MM-dd HH:mm:ss.SSS} Line: %L [%t] %-5level %logger{36} - %msg%n"/&gt;

标签: java logging log4j


【解决方案1】:

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

但我需要说明我的偏见:)

  1. 就个人而言,我发现 logger.debug() 调用几乎没有用处。现代 IDE(我使用 Eclipse)提供了出色的调试支持,而不会让您的代码与 logger.debug() 语句混淆。 @rmalchow 已经指出了不需要的调试语句的缺点 - 我见过一个案例,一旦在 logger.debug() 调用周围放置一些 if 语句,性能就会提高 100% 以上。
  2. 所以在我的世界里,日志记录适用于我无法使用 IDE 调试的生产系统。这带来了许多责任。
  3. 对 System.err() 的调用应替换为 logger.error() 调用。默认情况下,这些将转到 System.err,但如果需要,您可以重定向。
  4. 如果你不能增加价值,那就让异常渗入。我倾向于将它们变成 RuntimeExceptions,但一些纯粹主义者讨厌这样。
  5. 当您可以增加价值时,不要吞下堆栈跟踪。例如,您的 logger.fatal 应该是 logger.fatal("..msg...", exception)。这将节省许多愉快的 grep 代码时间。

至于指标,您可以随时自行调整 - 例如后端调用完成并在信息级别记录所需的时间。对于一个有用的框架,我没有具体的建议,但其他人可能会。

【讨论】:

    【解决方案2】:

    许多日志框架的一个核心思想是,您不决定在应用程序中做什么,而是在配置中决定。因此,基本上,您的应用程序会记录所有内容,并且您的配置“过滤”并将输出发送到正确的位置(即不同的文件、系统日志,甚至完全忽略它)

    一般来说,在开发环境中,您希望记录更多信息,因此您可以将所有内容设置为“DEBUG”,而在生产环境中,将其设置为“INFO”。

    有时,执行如下模式可能会有所帮助:

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

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

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

    对于实际的执行时间指标,您可能想看看其他地方 - 提供计数器和时间测量(包括最大值、最小值、平均值等)的优秀库是 metrics-core:

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

    如果你使用的是spring,你可能想看看我基于这个库的方面:

    https://github.com/rmalchow/metrics

    【讨论】:

      【解决方案3】:

      对于您的申请,我认为您所做的已经足够了。你不需要更多。

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

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

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

      【讨论】:

        【解决方案4】:

        您可以使用 AOP(面向方面​​的编程)来获得更好的日志记录体验。如果您想要非常细粒度的日志记录,您应该使用 Aspectj。但是如果可以的话,开始学习AOP spring-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());
        }
        

        }

        【讨论】:

          猜你喜欢
          • 2019-03-14
          • 2016-01-26
          • 2012-06-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多