tutorial proyecto mvc mediante libro framework español ejemplos desarrollo crear books aplicaciones java logging log4j

java - proyecto - spring framework pdf español



Log4J: estrategias para crear instancias de Logger (10)

Al desplegar múltiples EAR / WAR, puede ser mejor empacar el log4j.jar más arriba en la jerarquía del cargador de clases.
es decir, no en WAR o EAR, sino en el cargador de clases del sistema de su contenedor; de lo contrario, varias instancias de Log4J escribirán simultáneamente en el mismo archivo, lo que generará un comportamiento extraño.

Decidí usar Log4J logging framework para un nuevo proyecto de Java. Me pregunto qué estrategia debería usar para crear / administrar instancias de Logger y por qué?

  • una instancia de Logger por clase, por ejemplo

    class Foo { private static final Logger log = Logger.getLogger(Foo.class); }

  • una instancia de Logger por hilo
  • una instancia de Logger por aplicación
  • rebanado horizontal: una instancia de Logger en cada capa de una aplicación (por ejemplo, la capa de vista, la capa de controlador y la capa de persistencia)
  • rebanado vertical: una instancia de Logger dentro de las particiones funcionales de la aplicación

Nota: Este problema ya se considera en cierta medida en estos artículos:

¿Cuál es la sobrecarga de crear un registrador Log4j


Como han dicho otros, crearía un Logger por clase:

private final static Logger LOGGER = Logger.getLogger(Foo.class);

o

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

Sin embargo, he encontrado útil en el pasado tener otra información en el registrador. Por ejemplo, si tiene un sitio web, podría incluir el ID de usuario en cada mensaje de registro. De esta forma, puede rastrear todo lo que hace un usuario (muy útil para la depuración de problemas, etc.).

La forma más fácil de hacerlo es usar un MDC, pero puede usar un registrador creado para cada instancia de la clase con el nombre incluido el ID de usuario.

Otra ventaja de usar un MDC es que si usa SL4J, puede cambiar la configuración dependiendo de los valores en su MDC. Entonces, si desea registrar toda la actividad de un usuario en particular en el nivel de DEPURACIÓN, y dejar a todos los otros usuarios en ERROR, puede hacerlo. También puede redirigir diferentes salidas a diferentes lugares dependiendo de su MDC.

Algunos enlaces útiles:

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html

http://www.slf4j.org/api/index.html?org/slf4j/MDC.html


El mejor y más fácil método para crear registradores personalizados, no vinculados a ningún nombre de clase es:

// create logger Logger customLogger = Logger.getLogger("myCustomLogName"); // create log file, where messages will be sent, // you can also use console appender FileAppender fileAppender = new FileAppender(new PatternLayout(), "/home/user/some.log"); // sometimes you can call this if you reuse this logger // to avoid useless traces customLogger.removeAllAppenders(); // tell to logger where to write customLogger.addAppender(fileAppender); // send message (of type :: info, you can use also error, warn, etc) customLogger.info("Hello! message from custom logger");

ahora, si necesita otro registrador en la misma clase, no hay problema :) simplemente cree uno nuevo

// create logger Logger otherCustomLogger = Logger.getLogger("myOtherCustomLogName");

ahora vea el código anterior y cree un nuevo archivo adjunto para que su salida se envíe en otro archivo

Esto es útil para (al menos) 2 situaciones

  • cuando desee un error por separado de la información y advierte

  • cuando gestiona múltiples procesos y necesita resultados de cada proceso

PD. tener preguntas ? ¡Siéntete libre de preguntar! :)


Estoy seguro de que esta no es una buena práctica, pero he sacrificado un poco el tiempo de inicio de las aplicaciones para guardar las líneas de código. Específicamente, al pegar en:

Logger logger = Logger.getLogger(MyClass.class);

... los desarrolladores a menudo olvidan cambiar "MyClass" al nombre de clase actual, y varios registradores siempre terminan señalando en el lugar equivocado. Esto es malo.

Ocasionalmente he escrito:

static Logger logger = LogUtil.getInstance();

Y:

class LogUtil { public Logger getInstance() { String callingClassName = Thread.currentThread().getStackTrace()[2].getClass().getCanonicalName(); return Logger.getLogger(callingClassName); } }

El "2" en ese código podría estar equivocado, pero la esencia está ahí; realice un golpe de rendimiento para (en la carga de la clase, como variable estática) encuentre el nombre de la clase, de modo que un desarrollador no tenga realmente una manera de escribir mal este error o introducirlo.

