Как сделать запись в Apache Log4J в этом приложении полезной?

У меня есть приложение, которое представляет собой простое сетевое приложение для шуток-нокаутов. Я включил 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, чтобы решить, нужно ли что-то записывать (т.е. Если пользователь вводит "quit", я могу сделать для него определенный журнал).

Есть ли способ включить показатели производительности в ведение журнала? Это было бы очень полезно для меня. Моя цель состоит в том, чтобы код продемонстрировал что-то, что может помочь в его отказе от сбоев (позже, возможно, мы сможем использовать журналы для перезапуска клиентской стороны, если они были прерваны).

спасибо

Ответ 1

Во-первых, ваш код не компилируется. Первый вызов logger.info() должен находиться внутри статического блока {} или перемещаться в main(); И цикл while() будет выходить с первого раза - вам нужны {} скобки вокруг операторов отладки и разрыва.

Но мне нужно указать мои предрассудки:)

  • Лично я мало использую для вызовов logger.debug(). Современные IDE (я использую Eclipse) обеспечивают отличную поддержку отладки без загромождения кода с помощью операторов logger.debug(). @rmalchow уже указал на недостатки ненужных операторов отладки - я видел случай, когда производительность увеличилась более чем на 100%, если несколько операторов if были поставлены вокруг вызовов logger.debug().
  • Итак, в моем мире регистрация выполняется для производственных систем, которые я не могу отлаживать с помощью IDE. Это приносит ряд обязанностей.
  • Вызовы в System.err() должны быть заменены вызовами logger.error(). По умолчанию они перейдут в System.err, но при необходимости вы можете перенаправить.
  • Если вы не можете добавить значение, просто разрешите пересылку исключений. Я склонен превращать их в RuntimeExceptions, но некоторые пуристы ненавидят это.
  • Когда вы можете добавить значение, не проглатывайте трассировку стека. Например, ваш logger.fatal должен быть logger.fatal( ".. msg...", исключение). Это сэкономит много счастливых часов кода grepping.

Что касается метрик, вы всегда можете перевернуть свой собственный - например, время, необходимое для завершения и входа на информационный уровень. У меня нет конкретных предложений для полезной структуры, но другие могут.

Ответ 2

Одна из основных идей для многих фреймворков регистрации заключается в том, что вы НЕ решаете, что делать в приложении, но в конфигурации. так что, в основном, ваше приложение регистрирует все, а ваш конфиг "фильтрует" и отправляет вывод в нужное место (т.е. разные файлы, syslog или даже игнорирует его полностью)

в общем, в среде разработки вы хотите записать больше, поэтому вы можете установить все на "DEBUG", а при производстве вы установите его "INFO".

иногда бывает полезно сделать такой шаблон, например:

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

чтобы избежать выполнения форматирования (в данном случае) и сразу же выбросить его.

макет шаблона также немного проблематичен - например, получение номера строки ненадежно (в основном это зависит от кода, скомпилированного с помощью debug = true) и очень дорогого (он должен извлекать стек и извлекать информацию о линии от него).

для фактических показателей времени выполнения вы можете посмотреть в другом месте - отличная библиотека, которая обеспечивает счетчики и измерения времени, включая max, min, average и т.д. - метрика-ядро:

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

и если вы используете spring, вы можете посмотреть мой аспект на основе этой библиотеки:

https://github.com/rmalchow/metrics

Ответ 3

Для вашего приложения, я думаю, что вы сделали достаточно. вам больше не нужно.

Отладка для отладки/Ошибка для исключения и ошибок. Может быть добавлена ​​информация для запуска и остановки сервера.

Теперь, если у вас было более крупное приложение, вы должны сделать это:

  • Изменить Log4J для ведения журнала см. logback vs log4j
  • Отладочные параметры передаются и возвращают значения каждого метода, используя 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());
}

}