埋點回歸&實時埋點自動化&離線數據監控

1. 埋點相關文檔:

埋點涉及到的各種平臺

XX平臺:抓取實時埋點日誌

正則平臺:埋點case正則表達式

XX監控平臺:關注埋點監控日報

BI埋點數據監控平臺:大盤數據

XX報警平臺:但暫不支持正則報警,待RD完善

 

2. 搜索埋點測試方法

2.1 什麼是埋點

埋點又稱爲“數據採集”,例如在APP端埋點可以將此APP中的用戶行爲、APP性能、設備信息、交互信息等進行自定義收集,所以將採集數據的這一過程稱之爲埋點。公司內部埋點是發生在數據結論之前的一種行爲,在拿到某個數據之前一定要進行埋點,例如向大數據部門提數據需求之前要先向產品部門提埋點需求,只有埋點需求執行完成,纔會產生和記錄到需要的數據,再由大數據部門來實現需求的數據落地

根據鏈接中spm和scm的組合,我們就能追蹤到這條鏈接,是由什麼內容提供方提供的,並且由用戶在哪個指定頁面的指定位置點擊產生的。通過spm和scm的組合效果評估,能知道什麼位置投放什麼內容效果最好,什麼樣的內容投放在什麼位置效果最佳,從而達到將合適的內容推送到合適的位置的效果。後期根據FBI數據統計得知大盤數據

2.2 埋點的分類

目前業務日誌分爲兩大類

  • 系統自動採集的頁面瀏覽(PV, Page View)日誌. 這部分日誌在頁面被瀏覽器打開時自動發送, 一般不需要用戶和前端開發干預

  • 其他自定義日誌. 這部分日誌不會自動發出, 而是由開發同學自己編寫代碼, 在用戶執行了某些交互(如點擊, 滑動, 鍵盤輸入)或者觸發某些條件(如遊戲通關播放過場動畫, 視頻播放到某個特殊時點)時 , 通過調用日誌接口主動上報日誌(或直接發送日誌到日誌服務器).

點擊埋點和曝光埋點和頁面埋點

  • 點擊埋點
    • 用戶進行了點擊等交互操作後的埋點
  • 曝光埋點
    • 整體頁面曝光:頁面被展示時的埋點
    • 局部頁面曝光:模塊或坑位出現在視口時的埋點

2.3 埋點測試的驗證模式及分析

4個重要步驟:行爲觸發->上報埋點->讀取埋點->驗證埋點
2.3.1 行爲觸發

點擊、暴露某個控件,離開某個頁面等,可以認爲是一次行爲。觸發行爲可以通過手工和自動化腳本

2.3.2 上報埋點

觸發行爲後,自然就要相應的上報一次埋點,上報埋點本身是從sdk進行上報的,可以研究下工作原理和其上報的鏈路

2.3.3 讀取埋點

要對埋點進行實時校驗,就要實時獲取到埋點
搞清楚sdk是如何上報的埋點的,就可以去對其攔截,從而拉取到實時的埋點日誌,並對其做一些標記,以此來做校驗

2.3.4 驗證埋點

當行爲和埋點日誌都被感知到並採集到後,可以根據數據的特徵、時間、鏈路信息等去進行關聯行爲及埋點事件,並根據場景進行驗證

 

背景

由於搜索埋點數據過於老化,導致統計方面的一些工作的不方便。經過產品評估後決定需要重構部分埋點字段的參數,所以搜索的iOS端和Android端開始了一段

全部埋點的測試之路

面臨的困難

Ø❎每次測試任務量巨大,要求QA覆蓋全部46個類型卡片,100+種狀態

Ø❎埋點日誌字段較多。曝光埋點每個日誌多達300+key value

Ø❎埋點測試每個季度不能出一個bug,不允許出錯

Ø❎流量分散,老的SDK中包含大量且複雜的版本控制邏輯

Ø❎埋點由客戶端下發,容錯率和迭代效率較低

解決辦法

Ø✅ 技術側:通過鏈路配置和場景路由,將不同場景的流量分發致對應的處理鏈路

Ø✅ 技術側:編寫scheme解析器:支持腳本動態解析、執行自定義方法、謂詞邏輯判斷; scheme之間支持繼承和引用下發數據全組件化,通過組件化數據結構實現埋點的下發

Ø✅ 技術側:從場景、版本、ab、xx四個維度進行scheme路由, 實現引擎數據到組件化結構的全自動解析

Ø✅QA 側(以下均爲):Mock數據,構造全部產品形態,避免卡片下線、卡片類型難以查找等情況,輔助測試埋點

Ø✅ 結合埋點治理平臺,抓取埋點日誌

Ø✅ 接入正則平臺,正則表達式判斷部分key value

Ø✅ 設計埋點日誌數據對比腳本,提升測試效率

Ø✅ 接入XX監控平臺,採樣監控搜索埋點

Ø✅ 接入XX報警平臺

Ø✅ 接入XX 設計監控SQL

Ø✅ 開發讀取數據庫的埋點日誌的腳本,分場景判斷

 

