【项目总结】android 日志收集

来新公司20天,完成了第一个任务,安卓端日志收集流程的开发,在这里总结一下。

 

1.场景介绍

    公司有多个产业,各产业产生若干app,现在需要收集app的日志信息,并做相关计算,例如流量统计、用户画像等。

    用户的数量级目前不易确定,因为有大半app还在开发中,并没有发布。因为我们是新成立的数据组,没有人熟悉安卓相关的东西,所以老板让我研究一下把这条线打通。

2.技术方案

    Android SDK(日志产生) -> Flume (日志收集) -> kafka(消息缓存) -> storm(日志解析) -> hbase (落地)

    每一个模块我之前都没有接触过,所以都要从头了解,好在flume之后的这些服务已经搭好,我只要摆正姿势使用就可以。

3.技术细节

3.1 Android SDK

    安卓日志的统计对象是用户的行为,即点击、滑动、翻页、跳转等事件;统计内容主要包括设备信息、用户信息、事件信息等。

3.1.1 接口设计

    SDK开发完后,最终会提供给app开发团队,让他们接入到app中,在需要产生日志的地方埋点;因此SDK的接口不能复杂,不能带来太多的接入开发工作。考虑之后,第一阶段只提供下面几个接口

(1) luanchApp() // app启动时调用,目的是初始化sdk
(2) onEvent()   // 各类按钮相应事件中调用,用来统计普通事件
(3) onPageStart() // 页面/activity的开始事件中调用,用来统计页面访问事件
(4) onPageEnd() // 页面/activity的结束事件中调用,用来统计页面访问事件

3.1.2 Android Activity 生命周期

    页面事件是比较重要的一部分,开始之前,对安卓activity的生命周期做了一下了解。下面是几个相关的方法,

(1) onCreate(), onDestroy()   // activity对象的创建和销毁
(2) onStart(), onStop() //activity的开始和停止事件
(3) onResume(), onPause() // activity的继续和暂停事件

    通俗来讲,当activity显示出来,就会调用一次onStart,变得看不见,就会调用一次 onStop;当可以在activity上进行操作时,则会调用一次onResume,变得不能操作时,就会调用一次onPause。onResume和onStart的区别的一个例子:当一个activity A的上面,出现一个透明activity B将A覆盖,那么会调用A的 onPause,而不会调用 onStop。因为A还看得见,但是不能操作了。

3.1.3 日志项

 

名称例子类型说明
useridabc字符串用户id(由app提供)
appid123字符串应用id(由app提供)
guid787f7300-37e2-34d8-b101-c8ef415385ae字符串设备唯一id
imei867831028457919字符串国际移动设备标识
lnzh字符串语言
density3.0浮点型屏幕密度
tel13012836193611位整数电话号码
macf4:8b:32:af:22:e9字符串设备mac地址
iscrack10或1是否root
timezoneAsia/Shanghai字符串时区
nettypelte字符串网络类型
longitude39.001浮点型经度
os4.4.4字符串os版本
platformandroid字符串os
moduleMI 4LTE字符串手机型号
sr1080*1920字符串屏幕分辨率
sdkver1.1.5字符串sdk版本
isp46002整型运营商代号
appver1字符串app版本
ip10.0.2.15字符串ip地址
ismobile10或1是否为手机
requesttime1451272912整型请求产生事件
netstatus10或1网络状态
sim898600310115f0024716字符串sim卡id
channel12字符串app渠道
latitude120.123浮点型纬度
event.sessionid112312341341341341字符串事件所属的sessionid
event.eventtime1451028244整型事件产生时间
event.duration12整型事件持续事件
event.pagedur12整型页面停留时间
event.definedidabc字符串自定义事件id
event.prepageidred字符串前一个页面id
event.curreventpage字符串事件类型
event.pageidblue字符串当前页面id

 

    这里面有几个项比较纠结,不易获取:

    (1) latitude 和 longitude,参考一篇帖子,http://stackoverflow.com/questions/20438627/getlastknownlocation-returns-null

    (2) IP,按照找到的方法总是取不到安卓的真实ip,索性不取了,在flume中的http请求头中得到

3.1.4 日志产生流程

    为了让后续实时分析避免对历史数据的关联,发送的日志数据,每条记录都带上全部字段信息。这样就导致每条记录至少在1K,如果实时发送,吃不消。因此,使用定时发送策略,暂定每60s发送一次,每次发送的数据中,设备相关的信息只保留一份,事件以数组的形式附在其后。这样,经过压缩之后,基本可以保证每分钟日志产生流程在 2K 以内。另外,页面事件的产生,是在 onPageEnd 中,也就是说,当离开这个页面的时候,才产生这个页面的对应事件,这样做的目的是为了统计页面停留时间。

 

    上图是日志产生的流程图。时钟响应每1分钟触发一次,期间产生的事件,放入sqlite数据库中。有一点需要注意:

    app如果退出,则会导致缓存的事件不能及时发出,因为我们平时从后台退出app的方法是会直接杀死进程的。为了避免这种情况,当app发生进入后台、屏幕锁定这两种动作时,不管时钟相应是否触发,直接发送一次缓存事件,因为这两种动作之后,app进程很有可能被杀掉。另外,如果因为各种原因,app退出后还是留下没有及时发出的事件,那么下次打开app时,第一件事就是把上次缓存的事件发送出去。

3.1.5 日志格式

    日志最终以json格式发送,例子如下。client部分是设备相关的信息,events是对应的事件信息。

{
  "client": {          
    "ln": "zh",        
    "density": "3.0",    
    "tel": "",            
    "userid": "",         
    "appid": "731224921",                
    "mac": "f4:8b:32:af:22:e9",         
    "iscrack": "0",                       
    "timezone": "Asia/Shanghai",         
    "nettype": "lte",                    
    "longitude": "",                     
    "os": "4.4.4",                       
    "platform": "android",               
    "module": "MI 4LTE",                
    "sr": "1080*1920",                   
    "sdkver": "1.1.5",                  
    "isp": "46002",                      
    "imei": "867831028457919",           
    "udid": "",                          
    "appver": "1.0",                     
    "ip": "10.0.2.15",                   
    "ismobile": "1",                     
    "guid": "787f7300-37e2-34d8-b101-c8ef415385ae",   
    "requesttime": "1451272912",                       
    "vendorid": "",                                    
    "netstatus": "1",                                  
    "advertid": "",                                    
    "sim": "898600310115f0024716",                     
    "latitude": "",                                    
    "channel": "12"                                    
  },
  "events": [         
    {
      "eventtime": "1451028244",
      "duration": "",
      "isfirst": "",
      "pagedur": "1",
      "defineid": "",
      "moduleid": "",
      "prepageid": "",
      "params": "",
      "modulecnt": "",
      "currevent": "page",
      "pageid": "MAIN"
    },
    {
      "eventtime": "1451028245",
      "duration": "",
      "isfirst": "",
      "pagedur": "1",
      "defineid": "",
      "moduleid": "",
      "prepageid": "MAIN",
      "params": "",
      "modulecnt": "",
      "currevent": "page",
      "pageid": "MAIN"
    }
  ]
}

3.1.6 日志压缩方法

    为了节省流程,日志在传输之前需要进行压缩。压缩使用 gzip 方法。直接对 json 字符串进行 gzip,然后输出的数据进行 base64,最后为了用get方法请求,需要再进行一次 UrlEncode。压缩后的数据形式如下。经测试,在包含50个左右的event时,压缩后大小在2k以内。

 data=H4sIAAAAAAAAAM1STW%2FUMBD9KyhH1A3%2BSuLkxgHQSgUOIHGgHBx7sms1cYLtVGpX%2Fe%2BMk91qKwFSqx6qXObNeGbee5NDpnsLLmbNIetd1mR3%2B%2BwiM%2BCCjbcIeU4QR%2BgxxmAO4K1ZYzVNS1hxypioGcXcoDRmOtHItuGsUV3DWAM1VmzQXulrrC4D7QB3owOE74NVV%2B%2B%2B7ZXb7ZXFmoMYb6dU%2BrH9uMVEP7qdjbNJKUp5zhmticTCGDAjcvwQTL2K3egHTCln%2FIjckM9o5j71fd6%2BEZffP2Aq%2BDSGSPKW1ixxCeb6BpZkTvNioTqluSUhLKEBLEJZVpJTwqQoqpomRbM5c%2BI0IQ20qZ1WLKdVzoTMGV0NGMbWLmSSU7t5NU9WXcUJ2fAK2IYLIzctJXSjJXSCFlwWCvC1h98zhJhsS%2F2iYKREHmnbDTgzPhwFzQtRxTkc1yiDzOKpGmyyR9YStaEYSosORYqKlslmFU8uM55TVvMipTVexi33pyy7v8gAF0Yc%2F%2FOwho858SJpNbPHYaNbt9rQWR%2FiCia1Aywf6RnorIMTvfVaJzR5SI8foPJqCOcPtTvO1LP3CxeEqeW4Zum8%2FPpp%2BwV5%2F5VttfxG%2F2JLHtF9PtsAIeD4pcQ1iEK3oCtetoSrVtNO1x2pO1Hymsv%2Fi8PT%2Bniu7nnCXuoMLyfsaVeTr%2FMf%2B3X%2FB5yw2A5OBQAA

3.1.7 接入flume测试

   flume是一个常用的日志收集工具,下一节做具体说明。flume提供了很多日志的接入方式,http就是其中一种。只需要在app中向flume指定的服务器端口发送http请求,即可完成日志的收集。

3.1.8 部分参考资料

    http://stackoverflow.com/questions/5586197/android-user-agent              --- 安卓获取 user agent

    http://wingjang.blog.163.com/blog/static/479134422013107111424348/      --- base64 编码的换行问题

    http://blog.youkuaiyun.com/liuhe688/article/details/6733407                             ---  activity 的生命周期

    http://blog.youkuaiyun.com/gouguofei/article/details/7775752                            --- 安卓监听程序进入后台

    http://blog.youkuaiyun.com/m_changgong/article/details/7608911                      ---  安卓监听手机锁屏

 

 

3.2 Flume

      flume 的简介参考这篇帖子,http://shiyanjun.cn/archives/915.html。

      在这个项目中,配置了一个http source,两个memory channel,两个 sink;一个是 file roll sink,用来把日志写到本地文件,另一个是 kafka sink,用来将日志推到 kafka 上,以便后续处理。

3.3 Kafka

3.4 Storm

     storm 的简介参考,http://www.searchtb.com/2012/09/introduction-to-storm.html。

     在这个项目中,topology 中一共有一个spout 和 三个 bolt;spout 是从kafka中取数据,然后emit;第一个 bolt 是日志的解析,通过 UrlDecode -> 反base64 -> gunzip,可以恢复出日志json字符串;再将json拆成若干个events数据行,然后以list的形式发送;第二个bolt是将数据写入hbase,每个event对应一行数据,每行数据都带有全部采集项信息;第三个bolt是创建hbase表,日志表目前按照日期每天新建一个。当第二个bolt插入时发现没有建表时,才会执行第三个bolt。

3.5 HBase

 

转载于:https://www.cnblogs.com/sparrowjack/p/5129741.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值