H5W3
当前位置:H5W3 > Andriod > 正文

【安卓】Android日志开发实践(一)

前言

现在软件开发门槛越来越低,随便一个大学生培训几个月就可以开始开发软件,但是事实上,软件开发是有较高门槛的,写出高质量的代码并不容易。按28定律,只有20%程序员能写出合格的代码,其他80%代码质量都是有问题的。按从业多年接触的经验上看,竞然高达有80%的人不注重日志实践,甚至连日志实践都很肤浅。不夸张地说,面试程序员时,如果连接日志实践都无法说清楚的,几乎可以肯定是没有经验的或水平很一般的。
有经验的人在构建应用程序基础框架时,一般会前置构建好日志模块。笔者从事的物联网设备开发领域有很多使用Android开发的设备,水平不一的Android程序员经常开发出崩溃、闪退、ANR等问题设备的,在Android开始时,日志实践更是重要,一般我们应该结合自身的应用特点定义和配置好日志模块。

常见的Android日志框架包括:

  • 原生logcat
    Android原生内置的日志模块,与Android Studio结合紧密,相当于Chrome中的console,算是比较基础的日志模块。
    零配置,直接log.d,log.ilog.w,log.e就可以在控制台输出日志。 一般,我们就会release版本中关闭日志输出功能以减少开销。
  • Logger

