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:
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
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:
- Un controlador
- Una implementación de servicio
- Un albacea
- 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'' ...