3. 埋點客戶端服務端交互

4. 埋點測試歷程

4.1 客戶端

Ø❎2018年10月:單靠人肉diff工作量大且效率低

Ø❎2019年S1上季度:接入正則平臺,正則case測試埋點,SQL批量創建共67條case + 開發埋點對比腳本(點擊 曝光 新老版本 新老架構 track_info內外遷移)

好處-正則平臺:新手上手快,不需要太多複雜的技術就可以測試

弊端-正則平臺:先從UT平臺以爲spmCD作爲埋點的唯一ID撈取日誌,再去正則平臺匹配規則,但由於搜索卡片的特殊性,很多卡片spmCD一致如K3-22XX,K8-9XXX,K6-1XX,XX的spmcd爲XXCast_\d*.portrait_\d* 也就是說如果UT 應該5個日誌命中一條正則但只有4個命中了,整體爲pass,無法精準定位是哪個卡片出錯了。而這樣的卡片佔比(67-15)/67=77.6%,如果堅持用正則平臺測試,也會大概率漏掉,造成埋點漏測;且UT平臺iOS端經常斷開連接

好處-腳本:日誌一一對比省去了大量人肉測試的時間和精力,高效便捷,PM RD自測,提交bug時直接粘貼控制檯日誌,省時省力,無漏測。適用於新的埋點需求測試和老功能埋點回歸

弊端-腳本:需要抓取雙端日誌,兩端操作完全一致,讀取本地文件。雙端曝光日誌方式不完全一致,導致內層jsonlist個數不一致,需要手動刪除小部分日誌

Ø❎ 2019年S1下季度:接入XX監控平臺

好處:測試右移、發佈後版本數據質量跟蹤

弊端:監控爲T+1採樣日誌,發現bug時候已經晚了,比如在一灰後纔有一部分用戶量

Ø❎ 2019 S1下季度:接入XX報警平臺

弊端: 接完發現不支持正則case,搜索是第一個接進去的業務,也是第一個踩雷的

Ø❎ 2019 S2季度:線上全量搜索埋點監控:接入XX,優化SQL

弊端-dqc:上手簡單,多行SQL,大量複製粘貼工作。可用於大量線上日誌監控,但如果此條日誌漏報,如ogc ugc未上報埋點,則總體count數目爲0,平臺的監控判斷是count!=0,此場景下會錯誤認爲此條case是pass的,造成發現不了一級故障

好處-dqc:出結果快,適用於大量日誌監控,尤其容易發現偶現的bug(A用戶日誌沒問題,B沒有,C有這種情況)。優化後的SQL比較能準確定位問題

Ø❎一灰前埋點回歸測試:讀取線上日誌,按版本和utdid維護撈取日誌並解析,提取公共的參數校驗,報警信息接入釘釘機器人,基於Spring Boot開發接口,報警信息數據入庫,與組內同學業務共建,開發前端,最終做成平臺

 

4.2 服務端

Ø❎RD:2019年2月服務端將老接口XX改爲XX,埋點字段spm scm trackInfo內的部分字段等由服務端下發,減少客戶端冗餘的代碼,出了問題後端上線,比較靈活,對線上數據影響小

Ø❎QA:冒煙平臺case設計,監控接口action.report下埋點字段的下發

 

4.3 歷程總結

埋點回歸:雙端純手工(4PD)-> 正則平臺(2PD)-> 埋點對比腳本(1PD)-> 埋點回歸自動化(0.5PD)

監控:T+1 -> FBI T+1 -> 15min 

 

5. 目標

業務方面:搜索核心指標和每個季度的重點工作,提前發現埋點類問題,保障線上不出問題

技術方面:沉澱出埋點自動化方法,從而達到提效,解放人力

 

5.1 提效之多端日誌對比腳本

 

Ø測試覆蓋以下 3 個測試版本
ü1119版本治理一期:
新老版本埋點數據分別約 10045
埋點BUG總數 105
ü1217版本埋點雙端統計
埋點BUG總數 40
ü0107版本:
手工測試平均1h/2個埋點,雙端卡片44個,也就是44h/88個埋點,測試全部點擊埋點耗時,44h=5.5pd,還不包括曝光埋點。。。
腳本測試,設計腳本2pd,測試3pd=24h/88個埋點,提效(44-24)h/44 = 45.5%
埋點BUG總數 67
ü後續每個版本……….
Ø優點
ü方便組內QA驗證埋點,提高效率;使用簡單,已爲PM開通git權限
Ø缺點:沒有實現完全自動化
 
 
 

3. QA貢獻:

3.1 多端日誌對比腳本

設計思想:

1. 整體設計:目前讀取本地日誌進行多端、多版本、單個json、jsonlist對比
src:entrance、utils、jsonDiff、localPathLog、logPath

2. entrance爲讀取UT平臺接口返回的最新日誌
2.1 utils爲解析點擊(單個json)、曝光埋點(jsonlist)日誌格式
2.2 jsonDiff.SingleCompare爲track_info內外key value的對比,必須存在的key 不需要校驗的value如"aaid", "k", "engine", "item_log"的過濾
2.3 jsonDiff.DiffrentPlatForm爲多端的日誌對比,將兩個數組放入集合,此集合包含這兩個json的key。分內外層判斷
內外層判斷,校驗所有集合是否在iOS Android中存在,不存在則日誌打印


