JavaRush /Blog Java /Random-ES /Iniciar sesión en Java: ¿qué, cómo, dónde y con qué?

Iniciar sesión en Java: ¿qué, cómo, dónde y con qué?

Publicado en el grupo Random-ES
¡Hola a todos, comunidad JavaRush! Hoy hablaremos sobre el registro de Java:
  1. ¿Qué es esto? ¿Por qué? ¿En qué casos es mejor utilizarlo y en qué casos no?
  2. ¿Cuáles son las diferentes implementaciones de inicio de sesión en Java y qué debemos hacer con esta diversidad?
  3. Niveles de registro. Analicemos qué es el appender y cómo configurarlo correctamente.
  4. Registrar nodos y cómo configurarlos correctamente para que todo funcione como queremos.
Este material está destinado a un público amplio. Quedará claro tanto para aquellos que recién se están familiarizando con Java como para aquellos que ya están trabajando, pero solo lo descubrieron con logger.info(“log something”); Let's Go.

¿Por qué es necesario el registro?

Veamos casos reales en los que el registro resolvería el problema. Aquí hay un ejemplo de mi trabajo. Hay puntos de aplicación que se integran con otros servicios. Utilizo el registro de estos puntos como “coartada” : si la integración no funciona, será fácil determinar de qué lado se originó el problema. También es recomendable registrar información importante que se guarda en la base de datos. Por ejemplo, crear un usuario administrador. Esto es exactamente lo que sería bueno registrar.

Herramientas de registro de Java

Tala: ¿qué, cómo, dónde y con qué?  - 2Las soluciones conocidas para iniciar sesión en Java incluyen:
  • log4j
  • JULIO - java.util.logging
  • JCL - tala de bienes comunes de Yakarta
  • Volver a iniciar sesión
  • SLF4J: fachada de registro simple para Java
Echemos un vistazo rápido a cada uno de ellos, y en la parte práctica del material tomaremos como base la conexión Slf4j - log4j . Esto puede parecer extraño ahora, pero no te preocupes: al final del artículo todo quedará claro.

Sistema.err.println

Inicialmente, por supuesto, estaba System.err.println (salida de registro a la consola). Todavía se utiliza para obtener rápidamente un registro durante la depuración. Por supuesto, no es necesario hablar de ninguna configuración aquí, así que recordémoslo y sigamos adelante.

Log4j

Esta ya era una solución completa, que se creó a partir de las necesidades de los desarrolladores. Resultó ser una herramienta realmente interesante de utilizar. Debido a diversas circunstancias, esta solución nunca llegó al JDK, lo que molestó enormemente a toda la comunidad. log4j tenía opciones de configuración para que el registro pudiera activarse en un paquete com.example.typey desactivarse en un subpaquete com.example.type.generic. Esto hizo posible separar rápidamente lo que debía registrarse de lo que no era necesario. Es importante señalar aquí que existen dos versiones de log4j: 1.2.x y 2.x.x, que son incompatibles entre sí . log4j agregó un concepto como appender , es decir, una herramienta con la que se registran y diseñan los registros: formateo de registros. Esto le permite registrar sólo lo que necesita y cómo lo necesita. Hablaremos más sobre appender un poco más tarde.

JULIO - java.util.logging

Una de las ventajas clave es la solución: JUL está incluido en el JDK (kit de desarrollo de Java). Desafortunadamente, durante su desarrollo no se tomó como base el popular log4j, sino una solución de IBM, que influyó en su desarrollo. De hecho, de momento existe JUL, pero nadie lo usa. Del “regular”: en JUL los niveles de registro son diferentes a los de Logback, Log4j, Slf4j, y esto empeora el entendimiento entre ellos. Crear un registrador es más o menos similar. Para hacer esto necesitas importar:
java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
El nombre de la clase se pasa específicamente para saber de dónde proviene el registro. Desde Java 8, es posible pasar Supplier<String>. Esto ayuda a contar y crear una cadena solo en el momento en que realmente se necesita, y no siempre, como era antes. Sólo con el lanzamiento de Java 8 los desarrolladores resolvieron problemas importantes, después de lo cual JUL se volvió realmente utilizable. Es decir, métodos con argumentos Supplier<String> msgSuppliercomo se muestra a continuación:
public void info(Supplier<String> msgSupplier) {
   log(Level.INFO, msgSupplier);
}

JCL - tala de bienes comunes de Yakarta

