我有一个简单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;我可以对其进行特定登录)。
是否有可能将性能指标纳入日志记录?这对我来说真的很有用。我的目标是让代码演示一些可能有助于使其在以后显示故障安全功能的东西(例如,如果它被中止,我们可能会利用日志重新启动客户端)。
感谢
答案 0 :(得分:4)
首先,您的代码无法编译。第一个logger.info()调用需要在static {}块内,或者移动到main();而你的while()循环将首次退出 - 你需要在debug和break语句周围使用{}括号。
但我需要陈述我的偏见:)
对于指标,您可以随时自行推送 - 例如时间后端调用完成和登录信息级别所需的时间。我没有针对有用框架的具体建议,但其他人可能会这样做。
答案 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,您可能希望根据此库查看我的方面:
答案 2 :(得分:2)
对于您的应用程序,我认为您所做的就足够了。你不需要更多。
调试调试/异常和错误的错误。可以为启动和停止服务器添加信息。
现在,如果你有一个更大的应用程序,你应该这样做:
答案 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());
}
}