App性能監(jiān)控-newRelicSDK使用及攔截上報(bào)方案

隨著應(yīng)用的發(fā)展越來(lái)越大筷转,產(chǎn)品的開(kāi)發(fā)和測(cè)試逐漸開(kāi)始關(guān)注app的在線運(yùn)行性能蔚万。最近一直在關(guān)注這個(gè)方向,說(shuō)一下自己的心得和體會(huì)徽曲。

所謂的性能監(jiān)控态兴,并不是做出一堆花哨的圖表讓人賞心悅目。其實(shí)目的只有兩個(gè)疟位,一個(gè)是能夠?qū)崟r(shí)發(fā)現(xiàn)線上的問(wèn)題瞻润,通過(guò)報(bào)警機(jī)制通知到相關(guān)負(fù)責(zé)人;另外一個(gè)就是能夠看到歷史數(shù)據(jù)甜刻,供測(cè)試和開(kāi)發(fā)進(jìn)行性能優(yōu)化绍撞。那么監(jiān)控的關(guān)鍵是確定監(jiān)控指標(biāo),在監(jiān)控指標(biāo)的指導(dǎo)下確定需要客戶端打點(diǎn)收集的日志得院。

APP性能監(jiān)控指標(biāo)

最近調(diào)研了一下這個(gè)方向傻铣,行業(yè)內(nèi)把這個(gè)方向稱為APM(application performance management)。國(guó)內(nèi)外都有不少公司在做這方面的產(chǎn)品祥绞,一些大公司為了防止應(yīng)用監(jiān)控?cái)?shù)據(jù)的外泄非洲,也會(huì)自行開(kāi)發(fā)性能監(jiān)控管理平臺(tái)。國(guó)內(nèi)做得比較好的如基調(diào)蜕径、博睿两踏、云測(cè)、聽(tīng)云等兜喻,國(guó)外有New Relic梦染、Blueware、OneAPM等朴皆。 各個(gè)平臺(tái)的技術(shù)方案大同小異(這里主要說(shuō)的是IOS平臺(tái))帕识,提供一個(gè)集成到應(yīng)用的SDK(static framework 或者 .a 文件), 然后收集日志上報(bào)到其后臺(tái)進(jìn)行數(shù)據(jù)處理和緯度分析。這些平臺(tái)的商業(yè)策略一般都是先免費(fèi)提供試用遂铡,再進(jìn)行租用收費(fèi)的方式肮疗。

APP的性能指標(biāo)主要分為兩大類(lèi):InterActions(UI交互) 和 Network (網(wǎng)絡(luò)連接)。在這兩個(gè)大分類(lèi)下扒接,會(huì)有如下細(xì)分指標(biāo):

InterActions:(按時(shí)間-版本:+device類(lèi)型伪货,+os類(lèi)型)

  • APP啟動(dòng)次數(shù)们衙、APP啟動(dòng)平均時(shí)間;
  • Controller display次數(shù)超歌、平均display時(shí)間砍艾;
  • Controller display過(guò)程中各個(gè)method(包括UI thread蒂教、worker thread中的method)的平均執(zhí)行時(shí)間巍举;

Network方面:(按時(shí)間-版本:+域名,+地區(qū)凝垛,+運(yùn)營(yíng)商懊悯, +連接網(wǎng)絡(luò)類(lèi)型)

  • 平均相應(yīng)時(shí)間
  • rpm(一分鐘請(qǐng)求次數(shù))
  • 總耗時(shí)
  • 傳輸數(shù)據(jù)大小
  • 再具體到某個(gè)API接口:
    (1) 平均http響應(yīng)時(shí)間 (區(qū)分web Application(webview) 和 network);
    (2) rpm梦皮;
    (3) 平均數(shù)據(jù)傳輸大刑糠帧(區(qū)分send和receive);