Debido al hecho de que durante mucho tiempo no hubo un estándar industrial en el registro y hubo un período en el que muchas personas crearon su propio registrador personalizado, decidieron lanzar JCL, un contenedor común que se usaría sobre otros. ¿Por qué? Cuando se agregaron algunas dependencias al proyecto, podrían usar un registrador diferente al registrador del proyecto. Debido a esto, se agregaron transitivamente al proyecto, lo que creó verdaderos problemas al intentar armarlo todo. Desafortunadamente, el contenedor tenía una funcionalidad muy pobre y no introdujo ninguna adición. Probablemente sería conveniente que todos usaran JCL para hacer su trabajo. Pero en realidad no funcionó así, por lo que utilizar JCL no es una buena idea en este momento.

Volver a iniciar sesión

Qué espinoso es el camino del código abierto... Logback fue escrito por el mismo desarrollador que log4j para crear un sucesor. La idea era la misma que la de log4j. Las diferencias fueron que en el inicio de sesión:
  • desempeño mejorado;
  • soporte nativo agregado para slf4j;
  • La opción de filtrado se ha ampliado.
De forma predeterminada, el inicio de sesión no requiere ninguna configuración y registra todos los registros desde el nivel DEBUG y superior. Si es necesaria la configuración, se puede realizar mediante la configuración xml:
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

SLF4J: fachada de registro simple para Java

Alrededor de 2006, uno de los padres fundadores de log4j abandonó el proyecto y creó slf4j (Simple Logging Facade for Java), un contenedor para log4j, JUL, common-loggins y logback. Como puede ver, el progreso ha llegado al punto en que crearon un contenedor encima del contenedor... Además, se divide en dos partes: la API, que se utiliza en la aplicación, y la implementación, que se agrega como dependencias separadas para cada tipo de registro. Por ejemplo, slf4j-log4j12.jar, slf4j-jdk14.jar. Basta con conectar la implementación correcta y listo: todo el proyecto funcionará con ella. Slf4j admite todas las funciones nuevas, como el formato de cadenas para el registro. Había ese problema antes. Digamos que hay una entrada de registro:
log.debug("User " + user + " connected from " + request.getRemoteAddr());
userHay una conversión implícita en el objeto user.toString()debido a la concatenación de cadenas, y esto lleva tiempo, lo que ralentiza el sistema. Y todo está bien si depuramos la aplicación. Los problemas comienzan si el nivel de registro para esta clase es INFO y superior. Es decir, este registro no se debe escribir y tampoco se debe realizar la concatenación de cadenas. En teoría, esto debería haberlo decidido la propia biblioteca de registro. Además, este resultó ser el mayor problema de la primera versión de log4j. No ofrecieron una solución normal, pero sugirieron hacerlo así:
if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
Es decir, en lugar de una línea de registro, sugirieron escribir 3(!). El registro debería minimizar los cambios en el código, y tres líneas contradecían claramente el enfoque general. slf4j no tuvo problemas de compatibilidad con JDK y API, por lo que inmediatamente surgió una hermosa solución:
log.debug("User {} connected from {}", user, request.getRemoteAddr());
donde {}denota inserciones de argumentos que se pasan en el método. Es decir, el primero {}corresponde a user, el segundo {}- request.getRemoteAddr(). Debido a esto, solo si el nivel de registro permite grabar en el registro, este mensaje se puede concatenar en uno solo. Después de esto, SJF4J rápidamente ganó popularidad y actualmente es la mejor solución. Por lo tanto, consideraremos el registro usando el ejemplo de un paquete slf4j-log4j12.

¿Qué se debe registrar?

Por supuesto, no deberías registrar todo. A veces esto es innecesario e incluso peligroso. Por ejemplo, si se comprometen los datos personales de alguien y de alguna manera salen a la luz, habrá verdaderos problemas, especialmente en proyectos orientados hacia Occidente. Pero también hay algo que es obligatorio iniciar sesión :
  1. Inicio/fin de la aplicación. Necesitamos saber que la aplicación realmente se inició como esperábamos y finalizó como esperábamos.
  2. Preguntas de seguridad. Aquí sería bueno registrar intentos de adivinar contraseñas, registrar inicios de sesión de usuarios importantes, etc.
  3. Algunos estados de la aplicación . Por ejemplo, la transición de un estado a otro en un proceso empresarial.
  4. Alguna información para la depuración , con un nivel adecuado de registro.
  5. Algunos scripts SQL. Hay casos reales en los que esto es necesario. Nuevamente, ajustando hábilmente los niveles, se pueden lograr excelentes resultados.
  6. Los subprocesos ejecutados (Thread) se pueden registrar en los casos en que se verifica el funcionamiento correcto.

