前端埋点数据采集(二)mock应用系统10万条前端埋点数据
前端埋点数据采集(二)mock应用系统10万条前端埋点数据
上一期我们分享了前端埋点数据采集(一)采集系统架构设计
我们说应用系统的数据,采集到大数据平台来,然后再到数仓。但是很多实际场景是应用系统、大数据平台、数仓平台各自并没有完成系统的搭建和开发。
假设现在一个场景是:应用系统javaweb并未开发完成,但是大数据平台刚刚完成搭建,就等应用系统上报埋点日志到大数据平台上了。而且由于业务变化较快,应用系统经常变更,上报的数据格式可能经常会变化。
这个时候怎么办?项目工期紧张,不能延期,而且没有额外资源给这个组。
这次我们将借这篇分享回答这个问题。
一、项目中遇到的问题和挑战
1、项目开发依赖性问题
项目在开发测试交付过程中经常遇到前后的工作存在很大的依懒性,其实“瀑布型开发模式下”这种依赖很难解决,必须要在项目开始阶段,项目详细计划书里面由产品经理、数据分析师、前后端应用架构师、大数据架构师、数仓架构师已经商议定义好了数据字段格式要求后,就可以各司其职做搭建开发工作了。大数据开发人员会根据商定的日志格式mock数据测试使用。这里要求日志格式不能太大变化,如果有变化需要项目经理发起变更申请审批流程。
2、业务不断变更带来的系统、数据不确定性
由于业务变化快,系统需要经常变更,数据格式不确定性。在VUCA时代这种场景很常见,项目充满着复杂性、不确定性、模糊性、异变性。特别是在互联网行业、快消、零售行业,业务变化很快,实时性、创新性要求高,传统的项目管理模式已经无法适应,需要的是打破部门之间、团队之间的竖井,打造“由灵活的小团队构建成灵活的大团队”场景。
3、引入敏捷项目管理
刚才的场景只是站在项目生命周期里面一个开发的环节角度来看,上下链路还没有跨部门,组织沟通还是通畅的。如果站在测试环节的角度看,难道项目一定要开发完成才能做测试吗?站在业务需求部门产品经理PM的角度看,难道只有完成整个开发流程,项目才能上线使用?其实项目一旦制定需求项目目标,测试项目内容都可以进行了,做TDD(Test Driver develop),不需要开发完成才做测试。TDD也是敏捷开发的一个重要特征。
作为一个Scrum Master,下次有机会分享敏捷开发各种topic。
二、埋点选型
我们在这里不介绍埋点基本常识(埋点是什么?为什么需要埋点?埋点分类等),可以另外开一篇分享。1、APP埋点工具
-
友盟
-
talking data
-
神策数据
-
后羿采集器等
优点:上手容易,基本不需要开发,开箱即用。
缺点:第三方工具平台带来可能导致信息泄露风险。
2、公司自定义开发
-
预先设定好想要获取的目标数据,
-
撰写代码把“采集器”埋到相应的页面上,用于追踪和记录的用户的行为
-
并把实时数据传送到后台数据库或者客户端。
优点:数量流向都在企业内部平台,能保证信息安全。缺点:需要根据业务自定义开发,有开发运维成本。我们这里选型的是公司自定义开发。这里主要是因为我们关注更多的是大数据平台数据的一个来源,所以定义埋点数据格式,然后通过java代码实现随机数据的mock,写到本地就OK。
三、定义埋点格式
在公司,埋点格式、字段指标、规范等一般都是业务部门(如产品经理)和开发部门(应用架构师)以及数据分析师(做数据分析),协定好的一些字段规范。根据项目计划书里面的附件规范实施就行了。我们这里以假设一个电商APP为案例,讲解最简单的埋点的上报数据基本格式。
1、公共字段
所有手机都包含于的字段。比如手机OS、品牌、经纬度等。2、业务字段具体业务字段,比如:商品ID、订单ID、优惠券、页面数据等。
3、事件内容
添加购物车,添加收藏、领取优惠券等4、日志格式埋点格式如下:这里以一个JSON字符串给出字段的组成形式。它包括
- 数据来源数据源来源于PC、APP、H5、爬虫等等
- 公共字段手机各种属性配置信息
- 用户事件用户一系列动作事件的跟踪,界面加载、点击、浏览等
5、广告标签
根据业务需求,我们这里定义了多个标签。具体每个标签就不一一细讲了,重点标签讲解如下:
:
标签 |
含义 |
entry |
入口 应用首页=1, 商品列表页=2 商品详情页=3 |
action |
动作 请求广告=1 取缓存广告=2 广告展示=4 广告点击=5 |
content |
状态 成功=0 失败=1 |
四、创建工程并对应封装javaBean
通过创建maven工程,把标签字段对应javaBean并且做封装
1、创建Maven工程
POM文件主要涉及
-
依赖fastJson对json解析
-
logback日志框架
-
编译打包maven插件
<!--阿里巴巴开源fastjson解析框架--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.51</version> </dependency> <!--日志生成框架logback--> <!--把bean对象封装成json对象,存储到磁盘上--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency>
2、根据标签定义javaBean
根据业务标签定义一一对应定义javaBean
五、主函数编程即JSON解析
其实主函数就是对固定的JSON字符串进行解析
1、JSON字符串形式
"H5":"xxxxx",//表示前端方式是:APP,还有H5\PC等
"common message": //公共字段common message
{
cm包含以下字段
"mid": "", (String) machineId设备唯一标识?
"os": "1.1.1", // (String) Android系统版本
"md": "HUAWEIPro35", (String) 手机型号
"ba": "xiaomi", (String) 手机品牌
"hw": "1920x1280", // (String) heightXwidth,屏幕宽高
"network": "4g", (String) 网络模式
"ln": 0, (double) lng经度
"la": 0 (double) lat 纬度
},
"et":
[ 事件json数组
{
"ett": "1933047503125", //客户端事件产生时间
"en": "display", 事件名称
"kv":
{ 事件结果,以key-value形式自行定义
"productsid": "1",
"action": "1",
"place": "1",
"type": "1"
}
}
]
}
2、JSON字符串的解析流程
3、主要核心代码
// 参数一:控制发送每条的延时时间,默认是0 Long delay = args.length > 0 ? Long.parseLong(args[0]) : 0L; // 参数二:循环遍历次数,默认是100000 int loop_len = args.length > 1 ? Integer.parseInt(args[1]) : 100000; // 生成日志数据 generateLog(delay, loop_len); private static void generateLog(Long delay, int loop_len) { for (int i = 0; i < loop_len; i++) { /** * 通过random控制2种状态 * 1.是处理启动日志;case(0) * 2.是处理事件日志;case(1) * */ int flag = rand.nextInt(2); switch (flag) { case (0): /** * 处理启动日志 * 1.创建启动日志bean对象并且赋值 * 2.把bean对象封装成json对象(用fastjson对象) * 3.控制台打印json * 4.json写到磁盘中 */ 1.创建启动日志bean对象并且赋值 AppStart appStart = generateStart(); 2.把bean对象封装成json字符串 String jsonString = JSON.toJSONString(appStart); /3.控制台打印 logger.info(jsonString); break; //4.json写到磁盘中 case (1): /** * 处理事件日志 * 1.创建json对象 * 2.向json中添加put ap的值 * 3.向json中添加put 公共属性的值 * 4.随机向json添加ett的值(1个事件一个函数)(多个数组封装) * 5.控制台打印,拼接事件和“|”符号 */ //1.创建json对象 JSONObject json = new JSONObject(); //2.向json中添加put ap的值 json.put("ap", "app"); //3.向json中添加put comFields的值 json.put("cm", generateComFields()); //4.随机向json添加ett的值(1个事件一个函数)(多个数组封装) //json.put("et",jason数组) //4.1先创建一个JSONArray数组 JSONArray eventsArray = new JSONArray(); /** * 4.2一个事件一个函数,一共11个事件的jSON对象 */ //5.控制台打印,拼接事件和“|”符号 long millis = System.currentTimeMillis(); logger.info(millis + "|" + json.toJSONString()); break; } // 延迟时间处理,,几秒就睡眠几秒 try { Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); }}}
六、LogBack框架日志生成打印
1、日志打印到控制台
我们先把参数改为1000条记录信息,然后运行程序,打印到控制台,检查日志符合JSON字段值,说明程序执行正常。
.在resource目录系添加LogBack.xml
我们把日志打印到服务器集群上,所以用LogBack框架配置LogBack.xml文件
- 定义日志文件的存储地址、格式、保留天数、日志大小
- 定义日志输出级别info
<!--定义日志文件的存储地址--> <property name="LOG_HOME" value="/opt/module/logs/" /> <!-- 控制台输出格式 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件。存储事件日志 -->
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- <File>${LOG_HOME}/app.log</File>设置日志不超过${log.max.size}时的保存路径,注意,如果是web项目会保存到Tomcat的bin目录 下 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志文件输出的文件名 --> <FileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.log</FileNamePattern> <!--日志文件保留天数 --> <MaxHistory>30</MaxHistory> </rollingPolicy> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>%msg%n</pattern> </encoder> <!--日志文件最大的大小 --> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>10MB</MaxFileSize> </triggeringPolicy> </appender> <!--异步打印日志--> <appender name ="ASYNC_FILE" class= "ch.qos.logback.classic.AsyncAppender"> <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> <discardingThreshold >0</discardingThreshold> <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> <queueSize>512</queueSize> <!-- 添加附加的appender,最多只能添加一个 --> <appender-ref ref = "FILE"/> </appender> <!-- 日志输出级别 --> <root level="INFO"> <appender-ref ref="STDOUT" /> <appender-ref ref="ASYNC_FILE" /> <appender-ref ref="error" /> </root>
七、上传jar包服务器集群
1、通过Maven打出jar包
2、上传jar包至服务器集群上
- 把生成的具有依赖jar包,上传到node01和02节点/opt/module/applog/路径下
- 然后通过java -jar XXX.jar 运行,查看目录,发现已经有日志文件生成
- 每次执行一次java -jar XXX.jar,都会输出10W条日志信息
- 格式是app.XXXX-XX -XX.log
-rw-rw-r-- 1 qiusheng qiusheng 409236 Apr 30 22:26 app.2021-04-30.log
-rw-rw-r-- 1 qiusheng qiusheng 2067847 May 8 23:39 app.2021-05-08.log
-rw-rw-r-- 1 qiusheng qiusheng 818279 May 9 00:10 app.2021-05-09.log
-rw-rw-r-- 1 qiusheng qiusheng 425014 May 10 21:32 app.2021-05-10.log
3、编写脚本文件实现在node01和02上生成日志
我们不希望日志打印到控制台,也不希望把日志生成到linux服务器集群占用空间,我们利用linux系统标准输入输出,把它放到“黑洞”里面。编写脚本mock_create_log.sh来实现在node01和02服务器上面生成埋点日志数据输出到“黑洞”。
cd /home/qiusheng/bin
vim mock_create_log.sh
#!/bin/bash
for node in node01 node02;
do
echo "=============== $node ==============="
ssh $node " cd /opt/module/applog/;
java -jar gmall2020-mock-log-2020-05-10.jar 1>/dev/null 2&1 & "
done
查node01、node02均有日志生成了。
-rw-rw-r-- 1 qiusheng qiusheng 405243 Apr 30 22:26 app.2021-04-30.log
-rw-rw-r-- 1 qiusheng qiusheng 813751 May 8 23:40 app.2021-05-08.log
-rw-rw-r-- 1 qiusheng qiusheng 804511 May 9 00:10 app.2021-05-09.log
-rw-rw-r-- 1 qiusheng qiusheng 401642 May 10 21:32 app.2021-05-10.log
[qiusheng@node02 log]$
总结:
- java应用项目还未完成,大数据平台怎么样上报数据?
- 了解埋点、日志格式、事件、工具选型
- 埋点格式的解析实质上对JOSN字符串的解析
- 生成的日志需要拼接处理后上传到服务器集群
- 编写linux脚本文件来实现多台服务器的日志生成到“黑洞”以免占用磁盘空间。
>>>>
Q&A
Q:mock_create_log.sh里面的xxx.jar 1>/dev/null 2&1 & 无法理解
A:
-
/dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。
-
linux系统标准输入0:从键盘获得输入 /proc/self/fd/0
linux系统标准输出1:输出到屏幕(即控制台) /proc/self/fd/1
linux系统错误输出2:输出到屏幕(即控制台) /proc/self/fd/2
-
1>/dev/null;标准输出到黑洞
2>/dev/null;错误输出到黑洞
1>/dev/null 2>/dev/null;2输出到黑洞,1也输出到黑洞
等价于简写 1>/dev/null 2&1
-
最后一个&表示脚本在后台运行
-