前言

埋点是线上项目采集数据的一种重要方式,这些可能是对error数据的采集,也可能是对用户偏好的采集。其实质其实就是在代码的相应位置添加埋点,执行相应埋点代码后能够将信息记录到对应文件中,然后在一定时机下上传到服务器。

关键问题

埋点要解决的几个关键问题如下:
1、由于全局都可能使用到埋点,因此一般埋点为单例模式。
2、放置埋点不可避免在多个线程的情况,因此要使用handler来实现,埋点要有自己的线程并且有Looper循环。
3、部分埋点逻辑可能要由业务中去实现,因此要由相应接口。

代码

1、定义了logTypeFilter变量,来保证只有已经定义的埋点类型才会被记录。未知的(没有定义的)埋点类型会被过滤。
2、Record内部类是此处定义的埋点结构。
3、此处record(String logType, String logContent, Exception exception)是提供给全局使用的设置埋点的方法。

/**** Copyright 2018 iQIYI.com** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.**/
package com.iqiyi.halberd.liteapp.utils;import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;/*** Created by eggizhang@qiyi.com on 17-10-27.* Using this utils for performance recording and process recording of lite app*/
public class LogUtils {public static final String TAG = LogUtils.class.getName();public static final String LOG_MINI_PROGRAM_ACTIVITY_LIFE_CYCLE = "log_type_app_activity_life_cycle";public static final String LOG_MINI_PROGRAM_PAGE_LIFE_CYCLE = "log_type_app_page_life_cycle";public static final String LOG_MINI_PROGRAM_FRAGMENT_LIFE_CYCLE = "log_type_app_fragment_life_cycle";public static final String LOG_MINI_PROGRAM_CACHE = "log_lite_app_cache";public static final String LOG_MINI_PROGRAM_EVENT = "log_lite_app_event";public static final String LOG_MINI_PROGRAM_ERROR = "log_lite_app_error";public static final String ACTION_START=" action start";public static final String ACTION_STOP=" action stop";public static final String LIFE_OBJECT_CREATE = " object create";public static final String LIFE_CREATE = " onCreate";public static final String LIFE_START = " onStart";public static final String LIFE_RESUME = " onResume";public static final String LIFE_PAUSE = " onPause";public static final String LIFE_STOP = " onStop";public static final String LIFE_DESTROY = " onDestroy";public static final String LIFE_CREATE_VIEW = " onCreateView";public static final String LIFE_DESTROY_VIEW = " onDestroyView";public static final String LIFE_ACTIVITY = " liteAppActivity";public static final String LIFE_FRAGMENT = " liteAppFragment";public static final String LIFE_PAGE = " liteAppPage";public static final String LIFE_WEB_VIEW = " halWebView";public static final String PAGE_CONTEXT_CREATE = " page context create";public static final String PAGE_CONTEXT_DISPOSE = " page context dispose";public static final String PAGE_THREAD_CREATE = " page thread create";public static final String PAGE_THREAD_STOP = " page thread stop";public static final String FRAGMENT_PUSH = " fragment push";public static final String FRAGMENT_POP = " fragment pop";public static final String CACHE_PAGE = " page cache";public static final String CACHE_FILE = " file cache";public static final String CACHE_IMAGE = " image cache";public static final String CACHE_MEMORY_HIT = " memory hit";public static final String CACHE_DISK_HIT = " disk hit";public static final String CACHE_MEMORY_CREATE = " memory create";public static final String CACHE_DISK_CREATE = " disk create";public static final String CACHE_NETWORK = " network access";public static final String CACHE_CHECK_UPDATE = "check update";public static final String COMMON_FAIL = "failed";public static final String COMMON_SUCCESS = "success";public static final String EVENT_TYPE = " event type is ";private final static String[] logTypeFilter = new String[]{LOG_MINI_PROGRAM_ACTIVITY_LIFE_CYCLE,LOG_MINI_PROGRAM_PAGE_LIFE_CYCLE,LOG_MINI_PROGRAM_FRAGMENT_LIFE_CYCLE,LOG_MINI_PROGRAM_CACHE,LOG_MINI_PROGRAM_EVENT,LOG_MINI_PROGRAM_ERROR};private static LogUtils instance = null;private String applicationFilesDir=null;private Thread logThread = null;private String manufacture = null;private String model = null;private String liteAppID = null;private boolean isNormalSize = true;private int messageQueueSize=0;private static final int QUEUE_MAX_SIZE = 100;private static final int QUEUE_NORMAL_SIZE = 5;private Handler handler;private static final int LOG_RECORD=0;private static final int REMOVE_EXTRA_FILES=1;private LogProvider logProvider;public static void setLogProvider(LogProvider logProvider) {getInstance().logProvider = logProvider;}public interface LogProvider {void doRecord(Record record, Exception e);void clearLogFile(String applicationFileDir);}private LogUtils() {}public static LogUtils getInstance() {if (instance == null) {synchronized (LogUtils.class) {if (instance == null) {instance = new LogUtils();}}}return instance;}public void init(Context context) {if (logThread == null) {applicationFilesDir=context.getFilesDir().getPath();manufacture = android.os.Build.MANUFACTURER;model = android.os.Build.MODEL;startThreadLoop();}}public String getApplicationFilesDir() {return applicationFilesDir;}public void setLiteAppIdIfNull(String liteAppID) {if (this.liteAppID == null) {this.liteAppID = liteAppID;}}private void startThreadLoop() {logThread = new Thread(new Runnable() {@SuppressLint("HandlerLeak")@Overridepublic void run() {Looper.prepare();handler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);try{switch (msg.what){case LOG_RECORD:consume((Record) msg.obj);break;case REMOVE_EXTRA_FILES:if(logProvider!=null)logProvider.clearLogFile(applicationFilesDir);break;}} catch (Exception e) {Log.e(LOG_MINI_PROGRAM_ERROR, "logFile name unknown error.", e);}}};Message msg=handler.obtainMessage();msg.what=REMOVE_EXTRA_FILES;handler.sendMessage(msg);Looper.loop();}});logThread.start();}private void consume(Record record) {//TODO 这里留上传接口if (record.exception == null) {Log.v("lite-app-log", record.toString());} else {Log.e("lite-app-error", record.toString(), record.exception);}if(logProvider!=null)logProvider.doRecord(record, record.exception);messageQueueSize--;}public class Record {private String logType;private long time;private int pid;private long tid;private String content;private Exception exception = null;public String getContent() {return content;}public long getTime() {return time;}@Overridepublic String toString() {if (messageQueueSize > QUEUE_MAX_SIZE) {isNormalSize = false;} else if (messageQueueSize < QUEUE_NORMAL_SIZE) {isNormalSize = true;}if (isNormalSize) {return "time:" + time + "," +"content:" + content + "," +"manufacture:" + manufacture + "," +"model:" + model + "," +"pid:" + pid + "," +"tid:" + tid + "," +"queueing:" + messageQueueSize + "," +"logType:" + logType + "," +"liteAppID:" + liteAppID + "," +".";} else {return "too muck log" + logType;}}}public static void log(String logType, String logContent) {if(getInstance().logThread!=null&&getInstance().handler!=null)getInstance().record(logType, logContent, null);}public static void logError(String logType, String logContent, Exception exception) {if(getInstance().logThread!=null&&getInstance().handler!=null)getInstance().record(logType, logContent, exception);}private void record(String logType, String logContent, Exception exception) {for (String aLogTypeFilter : logTypeFilter) {if (aLogTypeFilter.equals(logType)) {Record newRecord = new Record();newRecord.time = System.currentTimeMillis();newRecord.pid = Process.myPid();newRecord.tid = Thread.currentThread().getId();newRecord.content = logContent;newRecord.logType = logType;if (exception != null && logType.equals(LOG_MINI_PROGRAM_ERROR)) {newRecord.exception = exception;}Message msg=handler.obtainMessage();msg.what=LOG_RECORD;msg.obj=newRecord;handler.sendMessage(msg);messageQueueSize++;return;}}}
}