Errores de registro populares

Hay muchos matices, pero aquí hay algunos errores comunes:
  1. Exceso de tala. No deberías registrar todos los pasos que, en teoría, podrían ser importantes. Hay una regla: los registros no pueden cargar el rendimiento en más del 10%. De lo contrario habrá problemas de rendimiento.
  2. Registrar todos los datos en un solo archivo. Esto hará que leer/escribir en él sea muy difícil en cierto momento, sin mencionar que existen límites de tamaño de archivo en ciertos sistemas.
  3. Usar niveles de registro incorrectos. Cada nivel de registro tiene límites claros y debe respetarse. Si el límite es vago, pueden acordar qué nivel utilizar.

Niveles de registro

x: visible
FATAL ERROR ADVERTIR INFORMACIÓN DEPURAR RASTRO TODO
APAGADO
FATAL X
ERROR X X
ADVERTIR X X X
INFORMACIÓN X X X X
DEPURAR X X X X X
RASTRO X X X X X X
TODO X X X X X X X
¿Qué son los niveles de registro? Para clasificar de alguna manera los troncos, era necesario dar ciertas designaciones y distinciones. Para ello se introdujeron niveles de registro. El nivel se establece en la aplicación. Si una entrada pertenece a un nivel inferior al designado, no se ingresa en el registro. Por ejemplo, tenemos registros que se utilizan para depurar la aplicación. En el trabajo de producción normal (cuando la aplicación se utiliza para el fin previsto), dichos registros no son necesarios. Por lo tanto, el nivel de registro será mayor que el de depuración. Veamos los niveles usando log4j como ejemplo. Otras soluciones, excepto JUL, utilizan los mismos niveles. Aquí están en orden decreciente:
  • APAGADO: no se escriben registros, se ignorarán todos;
  • FATAL: un error después del cual la aplicación ya no podrá funcionar y se detendrá, por ejemplo, error de falta de memoria de JVM;
  • ERROR: La tasa de error cuando hay problemas que deben resolverse. El error no detiene la aplicación en su totalidad. Otras consultas pueden funcionar correctamente;
  • ADVERTENCIA: Indica registros que contienen una advertencia. Ocurrió una acción inesperada, a pesar de ello el sistema resistió y completó la solicitud;
  • INFO: un registro que registra acciones importantes en la aplicación. Estos no son errores, no son advertencias, son acciones esperadas del sistema;
  • DEBUG: registros necesarios para depurar la aplicación. Para garantizar que el sistema haga exactamente lo que se espera de él, o para describir la acción del sistema: "el método 1 comenzó a funcionar";
  • TRACE: registros de menor prioridad para la depuración, con el nivel de registro más bajo;
  • TODOS: nivel en el que se registrarán todos los registros del sistema.
Resulta que si el nivel de registro INFO está habilitado en algún lugar de la aplicación, se registrarán todos los niveles, desde INFO hasta FATAL. Si el nivel de registro es FATAL, solo se registrarán los registros con este nivel.

Grabación y envío de registros: Appender

Consideraremos este proceso usando log4j como ejemplo: proporciona amplias oportunidades para grabar/enviar registros:
  • para escribir en una solución de archivos DailyRollingFileAppender ;
  • recibir datos en la consola de la aplicación: ConsoleAppender ;
  • escribir registros en la base de datos - JDBCAppender ;
  • para controlar la transmisión vía TCP/IP - TelnetAppender ;
  • para garantizar que el registro no afecte el rendimiento: AsyncAppender .
Hay varias otras implementaciones: la lista completa se puede encontrar aquí . Por cierto, si el apéndice requerido no está disponible, esto no es un problema. Puede escribir su propio appender implementando la interfaz Appender , que solo acepta log4j.

Nodos de registro

