Logging in Android

     While developing an Android app, we often call the method of Log class (Log.d(), Log.i()...) to display the message or parameter that isn’t shown on screen for debugging or confirming the intermediate result. However, the message or parameter is only output to the window of Android Studio. If we ask our friend who is not a developer to test the app, it may be hard for him/her to tell us what the problem is without the log message. One solution is that the app saves the log message into a file on the runtime and then sends back the log file to us when a problem happens. 

    Logback is one of the logging tools to save the log message into file. Then we can retrieve the file later for analysis. The android version of Logback is Logback-android.

It can 

  • save messages into multiple files

  • Automatically create a new file according to the timing (new day or new week) and save the new coming message into the new file

  • Automatically create a new file when the size of the existing file exceeds a pre-defined volume. 


Step to implement Logback

1. Add the dependency in build.gradle (module)

dependencies {
  implementation 'org.slf4j:slf4j-api:1.7.25'
  implementation 'com.github.tony19:logback-android:2.0.0'
}

2. Create file “logback.xml” in the assets folder(app/src/main/assets). The content will be talked about later.
<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <property name="INTERNAL_LOG_DIR" value="${DATA_DIR}/log" />

    <appender name ="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <lazy>true</lazy>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${INTERNAL_LOG_DIR}/logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
            <totalSizeCap>20MB</totalSizeCap>
        </rollingPolicy>
        <append>true</append>
        <encoder>
            <charset>UTF-8</charset>
            <outputPatternAsHeader>true</outputPatternAsHeader>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [%logger{16}] - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>

</configuration>

3. In Activity or Fragment class, import these class:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

4. Use LoggerFactory to instantiate the logger by providing the name of logger in step 2. Then call the method to save messages into the file defined the step 2.
Logger log = LoggerFactory.getLogger(MainActivity.class);
log.info("hello world");

5. To stop the logger, invoked
log.stop();

Configuration of Logger

In step 2, we have created the ‘logback.xml’ file. We implement how the logger works there.


Property

We define variables here. It is convenient to define the location path of the log file we want to save. DATA_DIR is the pre-defined value in logback-android and its point to the internal app-specific storage location


Appender name

Name of appender with this setting


Appender class

 it defines the type of the logger. The common appender are:

  • LogcatAppender: Output the message to Logcat directly

  • FileAppender: Output the message to a file.

  • RollingFileAppender: When a certain condition is met, it will change to log messages into another file. The trigger condition can be time or file size. Below parameter is based on this appender.


Lazy

File is not created until first write if true


RollyPolicy

define what to do when create a new file


RollingPolicy class

determine the trigger condition by time or file size here. 

  • TimeBasedRollingPolicy

  • SizeAndTimeBasedRollingPolicy


fileNamePattern

define the rule of naming a file to be written to, including the file path. If the file does not exist, it is created automatically. We add a formatted date in the file name. Thus, the log file will be created for a new day. It also can be set to rollover by week or month depend on the value


maxHistory

Maximum number of files (i.e day here) is stored. The eldest file will be deleted.


totalSizeCap

Control the total size of all log files. The old file will be deleted when the total size cap exceeds. We can specify the size in units of “KB”, “MB” and “GB”.


maxFileSize

 In SizeAndTimeBasedRollingPolicy, we can specify the max size of each file. We put %i (filename index) in the value of fileNamePattern. When the file size reaches the defined max value before the current time period ends, a new file is created and the filename index increased by 1.


Append

set true to append the new messages at the end of the existing file. If false, the content of the existing file will be replaced by the new messages.


Encoder

define the format of messages to output


outputPatternAsHeader

output the pattern in the log file each time when the app starts.


Pattern

The format of message 


Logger

We can define multiple loggers with different Appender. Each logger can have more than one appender. Also a logger can inherit the effective level of message from its parent logger when it is not specified. The name that is defined with the symbol “.” shows the parent and child relationship. For example, “A.B”, where A is the parent logger. 


Level

the minimum level of message that the logger will save. The levels of message from high to low are

  • Error

  • Warn

  • Info

  • Debug

  • Trace


Appender-ref

The appender used in the logger.


Root

the default logger when we did not define another logger and the final effective level inherited by other loggers along the logger hierarchy


Next, we will retrieve the log file stored and send it when the app crashes in the next post.

    <appender name ="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <lazy>true</lazy>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${INTERNAL_LOG_DIR}/logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
            <totalSizeCap>20MB</totalSizeCap>
        </rollingPolicy>
        <append>true</append>
        <encoder>
            <charset>UTF-8</charset>
            <outputPatternAsHeader>true</outputPatternAsHeader>
            <pattern>%d{HH:mm:ss.SSS}  %-5level [%logger{16}] - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name=”exampleA” level = “Info”>
        <appender-ref ref="appdenerExampleA" />
    </logger>

    <logger name=”exampleA.B”>
        <appender-ref ref="appdenerExampleB” />
        <appender-ref ref="appdenerExampleC” />
    </logger>

    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>

Reference

[1] Logback Manual

https://logback.qos.ch/


[2] Logback in Android 

https://github.com/tony19/logback-android


留言

此網誌的熱門文章

Use okhttp to download file and show progress bar

Download File into app specific storage with Retrofit

Unzipp file with Zip4j library