更多内容可以查看github官方开源项目:
https://github.com/iqiyi/LiteApp

【LiteApp系列】埋点的设计相关推荐

  1. C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用

    前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...

  2. 数据产品经理:埋点的设计、管理与应用

    本文由作者 董小矿 于社区发布 前言: 本篇是从数据产品经理如何设计.管理和应用埋点的角度重新整理的文章,其中:1.埋点类型.2.1新增埋点设计.2.3产品指标地图部分的内容,与本人之前的文章有重叠, ...

  3. 九十、Python的GUI系列 | QtDesigner进行界面设计

    @Author:Runsen @Date:2020/7/11 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  4. IP网络设计系列之-局域网设计

    [导读]这是ip网络设计系列讲座的最后一部分,讨论园区局域网设计中遇到的一些问题.以太网交换机优越于传统的集线器环境的好处将首先介绍一下.应用虚拟局域网的动机已经同规划和配置虚拟局域网遇到的问题一起进 ...

  5. 惠普台式计算机系列,惠普发布设计笔记本、设计台式电脑等Z系列产品

    惠普发布新一代惠普Z系列产品,包含设计笔记本.设计台式电脑.显示器和VR等产品. 惠普Z系列设计笔记本HP ZBook 14u G6配有4K显示屏,支持100% Adobe RGB色域显示,拥有600 ...

  6. ML:MLOps系列讲解之《设计机器学习驱动的(ML-powered)软件—我们想要解决的业务问题是什么?》解读

    ML:MLOps系列讲解之<设计机器学习驱动的(ML-powered)软件-我们想要解决的业务问题是什么?>解读 导读:设计机器学习驱动的软件,这部分致力于任何软件项目中最重要的阶段之一- ...

  7. 芯片制造系列全流程:设计、制造、封测

    目录 芯片制造系列全流程(简) 一.芯片制造全流程简介 二.芯片设计 三.芯片制造 四.封装测试 芯片目前分为三个主要环节,分别是设计.制程.封测. 设计水平 制造这一块 最后说说封测这一块 芯片设计 ...

  8. ad15的stc元件库_STC单片机 STC15F系列单片机 Altium PROTEL 设计的器件原理图+PCB封装库文件...

    STC单片机 STC15F系列单片机 Altium PROTEL 设计的器件原理图+PCB封装库文件,Altium Designer.PROTEL原理图PCB封装文件,已经制板在实际项目中使用,可作为 ...

  9. FPGA-Xilinx 7系列FPGA DDR3硬件设计规则

    Xilinx 7系列FPGA DDR3硬件设计规则 引言:本文我们介绍Xilinx 7系列FPGA DDR3硬件设计规则及约束,包括Bank选择.管脚位置约束.管脚分配.端接.I/O标准和走线长度. ...

  10. STM32MP157系列教程连载-硬件设计篇3:STM32MP1微处理器之时钟篇

    STM32MP157系列教程连载-硬件设计篇3:STM32MP1微处理器之时钟篇 一.RCC系统概述 本文涉及的内容主要包含在以下几个文档中,文档可从ST官方网站与意法半导体stm32中国下载. 序号 ...