定義日誌數據data.txt等文件(單個json,校驗track_info外的字段在track_info都要存在)、data1_old(老版本上報的埋點)、 
data2_new(新版本上報的埋點)

2. 定義第一個類DataPathTag,老版本path1、新版本path2、同一個數據內path,以上埋點數據文件存放的相對路徑

3. 定義第二個類DataUtilsSingle是單個json(點擊日誌)工具類:將文件流放到內存中,BufferedReader按行讀取, 
3.1 分離內外數據 3.1.1 內層與外層的區別標識爲{},{爲開始,}爲結束,將內層與外層數據生成2個字符串track_info_outer、
track_info_inner, 找到track_info_inner第一個"="的下標,截取字符串,可強轉爲json

3.1.2 外層判斷是否包含}

3.2 內層、外層數據轉換 3.2.1 track_info_inner的格式本來就爲json,所以直接處理json即可, 截取track_info_inner字符串,
json格式{}裏所有內容,從{開始截取,直到}的位置,最後一位爲"," { "searchtab":"0", "pageName":"page_searchresults", "group_num":38, }

3.2.2 track_info_outer的格式爲A=1 外層數據處理,字符串轉數組,數組先以","分隔,再以"="分隔,數組再轉json,
如"A=1,B=2,C=3"-->[A=1,B=2,C=3]-->{"A":"1","B":"2","C":"1"}, object_id=dbb0ecb3786549098484, object_title=一出好戲, srid=1,

4. 定義第三個類DataUtilsMulti是多個json,即jsonlist(曝光埋點)工具類:把日誌按track_info內外轉化爲json進行解析

5. 第四個類JSONdiffVersion是新老數據的比較。調用DataUtilsSingle類,內層、外層分開判斷,先判斷key,再判斷value 
老版本的所有key必須在新版本中存在,如果不存在打印key,value。如果存在判斷value是否相同,不相同打印

5. 第五個類SingleCompare是單個版本上報的數據校驗,判斷track_info內是否包含track_info外所有的key 
如果不存在,打印key,value。如果存在判斷value是否相同,不相同打印

6. 第六個類NewArchKV是新老架構埋點數據的對比
track_info內層判斷:
校驗老版本track_info內層層必須不存在{"newArch"};
校驗新版本track_info內層層必須存在{"newArch"};
外層判斷:
校驗老版本track_info外層必須存在{"spm_new","scm_new"};
新版本track_info外層必須存在{"spm","scm"};
新版本track_info外層必須不存在{"spm_new","scm_new"};
且新版本spm scm的value與老版本的spm_new scm_new的value必須一致

7. 第七個類DiffrentPlatForm是判斷不同平臺 如 iOS Android iPad等多端或者多版本單個json的點擊埋點日誌,RD請參考自測

8. 第八個類ExposureDiff是判斷不同平臺 如 iOS Android iPad等多端或者多版本多個json(jsonlist)的曝光埋點日誌,RD請參考自測

9. 增加BI要求必須存在的key的校驗,共10個字段

待優化的地方:目前只支持從UT平臺抓取日誌手動拷貝到txt文件作對比。後續改爲雙端一致的操作,讀取UT接口最新的日誌多對比

1.value中存在兩個==,取第一個
2.value中存在:的情況,如曝光埋點_KG卡片(即UGC大詞)"tagvalue":"2:0;1:0",json解析的時候出錯
3.Android最後的日誌爲track_info的json格式,需要在日誌後面手動加英文逗號,再執行腳本

//內外層數據分離,用【{】表示track_info內層數據開始,用【},】表示track_info內層數據結束。有的埋點數據內層有"utparam":"{
"yk_abtest\":\"592:1381\"
}",這種數據,不能以}作爲內層結束判斷的標識

track_info={
    "k":"名偵探柯南",
    "object_num":3,
    "aaid":"074d90da3c8602ec629104ee7a57e796",
    "utparam":"{
    \"yk_abtest\":\"592:1381\"
    }",
    "newArch":"1",
    "object_title":"30-60分鐘",
    "source_from":"home"
},
spm=a2h0c.8166622.PhoneSokuFilter.sfilter_3,
scm=20140669.search.filter.filter_30-60分鐘,
pid=64b6847e992c4c45

 

流程圖

 

腳本運行結果

 

提交bug到bug系統(爲了數據脫敏,暫不附截圖~~~總之很方便)

 

5.2 提效之線上埋點監控

示例Demo

搜索結果頁-二方卡spm遍歷值條件下,10個核心埋點字段爲空的佔比統計,總和爲0 ---pass

各項字段佔比分別爲0   ---pass

--odps sql

--********************************************************************--

--author:本人

--create time:2019-12-25 16:13:23

--********************************************************************--

 

--以下SQL的as也可以去掉

