Skip to content
This repository

The reliable, generic, fast and flexible logging framework for Java on Android.

This branch is 0 commits ahead and 0 commits behind master

Fix error when child config has enclosing tag (#66)

A configuration error occurred when an included configuration was
enclosed in a <configuration> or <included> tag. The closing tag
of that enclosure was not detected and thus not removed from the
XML doc, which caused it to propagate to the parent config, leading
to an XML parsing error. This was seen as a confusing error to the
user:

   Failed to instantiate [ch.qos.logback.classic.LoggerContext]

The problem was that the SaxEvent's qName was not populated for
the closing tag of the included config. However, the localName
was properly set. The IncludeAction now checks the qName and falls
back to localName if needed.

Fixes Issue #66
latest commit 7916e7e875
Tony Trinh authored
Octocat-spinner-32 logback-classic Add unit tests for FindIncludeAction April 06, 2014
Octocat-spinner-32 logback-core Fix error when child config has enclosing tag (#66) April 06, 2014
Octocat-spinner-32 src Merge tag 'tags/v_1.1.1' February 05, 2014
Octocat-spinner-32 .gitignore Merge tag 'tags/v_1.0.12' February 01, 2014
Octocat-spinner-32 LICENSE.md Update LICENSE.md March 13, 2014
Octocat-spinner-32 README.md Update README.md March 22, 2014
Octocat-spinner-32 codeStyle.xml - changed the autocrlf option to true under Windows. This should help December 03, 2009
Octocat-spinner-32 findbugs-exclude.xml added findbugs to the build August 31, 2012
Octocat-spinner-32 makejar.sh Remove minimizeJar from pom-uber.xml October 20, 2013
Octocat-spinner-32 merge.sh Make merge.sh remove logback-examples February 01, 2014
Octocat-spinner-32 pom-uber.xml Update version in pom-uber.xml to match pom.xml February 05, 2014
Octocat-spinner-32 pom.xml [maven-release-plugin] prepare for next development iteration February 28, 2014
Octocat-spinner-32 release.sh Tweak release script April 26, 2013
README.md

logback-android

v1.1.1-2

Overview

logback-android brings the power of logback to Android. This library provides a highly configurable logging framework for Android apps, supporting multiple log destinations simultaneously:

  • files
  • SQLite databases
  • logcat
  • sockets
  • syslog
  • email

Runs on Android 2.1 or higher.

Quick Start

  1. Add logback-android and slf4j-api to your project class path.
  2. Configure logback-android using either ${project-root}/assets/logback.xml 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.1.1-2</version>
</dependency>
<dependency>
  <groupId>com.github.tony19</groupId>
  <artifactId>logback-android-classic</artifactId>
  <version>1.1.1-2</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.6</version>
</dependency>

Contents

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 to redirect to logcat

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 Logback User mailing list.

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

Something went wrong with that request. Please try again.