Por lo general, no estoy entusiasmado con la pérdida de rendimiento para evitar errores de desarrollador en tiempo de ejecución, pero si sucede como singleton, ¿una vez? A menudo me parece un buen negocio.


La convención común es "una clase pr logger y usa el nombre de la clase como su nombre". Este es un buen consejo.

Mi experiencia personal es que esta variable de registrador NO se debe declarar estática sino como una variable de instancia que se recupera para cada nueva. Esto permite que el marco de trabajo de registro trate dos llamadas de manera diferente según su procedencia. Una variable estática es la misma para TODAS las instancias de esa clase (en ese cargador de clases).

También debe aprender todas las posibilidades con su servidor de registro de elección. Puede tener posibilidades que no esperaba posibles.


La estrategia más utilizada es crear un registrador por clase. Si crea nuevos hilos, déles un nombre útil, para que su registro sea fácilmente distinguible.

La creación de registradores por clase tiene la ventaja de poder activar / desactivar el registro en la estructura del paquete de tus clases:

log4j.logger.org.apache = INFO log4j.logger.com.example = DEBUG log4j.logger.com.example.verbose = ERROR

Lo anterior establecería todo el código de la biblioteca apache en el nivel INFO , cambiará el registro desde su propio código al nivel DEBUG con la excepción del paquete verbose.


Normalmente, tendrías la configuración de los registradores por clase porque es un buen componente lógico. Los subprocesos ya forman parte de los mensajes de registro (si su filtro los muestra), por lo que cortar los registradores de esa manera probablemente sea redundante.

Con respecto a los registradores de aplicaciones o basados ​​en capas, el problema es que debes encontrar un lugar para pegar ese objeto Logger. No es realmente un gran problema. El problema más grande es que algunas clases se pueden usar en múltiples niveles desde varias aplicaciones ... podría ser difícil obtener su registrador correctamente. O al menos complicado.

... y lo último que quieres son suposiciones erróneas en tu configuración de registro.

Si le importan las aplicaciones y las capas y tiene puntos de separación fáciles, el NDC es el camino a seguir. El código puede ser un poco excesivo a veces, pero no sé cuántas veces he sido salvado por una pila de contexto precisa que me muestra que se llamó a Foo.bar () desde la aplicación X en la capa Y.


Otra opción: puede probar el corte transversal de AspectJ en el registro. Marque aquí: Simplifique su registro . (Si no quiere usar AOP , puede mirar slf4j )

//Without AOP Class A{ methodx(){ logger.info("INFO"); } } Class B{ methody(){ logger.info("INFO"); } } //With AOP Class A{ methodx(){ ...... } } Class B{ methody(){ ...... } } Class LoggingInterceptor{ //Catched defined method before process public void before(...xyz){ logger.info("INFO" + ...xyz); } //Catched defined method after processed public void after(...xyz){ logger.info("INFO" + ...xyz); } ..... }

PD: AOP será mejor, es DRY (No repetir) .


Si su aplicación sigue los principios de SOA, para cada servicio A tendrá los siguientes componentes:

  1. Un controlador
  2. Una implementación de servicio
  3. Un albacea
  4. Una Persistencia

Por lo tanto, hace la vida más fácil tener un aController.log aService.log aExecutor.log y aPersistance.log

Esta es una separación basada en capas, por lo que todas las clases de Remoting / REST / SOAP escribirán en aController.log

Todo su mecanismo de programación, servicio de backend, etc. escribirá en aService.log

Y todas las ejecuciones de tareas se escriben en un Executor.log y así sucesivamente.

Si tiene un ejecutor multiproceso, es posible que deba usar un acumulador de registros u otra técnica para alinear correctamente los mensajes de registro para varios subprocesos.

De esta manera, siempre tendrás 4 archivos de registro que no son mucho y no demasiado, te lo digo por experiencia que hace la vida realmente más fácil.


  • Crea un registrador por clase.
  • Si tiene dependencias que requieren el Registro de Commons (bastante probable) use el bridge de slf4j para el Registro de Commons. Crea una instancia de tus registradores (por clase) usando la interfaz de registro de Commons: private static final Log log = LogFactory.getLog(MyClass.class);
  • Manifieste este patrón en su IDE usando atajos. Yo uso las plantillas en vivo de IDEA para este propósito.
  • Proporcione información contextual a los hilos usando un NDC (hilo de pila local de cadenas) o un http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html (hilo de mapa local de String →?).

Ejemplos de plantillas:

private static final Log log = LogFactory.getLog($class$.class); // live template ''log'' if (log.isDebugEnabled()) log.debug(String.format("$string$", $vars$)); // live template ''ld'', ''lw'', ''le'' ...