-- //通用需求正則平臺必須存在的key的校驗

-- public static String[] mustExistKeyOuter = {"spm", "scm"};

-- public static String[] mustExistKeyInner = {"soku_test_ab", "engine", "item_log", "aaid", "k", "source_from", "search_from"};

 

-- set odps.sql.type.system.odps2=true;

-- select date_format(CURRENT_TIMESTAMP(),"%Y%M%D") from dual;

 

select

-- 以下device,app_version,total_failrate在本地運行時爲了查看詳細數據,需要打開,在接入dqc時需要註釋掉

-- device,app_version,

-- round(spm_rate +scm_rate +track_info_rate+ soku_test_ab_rate+ engine_rate+ item_log_rate+ aaid_rate+ k_rate+ source_from_rate+ search_from_rate ,4)

-- as total_failrate FROM (select

 

sum( case when spm is null or trim(spm)='' then 1 else 0 end) as spm_null, sum(1) as log_total,

round(sum(casewhen spm isnullortrim(spm)=''then1else0end)/sum(1),4)as spm_rate,

 

sum( case when scm is null or trim(scm)='' then 1 else 0 end) as scm_null,

round(sum(casewhen scm isnullortrim(scm)=''then1else0end)/sum(1),4)as scm_rate,

 

sum( case when track_info is null or trim(track_info)='' then 1 else 0 end) as track_info_null,

round(sum(casewhen track_info isnullortrim(track_info)=''then1else0end)/sum(1),4)as track_info_rate,

 

sum(casewhenget_json_object(track_info,'$.soku_test_ab')isnullortrim(get_json_object(track_info,'$.soku_test_ab'))=''then1else0end)as soku_test_ab_null,

round(sum(casewhenget_json_object(track_info,'$.soku_test_ab')isnullortrim(get_json_object(track_info,'$.soku_test_ab'))=''then1else0end)/sum(1),4)as soku_test_ab_rate,

 

sum( case when get_json_object(track_info,'$.engine') is null or trim(get_json_object(track_info,'$.engine'))='' then 1 else 0 end) as engine_null,

round(sum(casewhenget_json_object(track_info,'$.engine')isnullortrim(get_json_object(track_info,'$.engine'))=''then1else0end)/sum(1),4)as engine_rate,

 

sum( case when get_json_object(track_info,'$.item_log') is null or trim(get_json_object(track_info,'$.item_log'))='' then 1 else 0 end) as item_log_null,

round(sum(casewhenget_json_object(track_info,'$.item_log')isnullortrim(get_json_object(track_info,'$.item_log'))=''then1else0end)/sum(1),4) item_log_rate,

 

sum( case when get_json_object(track_info,'$.aaid') is null or trim(get_json_object(track_info,'$.aaid'))='' then 1 else 0 end) as aaid_null,

round(sum(casewhenget_json_object(track_info,'$.aaid')isnullortrim(get_json_object(track_info,'$.aaid'))=''then1else0end)/sum(1),4)as aaid_rate,

 

sum( case when get_json_object(track_info,'$.k') is null or trim(get_json_object(track_info,'$.k'))='' then 1 else 0 end) as k_null,

round(sum(casewhenget_json_object(track_info,'$.k')isnullortrim(get_json_object(track_info,'$.k'))=''then1else0end)/sum(1),4)as k_rate,

 

sum( case when get_json_object(track_info,'$.source_from') is null or trim(get_json_object(track_info,'$.source_from'))='' then 1 else 0 end) as source_from_null,

round(sum(casewhenget_json_object(track_info,'$.source_from')isnullortrim(get_json_object(track_info,'$.source_from'))=''then1else0end)/sum(1),4)as source_from_rate,

 

sum( case when get_json_object(track_info,'$.search_from') is null or trim(get_json_object(track_info,'$.search_from'))='' then 1 else 0 end) as search_from_null,

round(sum(casewhenget_json_object(track_info,'$.search_from')isnullortrim(get_json_object(track_info,'$.search_from'))=''then1else0end)/sum(1),4)as search_from_rate

-- 以下device,app_version,在本地運行時爲了查看詳細數據,需要打開,在接入dqc時需要註釋掉

,device,app_version

 

from database.table_name

WHERE ds=to_char(dateadd(GETDATE(),-1,'dd'),"yyyymmdd")

-- 以下and hh in(18,19)在接入dqc時需要註釋掉,監控線上一天24小時的數據。僅用於本地調試

and hh in(18,19)

-- WHERE ds=replace(split_part(dateadd(from_unixtime(unix_timestamp()),-1,'dd')," ",1),"-","")

and site='xx' and (device='android'or device='iphone')

and app_version >='8.3.0'

-- and (spm like '%a2h0c.8166622.rdirect%' OR spm like '%a2h0c.8166622.rmovie%')

-- and (original_spm like '%a2h0c.8166622.xx%' OR original_spm like '%a2h0c.8166622.xx%' OR original_spm like '%a2h0c.8166622.PhoneSokuPromote%')

 

and(original_spm like'%a2h0c.8166622.xx%'OR original_spm like'%a2h0c.8166622.xx%'OR original_spm like'%a2h0c.8166622.xx%')

-- and (original_scm like '%20140669.xx.xx%' OR original_scm like '%20140669.xx.xx%' OR original_scm like '%xx.xx.xx%')

-- and spm like '%a2h0c.8166622.rdirect%' and (xx REGEXP (.*a2h0c\.8166622\.(xx|xx).*)

-- 以下GROUP BY device,app_version在本地運行時爲了查看詳細數據,需要打開,在接入dqc時需要註釋掉

GROUPBY device,app_version

-- )

;

 

優化前的SQL:
設計上:
mysql也支持聚合的時候加一些條件,不過一般都是數據分析師纔會這麼搞,或者BI統計的時候用。日常這麼寫SQL,要被DBA乾死的。因爲這樣很消耗Mysql的cpu,計算也一般都很慢,在線業務跑這種SQL,那接口幾秒鐘能返回也是夠快了,隨便幾個併發起來了,庫都要被拖掛了。
業務上:SQL查詢的是A or B or C or D爲空的總和計算/total_log,接入監控報警,一旦報警,無法準確定位是哪個字段出錯了,可能是A可能是B可能是C,因爲計算的是總和出錯率。到時候還需要把SQL粘貼到odps,逐一修改判斷哪個字段爲空
優化後的SQL:
分別計算A爲空B爲空C爲空D爲空的出錯率,因爲最終的監控只能監控一個字段,所以需要sum()輸出一個值接入監控系統
校驗1個場景下的10個字段,統計,佔比,如果哪個字段漏掉了,排查的時候,只需要把監控SQL粘貼到odps去掉sum(*),清晰地看到ABCD各自的失敗率佔比。哪個字段爲空,準確定位
不需要分多個規則配置,不需要分端,減少冗餘無效的複製粘貼以及一堆規則的填寫,精簡化,報錯明顯

 

 

5.3 提效之服務端冒煙case

接口監控

 

5.4 提效之埋點回歸自動化

 

## 腳本設計思路

腳本部分:

1.根據搜索的獨特業務設計SQL(版本維度、utdid維度、ds維度等)讀取線上離線表--點擊埋點 曝光埋點15分日誌鍾延遲表,xx_clk_ri(點擊)和xx_exp_ri(曝光)
獲取每條SQL的查詢字段內是否存在content字段(裏面爲所有日誌,origialParam爲客戶端全部傳參)

業務邏輯SQL設計如下:
--可用於預發包(後端連接線上)、灰度環境、線上環境迴歸測試,線上與預發的utdid不同,別寫錯了。日誌15分鐘延遲
SELECT app_version, os,utdid,xx,page,xx,xx,xx,xx,ds,hh,mm FROM ytods.s_yt_log_wl_app_clk_ri 
where event_id = '2101' and spm like "%a2h0c%"  
-- and page in ("page_searchresults") 
and os in ("iPhone OS") and app_version='8.4.0' and
(user_nick ="xx" or utdid="xx") 
and site="xx" and ds="20200220" and hh in(16,17) LIMIT  500;

2.使用中間件開發環境-潘多拉
生成工程,配置maven,需要的依賴:com.aliyun.odps、fastjson、httpcore

3.按行讀取SQL查詢內容,單獨處理解析args日誌(搜索原始日誌,track_info外層和內層),pageAndArg1類爲按照頁面維度和arg1頁面控件維度進行日誌判斷,
具體日誌解析爲:找到{開始的位置,截取inner字符串,json格式{}裏所有內容,從{開始截取,直到}的位置,以","拆分,獲取key value
    try {
            int firstIndex = args.indexOf("{");
            // innerJson可能存在"object_title":"搜索","utparam":"{\"yk_abtest\":\"592:1381\"}"
            int lastIndexOf = args.lastIndexOf("}");
            //截取inner字符串,json格式{}裏所有內容,從{開始截取,直到}的位置
            String innerStr = args.substring(firstIndex, lastIndexOf + 1);
            String outerStr = args.substring(lastIndexOf + 2);
            String[] outer = outerStr.toString().split(",");
            innerJSON = JSON.parseObject(innerStr);
            outerJSON = new JSONObject();
            for (int i = 0; i < outer.length; i++) {
                String[] array = outer[i].split("=");
                // 以=拆分之後,爲key value
                outerJSON.put(array[0].trim(), array[1].trim());
            }

4.根據不同的搜索頁面設計不同的類,將公共參數設計爲單獨的公類供。方便代碼維護,一目瞭然
baseKeysCheck.existKeys(array1, record, count);

5.搜索結果頁page_searchresults埋點校驗,按照page && k的邏輯定位arg1,根據前3個條件判斷spm scm具體的控件位置。如搜索的query變了,請更新此代碼裏的k
每個卡片在需要校驗的算法字段前添加註釋,註釋分爲2部分,前面part1==埋點文檔卡片類型+點擊區域,如搜索結果頁1-26卡片一一對應,面part2=QA的case說明
part1+part2給人的感覺直觀,清楚的知道哪部分埋點的測試,測試點,以免漏測



遇到的問題以及分析:
1. 類似xx xx
的scm的B位帶空格,UT日誌是正確的,入庫的時候錯了,腳本用trim()方法去空白處理

2. 如果保證不同的卡片命中相同的正則表達式時,只有1條pass就pass,導致漏測了其他卡片的問題?
代碼中用page.equals("page_searchresults") && k.equals("鶴唳華亭")篩選對應卡片的全部日誌,
這也是與柏拉圖的不用之處,正則平臺用spmCD作爲唯一ID撈取日誌。我的增加了上述條件,極爲重要的page && k
再根據arg1.equals("xx")定位卡片的詳細區域
再根據if (!(spm.matches(spmAB + "PhoneSokuProgram_\\d*.poster") && scm.matches(scmAB + "(rtv|rvideoset-algo).\\S*"))) 判斷具體的點擊位置
最後對每條卡片進行baseKeysCheck.existKeys(array1, record, count);的校驗
baseKeysCheck爲公共方法判斷,具體爲BI要求的字段校驗
/**
 * 通用需求必須存在的算法字段key以及value的判斷
 * public static String[] mustExistKeyOuter = {"spm", "scm"};
 * public static String[] mustExistKeyInner = {"soku_test_ab", "engine", "item_log", "aaid", "k", "source_from", "search_from"};
 */

3. 何保證每條日誌都校驗,沒有漏校驗的日誌,無logMiss?
   if(){
        if () {
            if () {

            } else {
            }
            baseKeysCheck.existKeys(array1, record, count);
        } else if () {
        } else

        {
            System.err.println(arg1Miss() + logPrint(array1, record, count) + "缺失的arg1爲:" + arg1);
        }
    }
             
設計類logPrint,提供全局公共方法(count app_version event_id page arg1 os utdid user_nick args ds hh),大量減少sout 和 serr天長的日誌文案打印
bugDesc() "埋點異常,BUG BUG BUG!!!";
passDesc() "埋點正確,PASS PASS PASS!!!"
arg1Miss() "arg1缺失,未上報,arg1Miss Miss Miss!!!";

4. 日誌第4行解析有問題,解析報錯?
經排查爲此日誌沒有track_info,這種的日誌(page_searchresults_detailsdetaildownloadbutton)佔比極少數,則需要對解析方法單獨處理
debug排查問題,在代碼中打斷點,debug模式運行主函數,在Debugger下,添加或者刪除多餘的代碼
 // 如果沒有track_info的話,也就是隻有外層的spm scm
            if (firstIndex == -1) {

                String[] outer = args.split(",");
                outerJSON = new JSONObject();
                for (int i = 0; i < outer.length; i++) {
                    String[] array = outer[i].split("=");
                    // 以=拆分之後,爲key value
                    outerJSON.put(array[0].trim(), array[1].trim());
                }
                innerJSON = new JSONObject();
                jsonArray.add(innerJSON);
                jsonArray.add(outerJSON);
                return jsonArray;
            }

5. 如何保證日誌中無漏測的埋點,該上報的日誌都上報了?
5.1 在RunProcess中,
5.1.1 在開頭
// 初始化page_searchresults的arg1
        page_searchresults.initList();
        
5.1.2 在結尾
// 判斷最終的集合元素,正常爲空,代表每條日誌都各自命中了應該有的page&arg1,正確,無BUG!!!
           page_searchresults.result();
           
5.2 在page_searchresults中

5.2.1 在開頭
// 定義集合,把搜索page下對應的arg1放到list
    public static List<String> list = new ArrayList<>();
需要在odps裏撈取用戶去重後的arg1,如SELECT distinct(arg1) FROM database.table_name WHERE...
再添加到代碼list 以此保證應該上報的日誌都上報了(初次定義的時候需要人工在UT平臺逐條查看,保證都上報了)
    public static void initList() {
        // page_searchresults下所有的arg1,如有新增的在此處添加
        list.add("xx");
        list.add("xx");
        list.add("xx");
        ...
    }                    
    // 定義方法,供list集合調用,作爲最終的判斷埋點日誌是否漏測的判斷
    public static void result() {
           System.err.println("搜索結果頁埋點故障!!!【page_searchresults_微微一笑很傾城】請檢查是否漏測!!!日誌中不包含的日誌如下==" + list.toString());
       }
      
5.2.2 在結尾
// 遍歷每一條日誌,把命中的arg1分別從集合移除,如果最終集合的元素爲空,則正確,如果有arg1的值,則沒有此日誌,對應的arg1未上報,BUG!!!
    list.remove(arg1);         
           
6. 正則在線多個字符匹配可以添加(A|B|C),需要注意的是,遇到.要用\\轉義
 String spmAB = "a2h0c\\.8166622\\.";
 String scmAB = "20140669\\.search\\.";
 如果單一字符則用Regex.quote(spmAB)
 
 正則表達式的圖形網站 https://regexper.com/
 
7. track_info外層日誌按","拆分,但是部分的scmD位含有==
所以需要修改日誌解析代碼
spm=a2h0c.8166622.xx.selectbutton_2,statisticsTag=7e3f7045e40671fe,scm=20140669.search.xx-algo.xx,utpvid=6,     
          
8. 提取整個page_searchresults xx 的公共埋點區域爲單獨的方法baseKey_page_searchresults
// 10.分類篩選==點擊頂部第一行的"精選|劇集|娛樂|搞笑|文化|自頻道|播單"
// 篩選==點擊頂部篩選-綜合/全部(時長)/全部(清晰度)
// 16.吐槽==翻頁,點擊底部去吐槽

9. All_cards不同卡片類型入口分支判斷 All_arg1List爲不同區域的list集合// 通過k區分調用對應卡片的埋點日誌類

10. 默認頁埋點 A=a,B=b,C=c,track_info={"a":"aa","b":"bb","c":""cc"},D=d,E=e
結果頁埋點 track_info={"a":"aa","b":"bb","c":""cc"},A=a,B=b,C=c,D=d,E=e
// 截取outer字符串,A=a,B=b,C=c格式日誌,默認頁點擊埋點在track_info前面、後面均存在outer格式日誌,結果頁點擊埋點僅在track_info後面存在outer格式日誌
// 因此,分2部分解析日誌,前面part==outerStr1(track_info=爲11個字符) 後面part==outerStr2,2部分拼接==outerStr
            
analysisPageAndArg1
默認頁點擊埋點
track_info={
  "source_from":"home",
  "recext":"reqid=xx",
  "search_q":"小爸爸2",
  "req_id":"reqid=xx",
  "soku_test_ab":"a",
  "engine":"xx",
  "newArch":"1",
  "object_num":2,
  "object_title":"小爸爸2",
  "aaid":"xx",
  "show_q":"小爸爸2",
  "k":"小爸爸2",
  "word_location":1,
  "cn":"精選"
},
spm=a2h0c.8166619.xx.title_2,
statisticsTag=1bf9a9e001608b7d,
scm=20140669.search.personalword.keyword_小爸爸2,
utpvid=59,
pid=69b81504767483cf

11. 由於日誌太多 UT上報慢,爲了更好的排查問題,可以撈取埋點日誌缺失或者有err的ARG1對應的ARGS裏的 
"object_url":"xx&vid=xx==&searchKey=xx",
/maidianRun/mytest
下的IdUtil用base64解密出來vid(ids),再請求video-獲取視頻id的接口,http://xx?ids=xx
或者直接用summary的接口查解密前的vid,接口爲https://xx.com/q/video?id=xx==
後者更簡單,由接口看出,待排查的日誌爲 title: "鄉村愛情12 攤上這樣的爺爺" 點擊此視頻所上報產生的日誌


=================================================================================================
=================================================================================================

結果頁點擊埋點
track_info={
  "alginfo":"xx",
  "group_id":7902690,
  "object_type":103,
  "group_num":69,
  "search_q":"德雲社",
  "object_title":"播放",
  "group_type":2,
  "source_from":"home",
  "show_q":"德雲社",
  "aaid":"xx",
  "searchtab":"0",
  "soku_test_ab":"a",
  "k":"如懿傳",
  "item_log":"xx",
  "req_id":"reqid=xx",
  "search_from":"1",
  "cn":"精選",
  "engine":"xx",
  "word_location":1,
  "object_url":"xx",
  "newArch":"1",
  "recext":"xx"
},
spm=a2h0c.8166622.xx.playbutton,
statisticsTag=3c1bb32294b381f0,
scm=20140669.search.xx-algo.scg_7902690,
utpvid=28,
pid=69b81504767483cf
          
          
該設計的好處:
完美避開UT日誌平臺上報延遲1min-30min的問題,做到一頓操作猛如虎,狂點一番後,直接撈取odps日誌測試需要校驗的埋點,重複正則的完美校驗,無漏測~



--可用於預發包(後端連接線上)、灰度環境、線上環境迴歸測試,需要注意的是,線上與預發的utdid不同,別寫錯了。日誌15分鐘延遲

SELECT app_version, os,utdid,xx,page,event_id,xx,xx,xx,ds,hh,mm FROM database.table_name

where event_id = '2101' and spm like "%xx%"

-- and page in ("page_searchresults")

and os in ("iPhone OS") and app_version='8.4.0' and

(user_nick ="XX" or utdid="XX")

and site="xx" and ds="20200107" and hh in(16,17) LIMIT 500;

 

 

客戶端埋點日誌如下,需要對BI要求的算法字段解析判斷

 

運行結果, 場景:page_searchresults

 

 

提交bug到bug系統

1. 【iOS】搜索結果頁,page_searchresults_recommend_of_PhoneSokuProgram場景下scm的B位多了空格,日誌如下,測試代碼如下

埋點異常,BUG BUG BUG!!!第2條埋點日誌==app_version爲:【8.4.2】,event_id爲:【2101】,page爲:【page_searchresults】,arg1爲:【xx】,os爲:【iPhone OS】,utdid爲:【xx】,user_nick爲:【xx】,args爲:【track_info={"alginfo":"-1rcTrig-2+1-1rcType-2Query2QUERY-1rcQVst-220191111 21:23:38-1abId-2126721-1rkBiz-2querying_esmm_gujin_v1-1pn-20-1sceneId-214177-1rkPos-26-1rcQSim-20.00700-1rcQCate-2Q2Q-1rkScore-20.01258-1rcQuery-2奉天往事-1rcShdCate-2QUERY","group_id":7916307,"object_type":110,"group_num":3,"search_q":"鄉村愛情12上部","object_title":"鶴唳華亭·高甜番外","group_type":1,"source_from":"home","show_q":"鄉村愛情12上部","aaid":"1b49dffdd574dcd175d714e8fea85b2f","searchtab":"0","soku_test_ab":"a","source_id":14,"k":"鶴唳華亭","item_log":"eps_t~1$site~14$show_id~dcfa5b70a2d643318dd3$doc_source~1$eng_source~6$sp_id~1154993465549914112$rec_scg_id~7916307$rec_alginfo~-1show_id-2482416-1sceneId-214945-1scg_id-27916307$rec_recext~reqid=0ec081a9-9132-406b-9450-3b4b33c4b076$scg_id~7916307","req_id":"reqid=dfcc84cd-2733-446e-a32a-dab8912f1684","search_from":"3","cn":"精選","engine":"xx","object_num":1,"newArch":"1","recext":"reqid=dfcc84cd-2733-446e-a32a-dab8912f1684"},spm=a2h0c.8166622.xx.recommend_1,statisticsTag=e3e1fc18eb13ebdd,scm=20140669.search.rtv.set_7916307,utpvid=37,pid=xx】,ds爲:【20200107】,hh爲:【17】,搜索結果頁點擊【鶴唳華亭】的推薦語
 

================================================================================================

 

// 1. 節目卡(正式/專題/花絮),點擊ogc如鶴唳華亭的推薦語
else if (arg1.equals("page_searchresults_recommend_of_PhoneSokuProgram")) {
    String area = card1 + "推薦語";

    if (!(spm.equals(spmAB + "PhoneSokuProgram_\\d*.recommend_\\d*") &&
            scm.matches(scmAB + "rtv.(set|show|video|url|scg|playlist|live)_\\S*"))) {
        System.err.println(bugDesc() + logPrint(array1, record, count) + area);
    } else {
        System.out.println(passDesc() + logPrint(array1, record, count) + area);
    }

    baseKeysCheck.existKeys(array1, record, count);

}

 

排查原因如下:
類似page_searchresults_poster_of_PhoneSokuProgram page_searchresults_recommend_of_PhoneSokuProgram
的scm的B位帶空格,UT日誌是正確的,入庫的時候錯了,腳本用trim()方法去空白處理

 

完美避開UT日誌平臺上報延遲1min-30min的問題,做到一頓操作猛如虎,狂點一番後,直接撈取odps日誌測試需要校驗的埋點

 

 

1. debug排查問題,在代碼中打斷點,debug模式運行主函數,在Debugger下,添加或者刪除多餘的代碼

經排查爲日誌第4行解析有問題,沒有track_info,這種的日誌佔比極少數,則需要對解析方法單獨處理

 

2. 正則

正則在線多個字符匹配可以添加(A|B|C),但代碼如果寫()則會報錯

scm4.matches(scmAB + "(rvideoset-operation|PhoneSokuUgcSeries_\\d*).\\S*")

正確的爲 scm4.matches(scmAB + "rvideoset-operation|PhoneSokuUgcSeries_\\d*.\\S*"))) {

 

感謝我棟哥給我推薦正則表達式的圖形網站   https://regexper.com/

 

神奇 ,找了一下午原因,正則表達式看着沒問題,爲啥一直err??看了好久了 。。。。這個放在 TestDemo是pass的,但放在我的業務代碼是fail的。因爲自己傻缺的把test裏的日誌打印反了success 和fail反了。。。

 

 

如果track_info外層包含scm=20140669.search.rvideoset-algo.video_XNDQ5OTQ4NjgwNA==或者spm=a2h0c.8166622.page.downloadbutton,vid=XNDQyODk3OTMyOA==
則需要把==替換爲空,不影響以,拆分的判斷

 

接入定時任務平臺:

客戶端傳參監控:
cd /Users/lishan/Desktop/code/xx-testing/xx-testing-service

mvn compile 

mvn  exec:java -pl :xx-testing-service -Dexec.mainClass=com.xx.newcpw.sdksearch.RunProcess

 

搜索埋點自動化:
cd /Users/lishan/Desktop/code/xx-testing/xx-testing-service

mvn compile 

mvn  exec:java -pl :xx-testing-service -Dexec.mainClass=com.xx.newcpw.sdksearch.RunProcess

 

git地址2者公用一個:

http://xx.xx.git   
分支 clientreq

 

未完待續。。。。readme  流程圖產出,代碼完善,接入釘釘報警,錯誤 正常信息入庫,接口開發,前端開發等。。。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章