在兩大指標(biāo)上會(huì)增加如下方面的維度: 接入網(wǎng)絡(luò)剑肯、運(yùn)營(yíng)商捧毛、設(shè)備、系統(tǒng)版本让网、地區(qū)呀忧、app版本、統(tǒng)計(jì)時(shí)間溃睹;

NewRelic SDK使用說(shuō)明

我主要關(guān)注了國(guó)內(nèi)的聽(tīng)云平臺(tái)和國(guó)外的NewRelic平臺(tái)而账。國(guó)內(nèi)聽(tīng)云的統(tǒng)計(jì)平臺(tái)注冊(cè)只能看到非常基礎(chǔ)的統(tǒng)計(jì)因篇,一點(diǎn)細(xì)分分析維度泞辐,就提示你升級(jí)套餐,當(dāng)然你可以申請(qǐng)14天免費(fèi)試用竞滓,然后就是市場(chǎng)給你打電話過(guò)來(lái)咐吼。 其SDK中的framework也只提供一個(gè)頭文件,想要對(duì)統(tǒng)計(jì)數(shù)據(jù)的定制基本上沒(méi)有商佑。于是果斷切換到國(guó)外的newRelic平臺(tái)汽烦,newRlic平臺(tái)需要vpn訪問(wèn)才能快點(diǎn),一注冊(cè)所有的功能都能夠試用莉御,當(dāng)然試用期也只有14天撇吞。

關(guān)注一下SDK的使用,SDK提供了眾多可配置的頭文件礁叔,讓你能夠更加清楚的了解sdk提供的功能牍颈;

(1)最基礎(chǔ)的使用,當(dāng)然就是通過(guò)Apptoken注冊(cè)使用:(注意一下琅关,newRelic集成在debug時(shí)會(huì)檢查當(dāng)前應(yīng)用中hook的使用煮岁,需要將newrelic的注冊(cè)使用放到所有hook之后讥蔽,一般放到appdidfinishLaunch靠后的位置)

#import <NewRelicAgent/NewRelic.h>

[NewRelicAgent startWithApplicationToken:@"token"];

如果是最基礎(chǔ)的用法,我們可以通過(guò)charles攔截其數(shù)據(jù)上報(bào)画机,可以發(fā)現(xiàn)request和response的數(shù)據(jù)都是通過(guò)ssl加密冶伞、https傳輸,看不到明文數(shù)據(jù)步氏。如果需要看到明文數(shù)據(jù)可以使用非加密接口+ (void)startWithApplicationToken:(NSString*)appToken withoutSecurity:(BOOL)disableSSL

(2) SDK集成了各種指標(biāo)收集响禽,包括Interaction、SwiftInteraction荚醒、Crash芋类、NSURLSession、HTTPResponse等界阁。如下代碼所示:

typedef NS_OPTIONS(unsigned long long, NRMAFeatureFlags){
    NRFeatureFlag_InteractionTracing                    = 1 << 1,
    NRFeatureFlag_SwiftInteractionTracing               = 1 << 2, //disabled by default 
    NRFeatureFlag_CrashReporting                        = 1 << 3,
    NRFeatureFlag_NSURLSessionInstrumentation           = 1 << 4,
    NRFeatureFlag_HttpResponseBodyCapture               = 1 << 5,
    NRFeatureFlag_ExperimentalNetworkingInstrumentation = 1 << 13, //disabled by default
    NRFeatureFlag_AllFeatures                           = ~0ULL //in 32-bit land the alignment is 4bytes
};

你可以按照自己的需要指定需要收集的指標(biāo)數(shù)據(jù)妒牙,使用

+ (void) enableFeatures:(NRMAFeatureFlags)featureFlags; 
+ (void) disableFeatures:(NRMAFeatureFlags)featureFlags;

(3) 關(guān)于Interaction的主要方案就是hook controller中的各個(gè)生命周期方法片酝,NewRelicSDK中主要攔截了如下方法:

