2015-04-21 76 views
12

我有一個簡單的應用程序networked knock-knock joke app。我將一些Log4J(版本2)登錄到它。這裏是服務器類:如何在此應用程序中使Apache Log4J日誌記錄有用?

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語句來決定是否記錄某些內容(即,如果用戶輸入「quit」,我可以對此進行特定的登錄)。

有沒有可能將性能指標納入日誌的方法?這對我來說真的很有用。我的目標是讓代碼演示一些可能有助於稍後展示故障安全功能的內容(也就是說,如果它被中止,我們可能會利用日誌來重新啓動客戶端)。

感謝

+0

確定我想出與XML的文件的方式:'<的PatternLayout圖案=「%d {YYY-MM-DD HH:MM :ss.SSS}行:%L [%t]%-5級別記錄器{36} - %msg%n「/>' – Coffee

回答

3

一箇中心思想許多日誌框架的是,你不要決定如何在應用程序做,但在配置上。因此,基本上,您的應用程序將記錄所有內容,並將您的配置「過濾」並將輸出發送到正確的位置(即不同文件,系統日誌,甚至完全忽略它)。

一般來說,在開發環境中,想要記錄更多內容,因此您可以將所有內容設置爲「調試」,而在生產時,將其設置爲「信息」。

有時,它可能是有益的做一個模式像這樣:

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

4

首先,你的代碼不能編譯。第一個logger.info()調用需要位於靜態{}塊內,或者移至main();而你的while()循環將首次退出 - 你需要圍繞調試和break語句的括號。

但我要說明我的偏見:)

  1. 就個人而言,我找到logger.debug很少使用()調用。現代IDE(我使用Eclipse)提供了出色的調試支持,而不會使用logger.debug()語句混淆代碼。@rmalchow已經指出了不必要的調試語句的缺點 - 我曾經看到一個例子,如果在logger.debug()調用中放置一些語句,性能會增加超過100%。
  2. 因此,在我的世界中,日誌記錄適用於我無法使用IDE進行調試的生產系統。這帶來了一些責任。
  3. 對System.err()的調用應該被logger.error()調用所取代。默認情況下,這些將轉到System.err,但您可以根據需要重定向。
  4. 如果您無法增加價值,那就讓異常滲透。我傾向於把它們變成RuntimeExceptions,但一些純粹主義者討厭這個。
  5. 當您可以添加值時,不要吞下堆棧跟蹤。例如,你的logger.fatal應該是logger.fatal(「.. msg ...」,例外)。這將節省代碼的許多歡樂時光。

至於指標,你可以隨時推出自己的 - 例如,時間後端通話需要多長時間才能完成並登錄信息級別。我沒有針對有用框架的具體建議,但其他人可能會這樣做。

2

對於您的應用程序,我認爲您所做的已經足夠。你不需要更多。

調試調試/異常和錯誤的錯誤。可能會爲啓動和停止服務器添加信息。

現在,如果你有一個較大的應用程序,你應該這樣做:

  1. 更改log4j來進行的logback看到通過logback vs log4j
  2. 調試參數和返回使用AOP。它會節省很多的每一個方法的價值在開發過程中。我個人使用Jcabi loggable
1

您可以使用AOP(面向方面​​編程)獲得更好的日誌記錄體驗。如果你想要非常細粒度的記錄,你應該使用Aspectj。但是,如果罰款開始學習AOP春天唉。這裏是彈簧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()); 
} 

}

相關問題