Skip to content
Tony Trinh edited this page May 17, 2013 · 41 revisions

Release Snapshot

Overview

logback-android brings the power of logback to Android. logback is a reliable, generic, fast, and flexible logging library for Java applications.

Runs on Android 2.1 or higher.

The current version is 1.0.10-2.

Quick Start

  1. Add logback-android and slf4j-api to your project class path.
  2. Configure logback-android using an XML file or in-code statements. Otherwise, logging is silently disabled.
  3. Use slf4j-api in your application to write logging statements as shown in the example below.

Example:

package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.os.Bundle;
import android.app.Activity;

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // SLF4J
    Logger LOG = LoggerFactory.getLogger(MainActivity.class);
    LOG.info("hello world");
  }
}

Download

OR Maven users can simply add these dependencies to pom.xml:

<dependency>
  <groupId>com.github.tony19</groupId>
  <artifactId>logback-android-core</artifactId>
  <version>1.0.10-2</version>
</dependency>
<dependency>
  <groupId>com.github.tony19</groupId>
  <artifactId>logback-android-classic</artifactId>
  <version>1.0.10-2</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.5</version>
</dependency>

Configuration via XML

logback-android can be configured simply by creating assets/logback.xml, containing configuration XML. This file is read automatically upon loading the first logger from your code. Additional code configuration is not necessary.

Example 1: Basic configuration (single destination)

<configuration>
  <!-- Create a file appender for a log in the application's data directory -->
  <appender name="file" class="ch.qos.logback.core.FileAppender">
    <file>/data/data/com.example/files/log/foo.log</file>
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>  
  </appender>
  
  <!-- Write INFO (and higher-level) messages to the log file -->
  <root level="INFO">
    <appender-ref ref="file" />
  </root>
</configuration>

Example 2: Advanced configuration (multiple destinations)

<configuration>
  <property name="LOG_DIR" value="/data/data/com.example/files" />

  <!-- Create a logcat appender -->
  <appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
    <encoder>
      <pattern>%msg</pattern>
    </encoder>
  </appender>

  <!-- Create a file appender for TRACE-level messages -->
  <appender name="TraceLog" class="ch.qos.logback.core.FileAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>TRACE</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    
    <file>${LOG_DIR}/trace.log</file>
    
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>  
  </appender>

  <!-- Create a file appender for DEBUG-level messages -->
  <appender name="DebugLog" class="ch.qos.logback.core.FileAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>DEBUG</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    
    <file>${LOG_DIR}/debug.log</file>
    
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <!-- Write TRACE messages from class A to its own log -->
  <logger name="com.example.A" level="TRACE">
    <appender-ref ref="TraceLog" />
  </logger>
  
  <!-- Write DEBUG messages from class B to its own log -->
  <logger name="com.example.B" level="DEBUG">
    <appender-ref ref="DebugLog" />
  </logger> 

  <!-- Write INFO (and higher-level) messages to logcat -->
  <root level="INFO">
    <appender-ref ref="logcat" />
  </root>
</configuration>

AndroidManifest.xml

logback-android also supports configuration XML within your application's AndroidManifest.xml (requires setting up your initialization search path). Simply put the configuration XML inside the <manifest>/<logback> element as shown in the example below.

Example:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <logback>
        <configuration>
          <appender
              name="LOGCAT"
              class="ch.qos.logback.classic.android.LogcatAppender" >
              <tagEncoder>
                  <pattern>%logger{0}</pattern>
              </tagEncoder>
              <encoder>
                  <pattern>[ %thread ] %msg%n</pattern>
              </encoder>
          </appender>

          <root level="WARN" >
              <appender-ref ref="LOGCAT" />
          </root>
        </configuration>
    </logback>

</manifest>
Android Lint Preferences

If you enter configuration XML in AndroidManifest.xml, the Android SDK r21+ emits an error message by default due to the android namespace prefix missing from the logback-android configuration elements. To resolve this, change the Severity level for MissingPrefix in your project's Android Lint preferences from Eclipse.

Initialization search path

Even though assets/logback.xml is the first configuration loaded, this file could include other configuration files from within your JAR or from the host filesystem. This is achieved with the <includes> tag, containing a list of optional <include> tags (i.e., no error is thrown for nonexistent resources/files). The first <include> tag that points to an existent resource/file causes the remainder of the list to be ignored.

Example:

<configuration>
  <includes>
    <include file="/sdcard/foo.xml"/>
    <include resource="assets/config/test.xml"/>
    <include resource="AndroidManifest.xml"/>
  </includes>