UIViewController

  1. viewDidLoad
  2. viewWillAppear:
  3. viewDidAppear:
  4. viewWillDisappear:
  5. viewDidDisappear:
  6. viewWillLayoutSubviews
  7. viewDidLayoutSubviews

UIImage:

  1. imageNamed:
  2. imageWithContentsOfFile:
  3. imageWithData:
  4. imageWithData:scale:
  5. initWithContentsOfFile:
  6. initWithData:
  7. initWithData:scale:

NSJSONSerialization:

  1. JSONObjectWithData:options:error:
  2. JSONObjectWithStream:options:error:
  3. dataWithJSONObject:options:error:
  4. writeJSONObject:toStream:options:error:

NSManagedObjectContext

  1. executeFetchRequest:error:
  2. processPendingChanges

(4)在ARC模式下,你也可以使用如下宏攔截你想統(tǒng)計(jì)的應(yīng)用中關(guān)鍵方法:

- (void)myMethod
{
  NR_TRACE_METHOD_START(0);

  // … existing code

  NR_TRACE_METHOD_STOP;
}

更多的使用請(qǐng)關(guān)注其SDK文檔說(shuō)明:
https://docs.newrelic.com/docs/mobile-monitoring/mobile-sdk-api/new-relic-mobile-sdk-api/work-ios-sdk-api

newRelic SDK的數(shù)據(jù)攔截上報(bào)

newRelic SDK已經(jīng)做得非常精致,但是如果我們不想把數(shù)據(jù)上報(bào)到第三方平臺(tái)管理蚓哩,那應(yīng)該怎么辦呢帖汞,自己去研發(fā)一套纬朝,耗時(shí)費(fèi)力婚脱,而且還費(fèi)力不討好。那何不做一個(gè)數(shù)據(jù)攔截重付,把數(shù)據(jù)轉(zhuǎn)發(fā)到我們自己的后臺(tái)平臺(tái)呢顷级?

static framework public的頭文件并不包括上傳class的頭文件,但是當(dāng)網(wǎng)絡(luò)不好或者沒(méi)有網(wǎng)的時(shí)候确垫,我們可以從控制臺(tái)打印上報(bào)數(shù)據(jù)失敗的日志看到一些端倪弓颈,我們可以找到上傳日志的方法所在的類(lèi)為“NRMAHarvesterConnection”,如果是ssl上傳删掀,日志為send方法翔冀,如果是非ssl上傳,日志中顯示為sendData方法披泪;

為了更好的知道類(lèi)中方法的分布纤子,我們可以用class-dump-z工具解析出SDK中所有的頭文件。 class-dump-z是不能直接dump framework中的頭文件款票,解析出來(lái)的頭文件中會(huì)有一個(gè)source 為null的提示控硼。 一開(kāi)始覺(jué)得可能是因?yàn)閒ramework做了加密處理,找了一個(gè)越獄機(jī)器在cydia中安裝了openssh-how-to工具艾少,通過(guò)sftp把framework和Clutch上傳到越獄機(jī)器中卡乾,開(kāi)始用Clutch進(jìn)行解密,發(fā)現(xiàn)Clutch并不能直接解析缚够,也不能解析debug安裝的調(diào)試app幔妨。

最后終于將集成了newRelic SDK的的app 通過(guò)archive打包鹦赎,導(dǎo)出一個(gè)ipa。解壓出app目錄之后误堡,再用class-dump-z工具對(duì)app目錄的二進(jìn)制文件進(jìn)行頭文件導(dǎo)出古话,這時(shí)候我們就能夠看到sdk中的所有頭文件了;

我找到“NRMAHarvesterConnection”文件锁施,如下所示陪踩,可以看到其中的sendData方法。

#import <XXUnknownSuperclass.h> // Unknown library

@class NRMAConnectInformation, NSString;