最新文章

  1. 求求你了,配个GC日志呗,不然咋分析故障原因
  2. 精彩回顾 | Apache Flink x Iceberg Meetup · 上海站
  3. Kinect开发资源汇总
  4. shell命令总结3
  5. remote vscode无git_vs code 使用git
  6. 数据结构--位图 BitMap
  7. python中变量和函数的区别_python中带下划线的变量和函数的意义
  8. 40 CO配置-控制-产品成本控制-成本对象控制-实际成本核算/物料分类帐-维护材料分类帐文档的编号范围
  9. cad文字插件_超好用的4个CAD应用程序,让你提升工作幸福感,裂墙推荐
  10. Selenium1、Selenium2、Selenium3的区别,终于讲清楚了
  11. SQLServer中定义拼音检索函数,根据中文参数返回对应汉字的拼音首字母
  12. 10年经验总结:数据分析师7种工具,因果分析划重点!
  13. js实现扫雷-算法分析
  14. Yii Framework 开发教程(41) Zii组件-Tabs示例
  15. 一个有趣的博弈或推理游戏——除数博弈(动态规划与归纳法)
  16. JPA 学习(四) JPA_EntityManager系列
  17. 【复杂网络建模】——通过图神经网络来建模分析复杂网络
  18. java实训感想6000字_JAVA论文6000字:无线校园
  19. 【python 程序题:火车票购买程序】
  20. 零基础都能看懂的 STL map 详解

热门文章

  1. Ubuntu 出现这个提示“Waiting for cache lock: Could not get lock /var/lib/dpkg/lock-frontend.”?
  2. 什么是Subversion?
  3. Python爬虫之Selenium
  4. C++、Java、JavaScript中的异常处理(Exception)
  5. 【推荐系统系列6】ALS推荐算法原理
  6. 卖了43.2万美元的AI画作,其实是借鉴程序员代码的“山寨货”?
  7. dds提取工具_多媒体资源提取工具(MultiExtractor)
  8. 基于51单片机的电压检测系统设计(#0412)
  9. 进程间通信:管道(1)
  10. 步骤3_linux QQ install