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' }
<?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>
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
Logger log = LoggerFactory.getLogger(MainActivity.class); log.info("hello world");
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
[2] Logback in Android
留言
發佈留言