这是一个应用比较广泛的Android日志库,一款简单优秀强大的Android日志记录器Logger,有相当多的人在使用。优点是能提供线程/类/方法信息,支持JSON/XML格式化打印,输出格式简洁易看、能直接跳转到源文件。
但是Logger只是专门针对Android开发的,对一个完整的日志框架而言,并不完善。官方只包含一个DiskLogAdapter,如果要将日志输出到SocketHTTPsyslog等,需要自己开发Adapter

  • android-logback
    在Java领域,SLF4J是一个著名的JAVA日志门面框架,[logback](http://www.logback.cn/)是其实现。logback 继承自 log4j,它建立在有十年工业经验的日志系统之上。它比其它所有的日志系统更快并且更小,包含了许多独特并且有用的特性。android-logback则是其Android封装。
  • 其他Android日志框架

还有不少第三方开源的日志框架,如ViseLog,log4j,Hutool/logUntil等等。

日志需求

日志模块实践和配置应与需求相关联,笔者需要开发一套基于Android的物联网设备,不同于一般的Android App,其对日志的需求如下:

  • 支持输出到logcat,并且能自己输出格式,最重要的是要能跳转到源码文件。
  • 支持输出到文件,能按日期、日志文件大小、数量切割滚动输出日志。
  • 能输出到Sentry日志收集平台
  • 能输出到Syslog服务器
  • 能灵活配置日志参数,并可以在运行中修改日志级别、启用/禁用网络日志等。

基于上述需求,最终选型使用android-logback.

基本使用方法

安装

build.gradle中添加

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

logback-android提供了多种Appender,用来实现将日志输出到不同的目标,如下:

  • FileAppender
  • RollingFileAppender
  • SMTPAppender
  • SocketAppender, SyslogAppender
  • SQLiteAppender
  • AsyncAppender

XML配置

app/assets下创建一个logback.xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 日志保存位置   -->
<property name="LOG_DIR" value="/data/data/包名/files/logs" />
<!-- Logcat -->
<appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>%logger{12}</pattern>
</tagEncoder>
<encoder>
<pattern>[%-5level] - %msg\, %caller%\,L%line\,%thread%, %line%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--  Syslog   -->
<appender name="syslog" class="ch.qos.logback.classic.net.SyslogAppender">
<lazy>true</lazy>
<syslogHost>192.168.118.129</syslogHost>
<port>514</port>
<facility>LOCAL1</facility>
<reconnectionDelay>10000</reconnectionDelay>
<suffixPattern>[%thread] %logger %msg</suffixPattern>
<charset>UTF-8</charset>
</appender>
<appender name="SYSLOG" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="syslog" />
</appender>
<!-- 滚动文件   -->
<appender name="rollingfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %class{16} - %msg, L%line, %thread%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<maxFileSize>20MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>100MB</totalSizeCap>
</rollingPolicy>
</appender>
<appender name="FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="rollingfile" />
</appender>
<root level="DEBUG">
<appender-ref ref="LOGCAT" />
<appender-ref ref="FILE" />
<appender-ref ref="SYSLOG" />
</root>
</configuration>

关于android-logback的很多配置参数均可以参考logback文档。

需要注意的是针对文件、网络等输出目标,一般应配置AsyncAppenderAsyncAppender的作用简单也就仅仅是内置一个队列,然后批量进行日志输出。logcarAppender不需要。

使用

接下来在类中使用即可。


public class MyClass {
private final Logger log = LoggerFactory.getLogger(MyClass.class);
...
public void method(){
log.debug(...);
log.info(...);
log.warn(...);
log.error(...);
}
}

我们需要使用LoggerFactory.getLogger(类名)构建一个日志记录器,一般会使用当前类的类名作为logger的名称。

事实上,你完全也可以使用LoggerFactory.getLogger(任意字符串)构建,但使用类名可以得用类名形成层级关系,可以进行更加灵活的日志输出和控制。

至此,基本使用就算完成了。

但是,为了使用log,我们不得不写上大量的样板代码private final Logger log = LoggerFactory.getLogger(MyClass.class);,明显是很不爽的。

一般推荐使用lombok注解来简化此操作。如上例:


@Slf4j
public class MyClass {
....
public void method(){
log.debug(...);
log.info(...);
log.warn(...);
log.error(...);
}
}

只需要在所有类前添加一个@Slf4j的注解即可达到同样的效果,很时显清爽多了。

进阶开发和配置

基本配置并不能满足我们的需求,我们还需要解决:

  • 在logcat中输出
  • 输出到Syslog
  • 输出到Sentry

输出到logcat

android-logback已经实现了logcatAppender,我们只需要配置相应的参数即可。

    <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>%logger{12}</pattern>
</tagEncoder>
<encoder>
<pattern>[%-5level] - %msg\, %caller%\,L%line\,%thread%, %line%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>

只需要在按照logback[PatternLayout](http://www.logback.cn/06%E7%AC%AC%E5%85%AD%E7%AB%A0Layouts.html)规则配置pattern即可输出丰富的日志信息。

接下来我们还要解决一个问题,在logcat日志输出窗口直接跳转到输出日志所在的源文件。

方法很简单,只需要在pattern中添加.(%file:%line\)即可。

    <appender name="LOGCAT" class="ch.qos.logback.classic.android.LogcatAppender">
...
<encoder>
<pattern>[%-5level]", "%msg, .(%file:%line\\) , %thread </pattern>
<charset>UTF-8</charset>
</encoder>
</appender>

这样,每一条输出到logcat控制台的日志均会包含一个超链接,点击就可以直接跳转到打印日志时的源文件所在行。

输出至Syslog

syslog是Linux内置的标准日志功能,一般linux均至少会内置syslog clientsyslog server需要额外开启。

只所以在Android开发中启用syslog的原因是,公司的物联网设备即有Android的,也有嵌入式linux的,而在网络收集日志时,嵌入式Linux设备内置了syslog输出,我们希望使用统一的、现成的日志服务器。因此就有了这样的网络日志收集方案:

  • 使用一台linux服务器,配置启用syslog服务器。或者windows上安装Kiwi Syslog Server
  • 嵌入式Linux设备直接使用内置现成的syslog进行网络日志输出,即可以输出应用日志,还可以输出系统日志。
  • Android使用android-logback,但是配置启用syslogAppender.

以上就是我们需要启用syslog的原因。

 <appender name="syslog" class="ch.qos.logback.classic.net.SyslogAppender">
<lazy>true</lazy>
<syslogHost>192.168.118.129</syslogHost>
<port>514</port>
<facility>LOCAL1</facility>
<reconnectionDelay>10000</reconnectionDelay>
<suffixPattern>[%thread] %logger %msg</suffixPattern>
<charset>UTF-8</charset>
</appender>
<appender name="SYSLOG" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="syslog" />
</appender>

SyslogAppender的配置方式如上,suffixPattern就是用来指定输出日志的信息格式的。配置格式参照[PatternLayout](http://www.logback.cn/06%E7%AC%AC%E5%85%AD%E7%AB%A0Layouts.html)即可。

输出至sentry

sentry是用python/django写的一个通用开源的日志收集服务器,可以说功能相当强大,最关键的是各种语言的日志输出客户端都有,一般可以部署来进行日志收集。

使用sentry相当复杂,部署也比较重,一般使用官方的docker-compose进行部署,部署完毕后容器高达20几个,可以是一个相当重量级的应用,优点是可以进行大规模集群部署。
可以说,小型应用不推荐。

sentry官方就提供了sentry-logback库,直接引入就

   implementation('io.sentry:sentry-logback:4.0.0-alpha.2')  {
exclude group: 'ch.qos.logback'
}

sentry-logbackandroid-logback有引用冲突,需要配置一下exclude group。

小结

至此,使用android-logback的日志实践已基本可以工作。
但是还有几个问题需要解决:

  1. 静态的logback.xml配置文件不够灵活,我们需要能让用户或应用可以进行少量的配置,如是否启用网络日志等。
  2. 大型的Android应用可能涉及多个Library,如何实现日志的集中分发。

未完待续

本文地址:H5W3 » 【安卓】Android日志开发实践(一)

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址