Skip to content

127001david/Dlog

Repository files navigation

Dlog

提供Android端日志回捞解决方案,可以将有助于排查问题的信息写入日志文件,在接收到服务器端上传指令后将 本地的日志文件上传至日志服务器。
由上面的描述可见解决方案涉及三个角色,一个推送服务器,一个稳定高效的日志框架和一个日志服务器,虽然这三个角色 的实现都有各自的难点但是好在都有现成的开源项目供我们使用。解决方案采用两层结构,Dlog负责日志的写入和日志文件的管理, 应用层实现推送接收和上传文件,应用层的开发人员可以选用适合自己项目的推送服务器和日志服务器, Demo采用的推送服务器是极光推送,它可以根据用户ID或tag将上传指令推送给客户端; Dlog日志是基于微信xlog的,它采用的mmap写入方式高效且稳定;至于日志服务器可以自行搭建ftp服务器或nginx服务器。 所以Dlog的实现很简单,要说复杂的也就是极光推送和xlog的接入以及准备上传文件这两个地方。

初始化

Dlog.getInstance().init(ctx);

接收上传指令

使用的是极光推送的自定义推送处理模块,实现代码在MyReceiver中,这也是日志回捞流程的起点。

准备上传

Dlog.prepareLogFiles();

方法会返回一个日志文件路径列表,方法的实现涉及到进程间通信IPC,真正的实现类是 DlogManagerService。

方法解析(该段解析关注的是方案提出的过程,如果只关注结果可以直接看段末部分)

Dlog基于微信Mars xlog,xlog的日志的写入是先写入.mmap文件,在适当的时机调用Log.appenderFlush(boolean);方法 ,按照xlog官方提供的建议是在MainActivity的onDestroy方法中调用flush方法。 在调用了flush方法后xlog会将.mmap中的内容写入.xlog文件中,如果没有调用flush方法xlog则会在下次启动APP的时候调用。 显然这两个时机都不符合我们的应用场景,我们需要在收到服务器端上传日志命令后手动将缓存文件刷入待上传的日志文件。
手动刷入日志文件时会遇到一系列问题,首先按照xlog的实现方式,不同进程的日志需要写入进程专属的日志文件中, 这就涉及到进程间通信IPC,我们有两种选择,一种是在进程中注册广播,接收服务器端上传指令的进程 在接到指令后广播通知到其他所有进程,其他进程在接到广播后将自己的缓存日志刷入到日志文件, 这种方式貌似可行但是有一个缺陷,就是上传日志的进程不知道有多少进程注册广播监听,也不知道它们要完成日志写入需要花多长时间, 我们需要一种同步调用的方式在日志刷新完成时将所有这些日志文件上传到服务器端。如果是同步的IPC机制可以选择的是Binder机制, 确切的说是AIDL方式,它可以实现同步调用,从这方面讲AIDL就是另一种更可行的选择。但是我们要怎么使用它呢? 常见的方式就是将具体实现操作的进程视为服务端Server,将调用服务的进程视为客户端Client,这方式也就意味着 要在所有进程中注册并实现一个Service,接收服务器指令的进程建立与所有这些进程的连接,在接到上传指令 时调用Service的代理方法,但是这种实现方式存在两个问题:一是,所有进程分别实现一个Service 只是为了在接收到指令时执行一行flush代码显然是一种资源浪费;二是,作为典型的C-S架构应该是保持Client与Server端 多对一的关系,而这种实现方式却是Client对Server一对多关系,这是不合理的,在实际操作中也是不易管理的。
既然接收指令的进程作为Client是不合理的那么反过来,将它作为Server,让其他进程作为Client就实现了 Server对Client一对多的关系,那么怎么实现接收到上传指令后通知到其他进程呢?这类需求很容易让我们联想到 观察者模式,Binder机制中可以提供观察者模式吗?可以的,只需要借助android.os.RemoteCallbackList 就可以很容易的实现跨进程的观察者模式了,相关实现同样在DlogManagerService类中。

上传文件

Dlog.prepareLogFiles()方法会返回所有.xlog文件的路径,Demo中使用的网络框架是okhttp。

About

基于Mars xlog的日志回捞框架

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages