with springprofile mkyong log example error baeldung java logging io logback flush

java - springprofile - spring log error



El apilador de archivos de Logback no se vacĂ­a inmediatamente (3)

Decidí llevar mi solución a todos. Permítanme aclarar primero que esto no es un problema de logback y no es un problema de JRE. Esto se describe en el javadoc y, en general, no debería ser un problema hasta que te encuentres con algunas soluciones de integración de la vieja escuela sobre la sincronización de archivos.

Entonces, este es un apéndice de inicio de sesión implementado para descargar inmediatamente:

public class ImmediateFileAppender<E> extends RollingFileAppender<E> { @Override public void openFile(String file_name) throws IOException { synchronized (lock) { File file = new File(file_name); if (FileUtil.isParentDirectoryCreationRequired(file)) { boolean result = FileUtil.createMissingParentDirectories(file); if (!result) { addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]"); } } ImmediateResilientFileOutputStream resilientFos = new ImmediateResilientFileOutputStream(file, append); resilientFos.setContext(context); setOutputStream(resilientFos); } } @Override protected void writeOut(E event) throws IOException { super.writeOut(event); } }

Esta es la clase de utilidad de flujo de salida correspondiente. Debido a algunos métodos y campos de ResilientOutputStreamBase original que se suponía que se extenderían inicialmente tenían modificadores de acceso empaquetados, tuve que extender OutputStream lugar y copiar el resto y sin cambios de ResilientOutputStreamBase y ResilientFileOutputStream a este nuevo. Solo muestro el código cambiado:

public class ImmediateResilientFileOutputStream extends OutputStream { // merged code from ResilientOutputStreamBase and ResilientFileOutputStream protected FileOutputStream os; public FileOutputStream openNewOutputStream() throws IOException { return new FileOutputStream(file, true); } @Override public void flush() { if (os != null) { try { os.flush(); os.getFD().sync(); // this''s make sence postSuccessfulWrite(); } catch (IOException e) { postIOFailure(e); } } } }

Y finalmente la configuración:

<appender name="FOR_INTEGRATION" class="package.ImmediateFileAppender"> <file>/somepath/for_integration.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>for_integration.log.%i</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern> <immediateFlush>true</immediateFlush> </encoder> </appender>

Para algunas circunstancias, necesito forzar el enjuague en el appender de archivos de logback inmediatamente. He encontrado en los documentos que esta opción está habilitada de forma predeterminada. Misteriosamente esto no funciona. Como veo en las fuentes, el proceso subyacente implica BufferedOutputSream correctamente. ¿Hay algún problema con BufferedOutputSream.flush() ? Probablemente esto esté más bien relacionado con el problema del enrojecimiento.

Actualización : encontré el problema en Windows XP Pro SP 3 y en la versión 5.3 de Red Hat Enterprise Linux Server (Tikanga). Usé estas libs:

jcl-over-slf4j-1.6.6.jar logback-classic-1.0.6.jar logback-core-1.0.6.jar slf4j-api-1.6.6.jar

logback.xml es:

<configuration> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/somepath/file.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>file.log.%i</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="FILE"/> </root> </configuration>

Actualizado: proporcionaría una prueba unitaria, pero eso no parece tan simple. Déjame describir el tema más claramente.

  1. Se produjo un evento de registro
  2. El evento pasa al apéndice de archivo
  3. El evento se serializa con un patrón definido
  4. El mensaje de evento serializado se pasa al appender del archivo y está a punto de escribirse en la secuencia de salida
  5. Se finalizó la escritura en la secuencia, la secuencia de salida se vació (he comprobado la implementación). Tenga en cuenta que immidiateFlush es verdadero de manera predeterminada, por lo que el método flush() se invoca explícitamente
  6. ¡Ningún resultado en el archivo!

Un poco más tarde, cuando fluyó un búfer subyacente, el evento aparece en el archivo. Entonces, la pregunta es: ¿el flujo de salida garantiza una descarga inmediata?

Para ser sincero, ya resolví esto implementando mi propio ImmediateRollingFileAppender que aprovecha la facilidad de FileDescriptor para la sincronización inmediata. Cualquier persona interesada puede seguir esto .

Entonces este no es un problema de logback.


Has hecho un buen trabajo, bien hecho. Aquí hay una propuesta para hacerlo más conciso:

public class ImmediateFlushPatternLayoutEncoder extends PatternLayoutEncoder { public void doEncode(ILoggingEvent event) throws IOException { super.doEncode(event); if (isImmediateFlush()) { if (outputStream.os instanceof FileOutputStream) { ((FileOutputStream) outputStream.os).getFD().sync(); } } } }

En la configuración, debe usar ese codificador específico:

<encoder class="ch.qos.logback.core.recovery.ImmediateFlushPatternLayoutEncoder">

No probado. Probablemente habrá problemas de visibilidad con los campos, requiriendo usar el paquete logback ch.qos.logback.core.recovery .

Por cierto, lo invito a enviar un informe de error a logback para obtener una opción adicional immediateSync en LayoutWrappingEncoder .


Muchos middleware de monitoreo encuentran los nuevos eventos mediante verificación de actualizaciones de sello de tiempo y tamaño de archivo. Por este motivo, es necesario programar el momento en que se registra el evento, la marca de tiempo y el tamaño del archivo.

Esta clase podría resolverlo

public class MyFileAppender<E> extends FileAppender<E> { protected void writeOut(E event) throws IOException { super.writeOut(event); ResilientFileOutputStream resilientFos = (ResilientFileOutputStream) super.getOutputStream(); resilientFos.flush(); resilientFos.getChannel().force(true); } }

Establezca la clase MyFileAppender para appender.

<appender name="FILE" class="MyFileAppender">

Espero que logback solucione este problema.