</configuration>

Prior to v1.0.8-1, the initialization search path was hard-coded, and that can be recreated with this configuration:

<configuration>
  <includes>
    <include file="/sdcard/logback/logback-test.xml"/>
    <include file="/sdcard/logback/logback.xml"/>
    <include resource="AndroidManifest.xml"/>
    <include resource="assets/logback-test.xml"/>
    <include resource="assets/logback.xml"/>
  </includes>
</configuration>

Configuration in Code

If you prefer code-based configuration instead of the XML method above, you can use the logback classes directly to initialize logback-android as shown in the following examples. Note the direct usage of logback classes removes the advantage of the facade provided by SLF4J.

Example: Uses BasicLogcatConfigurator

package com.example;

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.android.BasicLogcatConfigurator;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    BasicLogcatConfigurator.configureDefaultContext();

    org.slf4j.Logger log = LoggerFactory.getLogger(MainActivity.class);
    for (int i = 0; i < 10; i++) {
      log.info("hello world");
    }
  }

}

Example: Configures appenders directly

package com.example;

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.android.LogcatAppender;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;

import android.os.Bundle;
import android.app.Activity;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    configureLogbackDirectly();

    org.slf4j.Logger log = LoggerFactory.getLogger(MainActivity.class);
    for (int i = 0; i < 10; i++) {
      log.info("hello world");
    }
  }

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

    // setup FileAppender
    PatternLayoutEncoder encoder1 = new PatternLayoutEncoder();
    encoder1.setContext(lc);
    encoder1.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
    encoder1.start();

    FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
    fileAppender.setContext(lc);
    fileAppender.setFile(this.getFileStreamPath("app.log").getAbsolutePath());
    fileAppender.setEncoder(encoder1);
    fileAppender.start();

    // setup LogcatAppender
    PatternLayoutEncoder encoder2 = new PatternLayoutEncoder();
    encoder2.setContext(lc);
    encoder2.setPattern("[%thread] %msg%n");
    encoder2.start();

    LogcatAppender logcatAppender = new LogcatAppender();
    logcatAppender.setContext(lc);
    logcatAppender.setEncoder(encoder2);
    logcatAppender.start();

    // add the newly created appenders to the root logger;
    // qualify Logger to disambiguate from org.slf4j.Logger
    ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    root.addAppender(fileAppender);
    root.addAppender(logcatAppender);
  }
}

Example: Configures by XML file

// snip…

private void configureLogbackByFilePath() {
  // 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();
  }
}

Example: Configures by in-memory XML string

// snip…

static final String LOGBACK_XML =
    "<configuration>" +
      "<appender name='FILE' class='ch.qos.logback.core.FileAppender'>" +
         "<file>foo.log</file>" +
         "<append>false</append>" +
         "<encoder>" +
           "<pattern>%-4r [%t] %-5p %c{35} - %m%n</pattern>" +
         "</encoder>" +
       "</appender>" +
       "<root level='DEBUG'>" +
         "<appender-ref ref='FILE' />" +
       "</root>" +
    "</configuration>"
    ;

private void configureLogbackByString() {
  // 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);

  InputStream stream = new ByteArrayInputStream(LOGBACK_XML.getBytes());
  try {
    config.doConfigure(stream);
  } catch (JoranException e) {
    e.printStackTrace();
  }
}

ProGuard

When optimizing your application with ProGuard, include the following rules to prevent logback-android and SLF4J calls from being removed (unless that's desired):

-keep class ch.qos.** { *; }
-keep class org.slf4j.** { *; }
-keepattributes *Annotation*

If you don't use the mailing features of logback (i.e., the SMTPAppender), you might encounter an error while exporting your app with ProGuard. To resolve this, add the following rule:

-dontwarn ch.qos.logback.core.net.*

Other Documentation

For help with using logback-android, ask the mailing list: [email protected].

Build

logback-android is built with Apache Maven 2+. Use these commands to create the uber JAR (with debug symbols).

git clone git://github.com/tony19/logback-android.git
cd logback-android
./makejar.sh

The jar would be in: target/logback-android-<version>.jar

License

logback-android: the reliable, generic, fast and flexible logging framework for Android.

Copyright © 1999-2013, QOS.ch. All rights reserved.

This program and the accompanying materials are dual-licensed under either the terms of the Eclipse Public License v1.0 as published by the Eclipse Foundation

or (per the licensee's choosing)

under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation.