blob: 297b31fcaeef720b58e943b9aa18d120d6d9149b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#import "WXMonitor.h"
#import "WXSDKEngine.h"
#import "WXSDKInstance.h"
#import "WXAppMonitorProtocol.h"
#import "WXHandlerFactory.h"
#import "WXLog.h"
#import "WXUtility.h"
#import "WXComponentManager.h"
#import "WXThreadSafeMutableDictionary.h"
#import "WXAppConfiguration.h"
#import "WXAnalyzerProtocol.h"
#import "WXSDKInstance_performance.h"
#import "WXAnalyzerCenter+Transfer.h"
static NSString *const kStartKey = @"start";
static NSString *const kEndKey = @"end";
@implementation WXMonitor
#pragma mark - Performance Monitor
static WXThreadSafeMutableDictionary *globalPerformanceDict;
+ (void)performancePoint:(WXPerformanceTag)tag willStartWithInstance:(WXSDKInstance *)instance
{
NSMutableDictionary *performanceDict = [self performanceDictForInstance:instance];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:2];
dict[kStartKey] = @(CACurrentMediaTime() * 1000);
performanceDict[@(tag)] = dict;
[dict setValue:@(tag) forKey:@"tag"];
}
+ (void)performancePoint:(WXPerformanceTag)tag didEndWithInstance:(WXSDKInstance *)instance
{
NSMutableDictionary *performanceDict = [self performanceDictForInstance:instance];
NSMutableDictionary *dict = performanceDict[@(tag)];
if (!dict) {
WXLogDebug(@"Performance point:%ld, in instance:%@, did not have a start", (unsigned long)tag, instance.instanceId);
return;
}
if (dict[kEndKey]) {
// not override.
return;
}
dict[kEndKey] = @(CACurrentMediaTime() * 1000);
if (tag == WXPTFirstScreenRender) {
[instance.apmInstance onStage:KEY_PAGE_STAGES_FSRENDER];
instance.apmInstance.isFSEnd = YES;
}
// if (tag == WXPTAllRender) {
// [self performanceFinish:instance];
// }
}
+ (void)performancePoint:(WXPerformanceTag)tag didSetValue:(double)value withInstance:(WXSDKInstance *)instance
{
NSMutableDictionary *performanceDict = [self performanceDictForInstance:instance];
if (performanceDict[@(tag)]) {
return;
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:2];
dict[kStartKey] = @(0);
dict[kEndKey] = @(value);
performanceDict[@(tag)] = dict;
}
+ (BOOL)performancePoint:(WXPerformanceTag)tag isRecordedWithInstance:(WXSDKInstance *)instance
{
NSMutableDictionary *performanceDict = [self performanceDictForInstance:instance];
if (!performanceDict) {
return NO;
}
NSMutableDictionary *dict = performanceDict[@(tag)];
return dict && dict[kStartKey] && dict[kEndKey];
}
+ (void)performanceFinish:(WXSDKInstance *)instance
{
[self performanceFinishWithState:MonitorCommit instance:instance];
}
+ (void)performanceFinishWithState:(CommitState) state instance:(WXSDKInstance *)instance
{
BOOL collectValue = (state == MonitorCommit)?TRUE:[WXAnalyzerCenter isOpen];
if(!collectValue){
return;
}
NSMutableDictionary *commitDict = [NSMutableDictionary dictionary];
commitDict[BIZTYPE] = instance.bizType ?: @"";
commitDict[PAGENAME] = instance.pageName ?: @"";
commitDict[WXSDKVERSION] = WX_SDK_VERSION;
commitDict[JSLIBVERSION] = [WXAppConfiguration JSFrameworkVersion];
commitDict[JSLIBSIZE] = [NSNumber numberWithUnsignedInteger:[WXAppConfiguration JSFrameworkLibSize]];
if (instance.userInfo[@"weex_bundlejs_connectionType"]) {
commitDict[@"connectionType"] = instance.userInfo[@"weex_bundlejs_connectionType"];
}
if (instance.userInfo[@"weex_bundlejs_requestType"]) {
commitDict[@"requestType"] = instance.userInfo[@"weex_bundlejs_requestType"];
}
if (instance.userInfo[@"weex_bundlejs_networkType"]) {
commitDict[NETWORKTYPE] = instance.userInfo[@"weex_bundlejs_networkType"];
}
if (instance.userInfo[@"weex_bundlejs_cacheType"]) {
commitDict[CACHETYPE] = instance.userInfo[@"weex_bundlejs_cacheType"];
}
if (instance.userInfo[CACHEPROCESSTIME]) {
commitDict[CACHEPROCESSTIME] = instance.userInfo[CACHEPROCESSTIME];
}
if (instance.userInfo[CACHERATIO]) {
commitDict[CACHERATIO] = instance.userInfo[CACHERATIO];
}
if (instance.userInfo[WXCUSTOMMONITORINFO]) {
if([instance.userInfo[WXCUSTOMMONITORINFO] isKindOfClass:[NSDictionary class]]) {
commitDict[WXCUSTOMMONITORINFO] = [WXUtility JSONString:instance.userInfo[WXCUSTOMMONITORINFO]];
}else if([instance.userInfo[WXCUSTOMMONITORINFO] isKindOfClass:[NSString class]]) {
commitDict[WXCUSTOMMONITORINFO] = instance.userInfo[WXCUSTOMMONITORINFO];
}
}
WXPerformBlockOnComponentThread(^{
WXPerformBlockOnMainThread(^{
[self commitPerformanceWithDict:commitDict instance:instance comitState:state];
});
});
}
+ (void)commitPerformanceWithDict:(NSMutableDictionary *)commitDict instance:(WXSDKInstance *)instance comitState:(CommitState) state
{
static NSDictionary *commitKeyDict;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// non-standard perf commit names, remove this hopefully.
commitKeyDict = @{
@(WXPTInitalize) : SDKINITTIME,
@(WXPTInitalizeSync) : SDKINITINVOKETIME,
@(WXPTFrameworkExecute) : JSLIBINITTIME,
@(WXPTJSDownload) : NETWORKTIME,
@(WXPTJSCreateInstance) : COMMUNICATETIME,
@(WXFirstScreenJSFExecuteTime) : FIRSETSCREENJSFEXECUTETIME,
@(WXPTFirstScreenRender) : SCREENRENDERTIME,
@(WXPTAllRender) : TOTALTIME,
@(WXPTBundleSize) : JSTEMPLATESIZE,
@(WXPTFsCallJsTime): M_FS_CALL_JS_TIME,
@(WXPTFsCallJsNum): M_FS_CALL_JS_NUM,
@(WXPTFsCallNativeTime): M_FS_CALL_NATIVE_TIME,
@(WXPTFsCallNativeNum): M_FS_CALL_NATIVE_NUM,
@(WXPTFsCallEventNum): M_FS_CALL_EVENT_NUM,
@(WXPTMaxDeepVDom): M_MAX_DEEP_VDOM,
@(WXPTImgWrongSizeNum): M_IMG_WRONG_SIZE_NUM,
@(WXPTTimerNum): M_TIMER_NUM,
@(WXPTCellExceedNum):M_CELL_EXCEED_NUM,
@(WXPTWrongImgSize):M_IMG_WRONG_SIZE_NUM,
@(WXPTInteractionTime):M_INTERACTION_TIME,
@(WXPTFsReqNetNum):M_FS_REQUEST_NET_NUM,
@(WXPTComponentCreateTime):M_COMPONENT_TIME,
@(WXPTComponentCount):COMPONENTCOUNT,
@(WXPTInteractionAddCount):M_INTERACTION_ADD_COUNT,
@(WXPTInteractionLimitAddCount):M_INTERACTION_LIMIT_ADD_COUNT,
@(WXPNewFSRenderTime):M_NEW_FS_RENDER_TIME
};
});
for (int tag = 0; tag < WXPTEnd; tag++) {
NSMutableDictionary *performanceDict = tag <= WXPTFrameworkExecute ? globalPerformanceDict : instance.performanceDict;
NSMutableDictionary *keyDict = performanceDict[@(tag)];
if (!keyDict || ![keyDict isKindOfClass:[NSMutableDictionary class]]) {
continue;
}
NSNumber *start = keyDict[kStartKey];
NSNumber *end = keyDict[kEndKey];
if (!start || !end) {
if (state == MonitorCommit) {
WXLogDebug(@"Performance point:%d, in instance:%@, did not have a start or end", tag, instance);
}
continue;
}
NSString *commitKey = commitKeyDict[@(tag)];
if (commitKey) {
commitDict[commitKey] = @([end integerValue] - [start integerValue]);
}else{
WXLogWarning(@"commitKey is nil with tag :%d",tag);
}
}
commitDict[@"instanceId"] = [instance instanceId]?:@"";
//new performance point
// if (!commitDict[SCREENRENDERTIME] && commitDict[TOTALTIME]) {
// commitDict[SCREENRENDERTIME] = commitDict[TOTALTIME];
// }
commitDict[CALLCREATEINSTANCETIME] = commitDict[COMMUNICATETIME];
commitDict[COMMUNICATETOTALTIME] = commitDict[TOTALTIME];
if (commitDict[SCREENRENDERTIME]) {
commitDict[FSRENDERTIME] = commitDict[SCREENRENDERTIME];
}
else {
commitDict[FSRENDERTIME] = @"-1";
}
if(state == MonitorCommit)
{
id<WXAppMonitorProtocol> appMonitor = [WXHandlerFactory handlerForProtocol:@protocol(WXAppMonitorProtocol)];
if (appMonitor && [appMonitor respondsToSelector:@selector(commitAppMonitorArgs:)]){
[appMonitor commitAppMonitorArgs:commitDict];
}
[self printPerformance:commitDict];
}
}
+ (NSMutableDictionary *)performanceDictForInstance:(WXSDKInstance *)instance
{
NSMutableDictionary *performanceDict;
if (!instance) {
if (!globalPerformanceDict) {
globalPerformanceDict = [WXThreadSafeMutableDictionary dictionary];
}
performanceDict = globalPerformanceDict;
} else {
performanceDict = instance.performanceDict;
}
return performanceDict;
}
+ (void)printPerformance:(NSDictionary *)commitDict
{
if ([WXLog logLevel] < WXLogLevelLog) {
return;
}
NSMutableString *performanceString = [NSMutableString stringWithString:@"Performance:"];
for (NSString *commitKey in commitDict) {
[performanceString appendFormat:@"\n %@: %@,", commitKey, commitDict[commitKey]];
}
WXLog(@"%@", performanceString);
}
#pragma mark - Error Monitor
+ (void)monitoringPointDidSuccess:(WXMonitorTag)tag onPage:(NSString *)pageName
{
[self monitoringPoint:tag isSuccss:YES error:nil onPage:pageName];
}
+ (void)monitoringPoint:(WXMonitorTag)tag didFailWithError:(NSError *)error onPage:(NSString *)pageName
{
[self monitoringPoint:tag isSuccss:NO error:error onPage:pageName];
}
+ (void)monitoringPoint:(WXMonitorTag)tag isSuccss:(BOOL)success error:(NSError *)error onPage:(NSString *)pageName
{
if (!success) {
WXLogError(@"%@", error.localizedDescription);
}
id<WXAppMonitorProtocol> appMonitorHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXAppMonitorProtocol)];
if ([appMonitorHandler respondsToSelector:@selector(commitAppMonitorAlarm:monitorPoint:success:errorCode:errorMsg:arg:)]) {
NSString *errorCodeStr = [NSString stringWithFormat:@"%ld", (long)error.code];
static NSDictionary *monitorNameDict;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
monitorNameDict = @{
@(WXMTJSFramework) : @"jsFramework",
@(WXMTJSDownload) : @"jsDownload",
@(WXMTJSBridge) : @"jsBridge",
@(WXMTNativeRender) : @"domModule"
};
});
pageName = pageName ? : [WXSDKEngine topInstance].pageName;
[appMonitorHandler commitAppMonitorAlarm:@"weex" monitorPoint:monitorNameDict[@(tag)] success:success errorCode:errorCodeStr errorMsg:error.localizedDescription arg:pageName];
}
}
@end