4

I have a question regarding Logback.

Short version

If the creation of an appender fails (for example permission denied), how do I explicitly re-attempt to create it when the problems with the permissions are resolved. I am using XML configuration. I would like to do this without re-starting my process.

Longer version

I am using Logback on Android (logback-android).

I am logging to a directory on the external storage, which means that if the user connects the device to the PC and enables mass-storage, the file system of the directory will be unmounted.

If the application is started, while the directory is not available, I inform the user but since the loggers are defined as static fields ...

private static final Logger LOG = LoggerFactory.getLogger(MyApplication.class);

... Logback attempts to create the appender anyway when my classes are loaded by the classloader and fails.

Because of how Android works, the application process continues running even when the user leaves all screens of my application (for example goes to the home screen) and so the appender will never be re-attempted to be created.

Is there any way to reset the appender from the config? If so, I could attempt to reset Logback if necessary whenever the user enters the initial screen of my application.

I tried to stop it using ...

LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
if (loggerContext != null)
    loggerContext.stop();

... which seems to work fine but I don't seem to be able to re-start it:

loggerContext.start()

This does not seem to re-create the appender.

Many thanks in advance for help.

MartinCz
  • 528
  • 4
  • 13

2 Answers2

2

Restarting the appender can be achieved by reloading LogBack's configuration. In my case I had the configuration in an XML file so I used something along the lines:

// reset the default context (which may already have been initialized)
// since we want to reconfigure it
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
lc.reset();

JoranConfigurator config = new JoranConfigurator();
config.setContext(lc);

try {
  config.doConfigure("/path/to/config.xml");
} catch (JoranException e) {
  e.printStackTrace();
}
MartinCz
  • 528
  • 4
  • 13
1

I had exactly the same problem. I keep loggers as static variables thus had to keep them through a reset. The solution is below:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
// Copy current loggers, necessary to keep logging.
List<LoggerContextListener> loggers = lc.getCopyOfListenerList();
lc.reset();
JoranConfigurator config = new JoranConfigurator();
config.setContext(lc);

try {
    // Context ctx;
    InputStream inputStream = ctx.getAssets().open("logback.xml");
    config.doConfigure(inputStream);
    for (LoggerContextListener l : loggers) {
        lc.addListener(l);  // restore loggers
    }
} catch (JoranException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
log.info("logger reset");

The assets/logback.xml below:

<configuration>
    <property name="EXT_CACHE_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/cache"/>
    <!-- Create a logcat appender -->
    <appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
    <encoder>
        <pattern>%msg%n</pattern>
    </encoder>
    </appender>

    <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${EXT_CACHE_DIR}/logs/current.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!-- rollover hourly -->
        <fileNamePattern>${EXT_CACHE_DIR}/logs/%d{yyyy-MM-dd_HH,UTC}.%i.log.gz</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy
            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
            <maxFileSize>100KB</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
        <pattern>%-5relative %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36}: %msg%n</pattern>
    </encoder>
    </appender>

    <root level="DEBUG">
    <appender-ref ref="logcat" />
    <appender-ref ref="ROLLING" />
    </root>
</configuration>

The problem I've encountered is: the file appender doesn't initialize.

Paweł Szczur
  • 5,484
  • 3
  • 29
  • 32