6

I have a eclipse RCP application using slf4j/logback to catch all the log messages.

Right now I have the following file appender configured:

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>softmodeler_client.log</file>
    <append>true</append>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>[%date] %level: %logger - %m%n</pattern>
    </encoder>
</appender>

This writes the log file into the application installation directory.
Some customers do not permit write access in the installation directory.
In that case we redirect the workspace and configurations directory defining the following in the Applicationname.ini file:

-data
@user.home/AppData/Roaming/Applicationname/workspace
-configuration
@user.home/AppData/Roaming/Applicationname/configuration

Now I would like to configure the logback.xml like this, pointing the logfile to the writable workspace directory:

<file>${osgi.instance.area}softmodeler_client.log</file>

This results in a FileNotFoundException, because of the file:/ prefix of the osgi.instance.area system property. I did not find another property without the protocol.

My question is how can I configure logback to write into my workspace, without having to modify the logback.xml every time?

EDIT:
Maybe I can register a listener from where I can set some initial properties?
I would prefer to use an existing system property or programmatically pass a variable to the logging framework. The goal is, not having to configure an additional parameter/variable for every installation (since quite a few and might be missed during updates). Just somehow automatically always write the log file into the workspace directory.

flavio.donze
  • 7,432
  • 9
  • 58
  • 91

3 Answers3

1

How can I configure logback to write into my workspace, without having to modify the logback.xml everytime?

I would like to suggest you that if any user wants to use his own specific location to write his log file, then it will be best to use a properties file.

dataLocation.properties file have a location. It may be changed per user.

logpathfile = d://logFiles

Then this path will be read from a java file and it will be sent to logback.xml file.


For example, I am using a sessionid as parameter. It is sent to logback.xml from java file. Hope you can adjust it with your code.

LoggerBySessionId.java

/**
 * 2    * Logback: the reliable, generic, fast and flexible logging framework.
 * 3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
 * 4    *
 * 5    * This program and the accompanying materials are dual-licensed under
 * 6    * either the terms of the Eclipse Public License v1.0 as published by
 * 7    * the Eclipse Foundation
 * 8    *
 * 9    *   or (per the licensee's choosing)
 * 10   *
 * 11   * under the terms of the GNU Lesser General Public License version 2.1
 * 12   * as published by the Free Software Foundation.
 * 13
 */
package com.waze.rr_logger;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class LoggerBySessionId {

    String configFile = "logback.xml";

    public LoggerBySessionId() {
    }

    public LoggerBySessionId(String configFile) {
        this.configFile = configFile;
    }

    public void log(String sessionId, String content) throws JoranException {

        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator configurator = new JoranConfigurator();
        lc.reset();
        configurator.setContext(lc);
        configurator.doConfigure(configFile);

        Logger logger = LoggerFactory.getLogger(LoggerBySessionId.class);
        MDC.put("sessionId", sessionId); // this sessionId is sent to logback.xml
        logger.debug(content);
    }

    static void usage(String msg) {
        System.err.println(msg);
        System.err.println("Usage: java " + LoggerBySessionId.class.getName() + " configFile\n" + "   configFile a logback " +
                "configuration file");
        System.exit(1);
    }
}

logback.xml

<configuration>
    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
        <!-- in the absence of the class attribute, it is assumed that the
             desired discriminator type is
             ch.qos.logback.classic.sift.MDCBasedDiscriminator -->
        <discriminator>
            <key>userid</key>
            <defaultValue>no_session_id</defaultValue>
        </discriminator>
        <sift>
            <appender name="FILE-${sessionId}" class="ch.qos.logback.core.FileAppender">
                <file>${userid}.log</file>
                <append>true</append>
                <layout class="ch.qos.logback.classic.PatternLayout">
                    <pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</pattern>
                </layout>
            </appender>
            <appender name="FILE-${sessionId}" class="ch.qos.logback.core.FileAppender">
                <file>${userid}.log</file>
                <append>false</append>
                <layout class="ch.qos.logback.classic.PatternLayout">
                    <pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</pattern>
                </layout>
            </appender>
        </sift>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="SIFT" />
    </root>
</configuration>
SkyWalker
  • 28,384
  • 14
  • 74
  • 132
0

You should consider using a groovy-based logback configuration like this:

import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.FileAppender
import static ch.qos.logback.classic.Level.DEBUG

def FILENAME = "file:///home/jdoe/app.log".replace("file://", "")

appender("FILE", FileAppender) {
  file = "${FILENAME}"
  append = true
  encoder(PatternLayoutEncoder) {
    pattern = "[%date] %level: %logger - %m%n"
  }
}

root(DEBUG, ["FILE"])

You're propably going to need the groovy runtime as dependency:

compile 'org.codehaus.groovy:groovy-all:2.4.6'

I'm not into OSGI, but I'm pretty sure there's a way to retrieve that ${osgi.instance.area} property and remove "file://" as shown above since Groovy is a fully-fledged language.

AndreLDM
  • 2,117
  • 1
  • 18
  • 27
0
  1. In order to have your log in an IDE you could use a ConsoleAppender (System.out, System.err):

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>[%date] %level: %logger - %m%n</pattern>
    </encoder>
    </appender>
    
  2. You can try using multiple logback config files, as suggested here: Setting logback.xml path programmatically

  3. To define your own properties from a file you could write in logback config file:

    <property file="path/to/your.properties" />

    or

    <property resource="your.properties" />
    

    and then

    <file>${YOUR_PATH}softmodeler_client.log</file>

    where YOUR_PATH is a variable from your.properties file

  4. You can simply send your variable on execution:

    java -DYOUR_PATH="workspace" AppName

Community
  • 1
  • 1
hammelion
  • 351
  • 2
  • 13