@interface NRMAHarvesterConnection : XXUnknownSuperclass {
    BOOL _useSSL;
    NRMAConnectInformation* _connectionInformation;
    NSString* _collectorHost;
    NSString* _applicationToken;
    NSString* _crossProcessID;
    long long _serverTimestamp;
}
@property(assign) BOOL useSSL;
@property(retain) NSString* crossProcessID;
@property(assign) long long serverTimestamp;
@property(retain) NSString* applicationToken;
@property(retain) NSString* collectorHost;
@property(retain) NRMAConnectInformation* connectionInformation;
-(void).cxx_destruct;
-(id)collectorHostURL:(id)url;
-(id)collectorHostDataURL;
-(id)collectorConnectURL;
-(id)createDataPost:(id)post;
-(id)createConnectPost:(id)post;
-(id)sendData:(id)data;
-(id)sendConnect;
-(id)send:(id)send;
-(id)createPostWithURI:(id)uri message:(id)message;
-(id)init;
@end

為了更好的了解方法的輸入和輸出參數(shù)沾谜,我使用了阿里最近開(kāi)源的ali-wax的lua調(diào)試工具進(jìn)行了sendData的方法的輸入輸出了解, 我們可以看到輸入?yún)?shù)data的class類(lèi)型膊毁,是一個(gè)“NRMAHarvestData”胀莹,我們同樣可以找到其頭文件基跑,查詢到里面的JSONObject方法,可以把data轉(zhuǎn)化成一個(gè)json對(duì)象描焰。 得到這個(gè)對(duì)象了我們就可以將數(shù)據(jù)轉(zhuǎn)發(fā)到我們自己的平臺(tái)媳否,并偽造一個(gè)http上傳成功或失敗的對(duì)象給sendData方法進(jìn)行內(nèi)存數(shù)據(jù)刪除處理即可。

waxClass{"NRMAHarvesterConnection"}

--如果需要上報(bào)荆秦,攔截這個(gè)方法即可
function sendData(self,data)
  print(data:class())
  jsonObject = data:JSONObject()
  self:ORIGsendData(data)
end

注:這里我只提供一種方案篱竭,公司產(chǎn)品并沒(méi)有采用這種方法,因?yàn)槲覀冏约旱男阅鼙O(jiān)控雖然數(shù)據(jù)粒度不夠步绸,已經(jīng)足夠日常查詢問(wèn)題使用了掺逼。更多是分享一下取巧的思路,以及紀(jì)錄一下破解的過(guò)程瓤介。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吕喘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刑桑,更是在濱河造成了極大的恐慌氯质,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祠斧,死亡現(xiàn)場(chǎng)離奇詭異闻察,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)琢锋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)辕漂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吴超,你說(shuō)我怎么就攤上這事钉嘹。” “怎么了烛芬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵隧期,是天一觀的道長(zhǎng)飒责。 經(jīng)常有香客問(wèn)我,道長(zhǎng)仆潮,這世上最難降的妖魔是什么宏蛉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮性置,結(jié)果婚禮上拾并,老公的妹妹穿的比我還像新娘。我一直安慰自己鹏浅,他們只是感情好嗅义,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著隐砸,像睡著了一般之碗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上季希,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天褪那,我揣著相機(jī)與錄音,去河邊找鬼式塌。 笑死博敬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的峰尝。 我是一名探鬼主播偏窝,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼武学!你這毒婦竟也來(lái)了祭往?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤劳淆,失蹤者是張志新(化名)和其女友劉穎链沼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體沛鸵,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡括勺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了曲掰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疾捍。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖栏妖,靈堂內(nèi)的尸體忽然破棺而出乱豆,到底是詐尸還是另有隱情,我是刑警寧澤吊趾,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布宛裕,位于F島的核電站瑟啃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏揩尸。R本人自食惡果不足惜蛹屿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岩榆。 院中可真熱鬧错负,春花似錦、人聲如沸勇边。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粒褒。三九已至识颊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怀浆,已是汗流浹背谊囚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工怕享, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留执赡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓函筋,卻偏偏與公主長(zhǎng)得像沙合,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子跌帐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容