最近忙在项目里面,在项目后期,有个埋点测试,服务端加客户端的点,差不多有 50 个,假设纯肉眼测试,那简直就是崩溃,因此前期先简单的做了数据解析及数据结构解析,后期准备平台化处理
以目前我们使用的神策打点举例,打点包含 事件,事件属性,预置属性
安卓和 ios 打同一个点的时候,若数据类型不一致,一旦一端入库之后,另一端肯定入不了库,因此需要检验数据类型
后续给大家补上关键代码处理
说下思路及目前做法:
1.由于我们这边等于在入库前做一次数据检查,但我们不需要存储数据,所以与客户端约定,在测试环境,客户端把打点数据发送到 nginx,由 nginx 转发到神策服务器
2.已经配置 nginx,把客服端的请求日志打印出来,所以只需解析 access.log 日志,
3.过滤出要处理的数据,urldecode 解码,base64 解密,gzip 解压缩,得到 json 数据
4.套用我之前文章中的格式解析,达到格式检验,其他就是自己写个方法解析数据。检验自己预期得到的数据
平台化思路:
1.打点时间按照指定数据格式文档上传服务器,自动生成模板事件格式,这个方案能解决客户端希望的格式检验问题
2.上传 access.log 日志到服务器
3.运行上述核心方法检验,输出测试结果
ps:服务端打点没有特意说到,我们这边服务端的打点处理更加简单,服务端代码默认是按照神策打点日志格式写到本地磁盘,把神策服务默认从该磁盘读取处理,因此只需把日志拉出来按照上述方式处理即可
Nginx 配置
解密
@Test
public void testDecode1() throws IOException{
String value = "H4sIAAAAAAAAE%2B2Y7W8bNRzH%2FxenL5PK5%2FM9OO%2FyNIRgMCmb9mJClntxEqsX%2B%2BTztaqqSt1LYLANaUgIELA3IBDiDdLQpok%2FZqRZ%2FwvspCU5LS1dq0Vl9F6dfmf%2FHj%2F%2BysmdXWDEiIO6F2BEMPZ8GHphFVCjWbJJRQ%2FUoxBCLwgIrgK%2BxaUBdbDWyLKuYdoAu7KfFvmQlr0EXoxQFfREboRMzNQPCIJ2qwlxu0YaIaphHDdqpENatdhvRjBowmuYeNZhplXGtRE8B%2FVdsNbjWyLhMw8exp1mSEitEwakhjuwVWu22o1aFMYYkqjT9AiyHtZUTre4zoWSbhNah%2BvO8VrCtBZcW9tff%2Fw6%2Fvr55Mdn409%2Bmm2wRvFh172LnPaFzg3tsR1Q77M059aaJ5pzSYdcDIa2BbGH5sZt0TNDUPejwNpGqsdT5%2B3GUEnuwarvnEputpXepGYns20C%2BB1nTMXGPCzLsoWkXc7QmUdMFn2WmEJPE7eNT7mzb4u%2BmGdnPS1WvB6vI69Uy2w8x8s1z4sRp32tRnTDznmgVSFtg40u%2BF4VHCU5RcB6maa5OwvS44YJV16Xy1zpvCFZumNEknfb71UqtoZUJMzYNNqi1%2BSJGvFGYsQWr1fsA07J9Cy9cHtH3AyVYyGxfQZ7e9VXACZhgEoA%2B5j4gYUYzQHmNGMDTo8rvIQM36AfNK537PprQg64Pvzi8eTB7%2FTF%2FoPxd08nP%2By%2F2H84%2BerZ%2BPmjyaN7h98%2BvjD0S%2FE%2B9SScAfrSTJeegItA7%2FbmqtCJc9efdolmgkl1ImZnRPvmzY7DpGVR3rzOpAVFVyrG0Ck8tK%2F0jP1%2F0L8tzLDOjNFiozA8Xx3qGCLsl1DHMIQ%2BjpyCL2r1tJQVcM5TPnI9SpQ0s%2BgHH3968M3T8Z%2B%2FHHz2ZAasq27lmv4fxPs4EcncsCyUt3nq9LRle6tVmtqt1XnHj8LeerdZGGOjXfgIvBKtUlkh1zGKSlx7oSUEBYj4b5eGHx2P%2Bwtn4%2F%2FG%2BZWMY2LpLuFOIncLj2F8WWT85edPxve%2FPPz53svf7k6%2Bv3ul4efS8Gnk99VAyJWI%2BLJwK1TxwENxWcXjCBJoP%2BHLgvXVjeSK5jPTHJHyXdtDIY4j%2B8tygeauGMhb2WuxjKBHMIqhfd7onx%2F%2FCt%2FJ3J4TwDI8S3E8ibtTJrWMH6WF5YKlr6UOi9DR3A6uyM53lUgdlG%2FsuvDR3wNnZBqjEwAA";
String value1 = URLDecoder.decode(value);
System.out.println(value1);
System.out.println(new String(uncompress(Base64Coder.decode(value1))));
}
public static byte[] uncompress(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
try {
GZIPInputStream ungzip = new GZIPInputStream(in);
byte[] buffer = new byte[256];
int n;
while ((n = ungzip.read(buffer)) >= 0) {
out.write(buffer, 0, n);
}
} catch (IOException e) {
// ApiLogger.error("gzip uncompress error.", e);
e.printStackTrace();
}
return out.toByteArray();
}
输出结果:
数据校验
/**
* 检查原始数据是否包含基础checkList,失败则添加到结果
* @param sourceInfo
* @param checkList
* @param event
* @return
*/
public JSONObject checkResult(JSONArray sourceInfo,Map<String,String> checkList,String event){
JSONObject result = new JSONObject();
Set<String> eventSet = new HashSet<String>();
JSONObject formatResult = new JSONObject();
for(int i = 0 ;i < sourceInfo.size(); i++){
JSONObject tempObj = JSONObject.fromObject(sourceInfo.get(i));
String eventValue = tempObj.getString("event");
if(eventValue.startsWith("$")){
continue;
}
if(StringUtils.isNotEmpty(eventValue)&& event.equals(eventValue)){
JSONObject propertiesObj = tempObj.getJSONObject("properties");
String eventInfo = "";
if(propertiesObj.containsKey("$os")) {
//拼接 Event事件 名称: os+event
eventInfo = propertiesObj.getString("$os") + "_" + event;
eventSet.add(eventInfo);
// //比对JSON
// formatResult.put(eventInfo,DiffMethod.diffFormatJson(propertiesObj,DEFAULT_PROPERTIES_JSON));
}
StringBuffer resultInfo = new StringBuffer();
StringBuffer formatResultInfo = new StringBuffer();
for (String key:checkList.keySet()){
if(!propertiesObj.containsKey(key)){
if(propertiesObj.containsKey("$os")) {
resultInfo.append("操作系统:[" + propertiesObj.getString("$os") + "]");
}
resultInfo.append("预期应有基础属性值:" + key + ",而实际不包含这个值");
}
if(propertiesObj.containsKey(key)){
String expectType = checkList.get(key);
String resultType = DiffMethod.getTypeValue(propertiesObj.get(key));
System.out.println(eventInfo + "--实际值:" + key + ":::" + propertiesObj.get(key));
if(!resultType.equalsIgnoreCase(expectType)){
System.out.println("预期:" + expectType);
System.out.println("实际:" + resultType);
formatResultInfo.append(key + "预期类型:" + expectType + ",实际类型:" + resultType);
}
}
}
result.put(eventInfo,resultInfo.toString());
result.put(eventInfo + "Format",formatResultInfo.toString());
}
}
return result;
}
方法调用
/**
* 测试指定事件
*/
@Test
public void testPointEvent(){
String filePath = "/nglog/dd.txt";
JSONArray sourceLog = scLogAnalyseApi.readLogAsList(filePath);
//测试自定义属性
Map<String,String> customPropertiesList = Maps.newHashMap();
String eventName = "PIANO_STUDENTS_ATTEND_CLASS";
customPropertiesList.put("app_source","String");
customPropertiesList.put("HANDLE_OBJECT","String");
customPropertiesList.put("TRAIN_GOODS_NAME","String");
customPropertiesList.put("COURSE_ITEM_TEACHER_USER_NICK","String");
JSONObject analyseResult = checkResult(sourceLog,customPropertiesList,eventName);
System.out.println(analyseResult);
}
转载文章时务必注明原作者及原始链接,并注明「发表于 TesterHome 」,并不得对作品进行修改。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!