Para la demostración usaremos la interfaz slf4j y la implementación de log4j. Crear un registrador es muy simple: necesita escribir lo siguiente en una clase llamada MainDemo, en la cual se realizará el registro:
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
Esto creará un registrador para nosotros. Para realizar una entrada de registro, puede utilizar muchos métodos que indican en qué nivel se realizarán las entradas. Por ejemplo:
logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find log4j.properties. Please, provide them");
logger.error("Connection refused to host = {}", host);
Aunque aprobamos la clase, al final lo que está escrito es el nombre completo de la clase con paquetes. Esto se hace para que luego pueda dividir el registro en nodos y configurar un nivel de registro y un anexo para cada nodo. Por ejemplo, el nombre de la clase: com.github.romankh3.logginglecture.MainDemo- en ella se creó un registrador. Y así es como se puede dividir en nodos de registro. El nodo principal es el RootLogger nulo . Este es el nodo que recibe todos los registros de toda la aplicación. El resto se puede representar como se muestra a continuación: Tala: ¿qué, cómo, dónde y con qué?  - 4Los appenders configuran su trabajo específicamente en los nodos de registro. Ahora, usando log4j.properties como ejemplo , veremos cómo configurarlos.

Configuración paso a paso de Log4j.properties

Ahora configuraremos todo paso a paso y veremos qué se puede hacer:
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
Esta línea dice que estamos registrando un appender de CONSOLA que usa la implementación org.apache.log4j.ConsoleAppender. Este appender escribe datos en la consola. A continuación, registremos otro agregador que escribirá en un archivo:
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
Es importante tener en cuenta que aún será necesario configurar los apéndices. Una vez que ya tengamos agregados registrados, podemos determinar qué nivel de registro habrá en los nodos y qué agregados se utilizarán.

log4j.rootLogger=DEPURACIÓN, CONSOLA, ARCHIVO

  • log4j.rootLogger significa que configuraremos el nodo principal, que contiene todos los registros;
  • después del signo igual, la primera palabra indica a qué nivel y superior se registrarán los registros (en nuestro caso, esto es DEBUG);
  • luego, después de la coma, se indican todos los apéndices que se utilizarán.
Para configurar un nodo de registro específico, debe utilizar la siguiente entrada:
log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
donde log4j.logger.se usa para configurar un nodo específico, en nuestro caso es com.github.romankh3.logginglecture. Y ahora hablemos de configurar el appender de CONSOLA:
# CONSOLE appender customisation
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
Aquí vemos que podemos establecer el nivel desde el cual se procesará el appender. Situación real: el nodo de registro recibió un mensaje con el nivel de información y lo pasó al agregador que tiene asignado, pero el agregador, con el nivel de advertencia y superior, aceptó este registro, pero no hizo nada con él. A continuación, debe decidir qué plantilla habrá en el mensaje. Estoy usando PatternLayout en el ejemplo, pero existen muchas soluciones. No serán revelados en este artículo. Un ejemplo de configuración de un agregador de ARCHIVO:
# File appender customisation
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
Aquí puede configurar en qué archivo se escribirán los registros, como se puede ver en
log4j.appender.FILE.File=./target/logging/logging.log
La grabación pasa al archivo logging.log. Para evitar problemas con el tamaño del archivo, puedes establecer el máximo: en este caso, 1 MB. MaxBackupIndex: indica cuántos archivos de este tipo habrá. Si se crea más de este número, se eliminará el primer archivo. Para ver un ejemplo real en el que se configura el registro, puede ir al repositorio abierto en GitHub.

Consolidemos el resultado.

Intente hacer todo lo descrito usted mismo:
  • Cree su propio proyecto similar al del ejemplo anterior.
  • Si tiene conocimientos sobre el uso de Maven, lo usaremos; si no, aquí hay un enlace a un artículo que describe cómo conectar la biblioteca.

resumámoslo

  1. Hablamos de qué soluciones hay en Java.
  2. Casi todas las bibliotecas de registro conocidas fueron escritas bajo el control de una sola persona :D
  3. Aprendimos qué se debe registrar y qué no.
  4. Descubrimos los niveles de registro.
  5. Nos familiarizamos con los nodos de registro.
  6. Analizamos qué es un apéndice y para qué sirve.
  7. Configuramos el archivo log4j.proterties paso a paso.

Materiales adicionales

  1. JavaRush: registro. Desenrollar una bola de stectrace
  2. JavaRush: conferencia sobre registradores
  3. Habr: registro de Java. Hola Mundo
  4. Habr: Registro de Java: la historia de una pesadilla
  5. Youtube: cursos de Golovach. Inicio sesión. Parte 1 , Parte 2 , Parte 3 , Parte 4
  6. Log4j: añadido
  7. Log4j: diseño
Vea también mis otros artículos:
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION