Cambio dinámico del nivel de registro log4j

127

¿Cuáles son los diferentes enfoques para cambiar el nivel de registro log4j dinámicamente, para que no tenga que volver a implementar la aplicación? ¿Los cambios serán permanentes en esos casos?

Ravi
fuente
3
Pregunta actualizada para log4j2: stackoverflow.com/questions/23434252/…
slaadvak
1
TENGA EN CUENTA que (casi) todo en esta página es sobre log4j, no log4j2. Toda esta página está tan llena de confusión y dirección errónea que es INÚTIL. Vaya a stackoverflow.com/questions/23434252/… como recomienda @slaadvak.
Lambart

Respuestas:

86

Cambiar el nivel de registro es simple; modificar otras partes de la configuración planteará un enfoque más profundo.

LogManager.getRootLogger().setLevel(Level.DEBUG);

Los cambios son permanentes a través del ciclo de vida del Logger. En la reinicialización, la configuración se leerá y utilizará, ya que establecer el nivel en tiempo de ejecución no persiste el cambio de nivel.

ACTUALIZACIÓN: Si está utilizando Log4j 2, debe eliminar las llamadas setLevelsegún la documentación, ya que esto se puede lograr a través de clases de implementación.

Las llamadas a logger.setLevel () o métodos similares no son compatibles con la API. Las aplicaciones deben eliminar estos. Se proporciona una funcionalidad equivalente en las clases de implementación de Log4j 2, pero puede hacer que la aplicación sea susceptible a cambios en las partes internas de Log4j 2.

Aaron McIver
fuente
55
Solo para dependencias de tiempo de ejecuciónLogManager.getLogger(Class.forName("org.hibernate.util.JDBCExceptionReporter")).setLevel(Level.FATAL);
CelinHC el
8
Tenga en cuenta que la API log4j 2 no proporciona un método "setLevel".
ChrisCantrell
55
Pero esto solo establece el registrador raíz, ¿no? Si se establecen niveles individuales para los registradores en la raíz, la configuración del registrador raíz no tendrá ningún efecto en los LOGGER. ¿No tendríamos que hacer algo como root.getLoggerRepository (). GetCurrentCategories (), iterar sobre cada instancia del registrador y establecer NIVELES para cada registrador? @AaronMcIver
TheMonkWhoSoldHisCode
8
@ChrisCantrell Log4j 2 proporciona una manera de hacer esto , aunque no es tan simple.
CorayThan
2
Log4j2 se puede configurar para actualizar su configuración escaneando el archivo log4j2.xml (o equivalente) a intervalos determinados. Por ejemplo, <Estado de configuración = "advertir" monitorInterval = "5" name = "tryItApp" packages = "">
Kimball Robinson el
89

File Watchdog

Log4j puede ver el log4j.xmlarchivo en busca de cambios de configuración. Si cambia el archivo log4j, log4j actualizará automáticamente los niveles de registro de acuerdo con sus cambios. Consulte la documentación de org.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long) para más detalles. El tiempo de espera predeterminado entre verificaciones es de 60 segundos. Estos cambios serían persistentes, ya que cambia directamente el archivo de configuración en el sistema de archivos. Todo lo que necesita hacer es invocar DOMConfigurator.configureAndWatch () una vez.

Precaución: el método configureAndWatch no es seguro para su uso en entornos J2EE debido a una fuga de hilo

JMX

Otra forma de establecer el nivel de registro (o la reconfiguración en general) log4j es mediante JMX. Log4j registra sus registradores como JMX MBeans. Usando las consolas MBeanServer de los servidores de aplicaciones (o jconsole.exe de JDK) puede reconfigurar cada registrador individual. Estos cambios no son persistentes y se restablecerán a la configuración establecida en el archivo de configuración después de reiniciar su aplicación (servidor).

Salir adelante por sí mismo

Según lo descrito por Aaron, puede establecer el nivel de registro mediante programación. Puede implementarlo en su aplicación de la forma en que le gustaría que sucediera. Por ejemplo, podría tener una GUI donde el usuario o administrador cambie el nivel de registro y luego llame a los setLevel()métodos en el registrador. Si persiste la configuración en algún lugar o no, depende de usted.

mhaller
fuente
8
Una advertencia con respecto al enfoque log4j watchdog: "Debido a que configureAndWatch lanza un hilo de watchdog separado, y porque no hay forma de detener este hilo en log4j 1.2, el método configureAndWatch no es seguro para su uso en entornos J2EE donde las aplicaciones se reciclan". Referencia: Preguntas frecuentes de Log4J
Somu
Si tuviera que usar la funcionalidad configureAndWatch de Log4j, podría detener ese hilo de vigilancia en el método @PostDestroy de EJB (eso es un indicador suficientemente bueno de cuándo se está cerrando el contenedor) ¿Eso es todo? ¡O hay algo más que me falta ...!
robin bajaj
lo siento, quería decir @PreDestroy método
Bajaj robin
" Log4j registra sus registradores como JMX MBeans ". Mi servlet usa log4j 1.2 No veo ningún MBeans log4j.
Abdull
Todo lo que necesita hacer es invocar DOMConfigurator.configureAndWatch () una vez. Cómo puedo conseguir esto ?
gstackoverflow
5

Log4j2 se puede configurar para actualizar su configuración escaneando el archivo log4j 2 .xml (o equivalente) a intervalos determinados. Simplemente agregue el parámetro " monitorInterval " a su etiqueta de configuración. Consulte la línea 2 del archivo de ejemplo log4j 2 .xml, que le dice a log4j que vuelva a escanear su configuración si han pasado más de 5 segundos desde el último evento de registro.

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

Hay pasos adicionales para hacer que esto funcione si está implementando en una instancia de tomcat, dentro de un IDE o cuando usa el arranque de primavera. Esto parece algo fuera de alcance aquí y probablemente merece una pregunta por separado.

Kimball Robinson
fuente
@vsingh, ¿está implementando dentro de arranque de primavera, tomcat o un contenedor o con un IDE? A veces puede haber pasos adicionales en esos casos (no es culpa de log4j2); básicamente, la aplicación no puede ver el cambio del archivo porque ha sido copiado a otra ubicación por un marco o herramienta.
Kimball Robinson
Hola, probé esto en Jboss6.4 y actualicé el archivo de configuración log4j2 en la ubicación (dentro del archivo .war) donde la aplicación puede ver el archivo. Sin embargo, todavía no funcionó. ¿Cualquier sugerencia?
MidTierDeveloper
3

Esta respuesta no lo ayudará a cambiar el nivel de registro dinámicamente, debe reiniciar el servicio, si está bien reiniciando el servicio, utilice la solución a continuación

Hice esto para cambiar el nivel de registro log4j y funcionó para mí, no he referido ningún documento. Utilicé este valor de propiedad del sistema para establecer mi nombre de archivo de registro. También utilicé la misma técnica para establecer el nivel de registro, y funcionó

pasó esto como parámetro JVM (uso Java 1.7)

Lo sentimos, esto no cambiará dinámicamente el nivel de registro, requiere un reinicio del servicio

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

en el archivo log4j.properties, agregué esta entrada

log4j.rootLogger=${logging.level},file,stdout

Lo intenté

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

Todo funcionó. ¡espero que esto ayude!

Tengo estas siguientes dependencias en mi pom.xml

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>
Anandkumar
fuente
2
Lo que haya mencionado parece estar bien, pero la pregunta es sobre cambiar dinámicamente el nivel de registro.
Azim
Para hacer esto, debe reiniciar el servicio. Esto no cambia los niveles de registro dinámicamente.
kk.
2

Con log4j 1.x, encuentro que la mejor manera es usar un DOMConfigurator para enviar uno de un conjunto predefinido de configuraciones de registro XML (por ejemplo, uno para uso normal y otro para depuración).

Hacer uso de estos se puede hacer con algo como esto:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

Simplemente llame a esto con el nombre de configuración apropiado y asegúrese de colocar las plantillas en el classpath.

ISparkes
fuente
¿Cuál es el punto de activación de este método? ¿Cómo sabe que este método debe ser invocado cada vez que hay un cambio en la configuración de log4j?
Pregunta el
Todavía no entiendo lo que quieres decir "a pedido". ¿Puedes mostrar un fragmento donde conectas este método?
pregunta el
2
Aquí tienes: este es un fragmento del controlador donde lo usamos. Tenemos una página de administración con algunos enlaces para reconfigurar dinámicamente el registro, que luego obtiene un GET al enlace / admin / setLogLevel? Level = Error y luego lo detectamos en el controlador de esta manera @RequestMapping (value = "setLogLevel", method = RequestMethod.GET) public ModelAndView setLogLevel (@RequestParam (value = "level", required = true) String level) {Log4jReconfigurator.reconfigureExisting (level);
ISparkes
Entonces, "a pedido" significa "cuando el usuario hace clic en el botón" en mi caso
ISparkes
Ah, te tengo. Por lo tanto, su consola de administración debe realizar una solicitud para invocar este método.
pregunta el
0

He utilizado este método con éxito para reducir la verbosidad de los registros "org.apache.http":

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);
Thomas Bernardin
fuente
0

Para log4j 2 API, puede usar

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));
Mohamed Stitane
fuente
-1

Si desea cambiar el nivel de registro de todos los registradores, utilice el siguiente método. Esto enumerará todos los registradores y cambiará el nivel de registro a un nivel dado. Asegúrese de que NO tiene una log4j.appender.loggerName.Threshold=DEBUGpropiedad establecida en su log4j.propertiesarchivo.

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}
kk.
fuente
-3

Puede usar el siguiente fragmento de código

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));
user2606570
fuente
Tengo que intentarlo.
user2045474