const pkg = require('../package.json'); let beacon = null; const getBeacon = (delay) => { if (!beacon) { // 涓嶆斁鍦ㄩ《灞傛槸閬垮厤棣栨寮曞叆灏辫鍔犺浇锛屼粠鑰岄伩鍏嶅湪鏌愪簺鐜姣斿webworker閲屽姞杞界伅濉攕dk鍐厀indow鐩稿叧瀵硅薄鎶ラ敊 const BeaconAction = require('../lib/beacon.min'); beacon = new BeaconAction({ appkey: '0AND0VEVB24UBGDU', versionCode: pkg.version, channelID: 'js_sdk', //娓犻亾,閫夊~ openid: 'openid', // 鐢ㄦ埛id, 閫夊~ unionid: 'unid', //鐢ㄦ埛unionid , 绫讳技idfv,閫夊~ strictMode: false, //涓ヨ嫑妯″紡寮€鍏�, 鎵撳紑涓ヨ嫑妯″紡浼氫富鍔ㄦ姏鍑哄紓甯�, 涓婄嚎璇峰姟蹇呭叧闂�!!! delay, // 鏅€氫簨浠跺欢杩熶笂鎶ユ椂闂�(鍗曚綅姣), 榛樿1000(1绉�),閫夊~ sessionDuration: 60 * 1000, // session鍙樻洿鐨勬椂闂撮棿闅�, 涓€涓敤鎴锋寔缁�30鍒嗛挓(榛樿鍊�)娌℃湁浠讳綍涓婃姤鍒欑畻鍙︿竴娆� session,姣忓彉鏇翠竴娆ession涓婃姤涓€娆″惎鍔ㄤ簨浠�(rqd_applaunched),浣跨敤姣(ms),鏈€灏忓€�30绉�,閫夊~ }); } return beacon; }; const utils = { // 鐢熸垚uid 姣忎釜閾捐矾瀵瑰簲鍞竴涓€鏉id getUid() { var S4 = function () { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); }; return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4(); }, // 鑾峰彇缃戠粶绫诲瀷 getNetType() { if (typeof navigator === 'object') { const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; return connection?.type || connection?.effectiveType || 'unknown'; } return 'unknown'; }, // 鑾峰彇pc绔搷浣滅郴缁熺被鍨� getOsType() { if (typeof navigator !== 'object') { return 'unknown os'; } var agent = navigator.userAgent.toLowerCase(); var isMac = /macintosh|mac os x/i.test(navigator.userAgent); if (agent.indexOf('win32') >= 0 || agent.indexOf('wow32') >= 0) { return 'win32'; } if (agent.indexOf('win64') >= 0 || agent.indexOf('wow64') >= 0) { return 'win64'; } if (isMac) { return 'mac'; } return 'unknown os'; }, isMobile() { const exp = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i; if (typeof navigator === 'object' && navigator.userAgent.match(exp)) { return true; // 绉诲姩绔� } return false; // PC绔� }, isAndroid() { const exp = /(Android|Adr|Linux)/i; if (typeof navigator === 'object' && navigator.userAgent.match(exp)) { return true; } return false; }, isIOS() { const exp = /(iPhone|iPod|iPad|iOS)/i; if (typeof navigator === 'object' && navigator.userAgent.match(exp)) { return true; } return false; }, isOtherMobile() { return isMobile && !isAndroid && !isIOS; }, // 鑾峰彇娴忚鍣ㄧ被鍨� getDeviceName() { if (typeof navigator !== 'object') { return 'unknown device'; } const explorer = navigator.userAgent.toLowerCase(); // 鑵捐浼氳鍐呯疆娴忚鍣� if (explorer.includes('app/tencent_wemeet')) { return 'tencent_wemeet'; } // 閬ㄦ父娴忚鍣� if (explorer.indexOf('maxthon') >= 0) { const match = explorer.match(/maxthon\/([\d.]+)/); const ver = (match && match[1]) || ''; return `鍌叉父娴忚鍣� ${ver}`.trim(); } // QQ娴忚鍣� if (explorer.indexOf('qqbrowser') >= 0) { const match = explorer.match(/qqbrowser\/([\d.]+)/); const ver = (match && match[1]) || ''; return `QQ娴忚鍣� ${ver}`.trim(); } // 鎼滅嫍娴忚鍣� if (explorer.indexOf('se 2.x') >= 0) { return '鎼滅嫍娴忚鍣�'; } // 寰俊娴忚鍣� if (explorer.indexOf('wxwork') >= 0) { return '寰俊鍐呯疆娴忚鍣�'; } // ie if (explorer.indexOf('msie') >= 0) { const match = explorer.match(/msie ([\d.]+)/); const ver = (match && match[1]) || ''; return `IE ${ver}`.trim(); } // firefox if (explorer.indexOf('firefox') >= 0) { const match = explorer.match(/firefox\/([\d.]+)/); const ver = (match && match[1]) || ''; return `Firefox ${ver}`.trim(); } // Chrome if (explorer.indexOf('chrome') >= 0) { const match = explorer.match(/chrome\/([\d.]+)/); const ver = (match && match[1]) || ''; return `Chrome ${ver}`.trim(); } // Opera if (explorer.indexOf('opera') >= 0) { const match = explorer.match(/opera.([\d.]+)/); const ver = (match && match[1]) || ''; return `Opera ${ver}`.trim(); } // Safari if (explorer.indexOf('safari') >= 0) { const match = explorer.match(/version\/([\d.]+)/); const ver = (match && match[1]) || ''; return `Safari ${ver}`.trim(); } if (explorer.indexOf('edge') >= 0) { const match = explorer.match(/edge\/([\d.]+)/); const ver = (match && match[1]) || ''; return `edge ${ver}`.trim(); } return explorer.substr(0, 200); }, }; const constant = { isMobile: utils.isMobile(), isBrowser: !utils.isMobile(), mobileOsType: utils.isAndroid() ? 'android' : utils.isIOS ? 'ios' : 'other_mobile', pcOsType: utils.getOsType(), }; // 璁惧淇℃伅锛屽彧鍙栦竴娆″€� const deviceInfo = { // 鈫撲笂鎶ラ」 deviceType: constant.isMobile ? 'mobile' : constant.isBrowser ? 'browser' : 'unknown', devicePlatform: constant.isMobile ? constant.mobileOsType : constant.pcOsType, deviceName: utils.getDeviceName(), //娴忚鍣ㄥ悕绉� }; // 鍒嗗潡涓婁紶鍘熷瓙鏂规硶 const sliceUploadMethods = [ 'multipartInit', 'multipartUpload', 'multipartComplete', 'multipartList', 'multipartListPart', 'multipartAbort', ]; const uploadApi = ['putObject', 'postObject', 'appendObject', 'sliceUploadFile', 'uploadFile', 'uploadFiles'].concat( sliceUploadMethods ); const downloadApi = ['getObject']; function getEventCode(apiName) { if (uploadApi.includes(apiName)) { return 'cos_upload'; } if (downloadApi.includes(apiName)) { return 'cos_download'; } return 'base_service'; } // 涓婃姤鍙傛暟椹煎嘲鏀逛笅鍒掔嚎 function camel2underline(key) { return key.replace(/([A-Z])/g, '_$1').toLowerCase(); } function formatParams(params) { const formattedParams = {}; const allReporterKeys = [ 'tracePlatform', 'cossdkVersion', 'region', 'networkType', 'host', 'accelerate', 'requestPath', 'size', 'httpMd5', 'httpSign', 'httpFull', 'name', 'result', 'tookTime', 'errorNode', 'errorCode', 'errorMessage', 'errorRequestId', 'errorStatusCode', 'errorServiceName', 'errorType', 'traceId', 'bucket', 'appid', 'partNumber', 'retryTimes', 'reqUrl', 'customId', 'fullError', 'deviceType', 'devicePlatform', 'deviceName', ]; const successKeys = [ 'tracePlatform', 'cossdkVersion', 'region', 'bucket', 'appid', 'networkType', 'host', 'accelerate', 'requestPath', 'partNumber', 'size', 'name', 'result', 'tookTime', 'errorRequestId', 'retryTimes', 'reqUrl', 'customId', 'deviceType', 'devicePlatform', 'deviceName', ]; // 闇€瑕佷笂鎶ョ殑鍙傛暟瀛楁 const reporterKeys = params.result === 'Success' ? successKeys : allReporterKeys; for (let key in params) { if (!reporterKeys.includes(key)) continue; const formattedKey = camel2underline(key); formattedParams[formattedKey] = params[key]; } return formattedParams; } // 閾捐矾杩借釜鍣� class Tracker { constructor(opt) { const { parent, traceId, bucket, region, apiName, fileKey, fileSize, accelerate, customId, delay, deepTracker } = opt; const appid = (bucket && bucket.substr(bucket.lastIndexOf('-') + 1)) || ''; this.parent = parent; this.deepTracker = deepTracker; this.delay = delay; // 涓婃姤鐢ㄥ埌鐨勫瓧娈� this.params = { // 閫氱敤瀛楁 cossdkVersion: pkg.version, region, networkType: '', host: '', accelerate: accelerate ? 'Y' : 'N', requestPath: fileKey || '', size: fileSize || -1, httpMd5: 0, // MD5鑰楁椂 httpSign: 0, // 璁$畻绛惧悕鑰楁椂 httpFull: 0, // http璇锋眰鑰楁椂 name: apiName || '', result: '', // sdk api璋冪敤缁撴灉Success銆丗ail tookTime: 0, // 鎬昏€楁椂 errorNode: '', errorCode: '', errorMessage: '', errorRequestId: '', errorStatusCode: 0, errorServiceName: '', // js琛ュ厖瀛楁 tracePlatform: 'cos-js-sdk-v5', // 涓婃姤骞冲彴=js traceId: traceId || utils.getUid(), // 姣忔潯涓婃姤鍞竴鏍囪瘑 bucket, appid, partNumber: 0, // 鍒嗗潡涓婁紶缂栧彿 retryTimes: 0, // sdk鍐呴儴鍙戣捣鐨勮姹傞噸璇� reqUrl: '', // 璇锋眰url customId: customId || '', // 涓氬姟id deviceType: deviceInfo.deviceType, // 璁惧绫诲瀷 绉诲姩绔祻瑙堝櫒銆亀eb娴忚鍣� devicePlatform: deviceInfo.devicePlatform, deviceName: deviceInfo.deviceName, md5StartTime: 0, // md5璁$畻寮€濮嬫椂闂� md5EndTime: 0, // md5璁$畻缁撴潫鏃堕棿 signStartTime: 0, // 璁$畻绛惧悕寮€濮嬫椂闂� signEndTime: 0, // 璁$畻绛惧悕缁撴潫鏃堕棿 httpStartTime: 0, // 鍙戣捣缃戠粶璇锋眰寮€濮嬫椂闂� httpEndTime: 0, // 缃戣矾璇锋眰缁撴潫鏃堕棿 startTime: new Date().getTime(), // sdk api璋冪敤璧峰鏃堕棿锛屼笉鏄函缃戠粶鑰楁椂 endTime: 0, // sdk api璋冪敤缁撴潫鏃堕棿锛屼笉鏄函缃戠粶鑰楁椂 }; this.beacon = getBeacon(delay); } // 鏍煎紡鍖杝dk鍥炶皟 formatResult(err, data) { const now = new Date().getTime(); const tookTime = now - this.params.startTime; const networkType = utils.getNetType(); const errorCode = err ? err?.code || err?.error?.code || err?.error?.Code : ''; const errorMessage = err ? err?.message || err?.error?.message || err?.error?.Message : ''; const errorServiceName = err ? err?.resource || err?.error?.resource || err?.error?.Resource : ''; const errorStatusCode = err ? err?.statusCode : data.statusCode; const requestId = err ? err?.headers && err?.headers['x-cos-request-id'] : data?.headers && data?.headers['x-cos-request-id']; const errorType = err ? (requestId ? 'Server' : 'Client') : ''; Object.assign(this.params, { tookTime, networkType, httpMd5: this.params.md5EndTime - this.params.md5StartTime, httpSign: this.params.signEndTime - this.params.signStartTime, httpFull: this.params.httpEndTime - this.params.httpStartTime, result: err ? 'Fail' : 'Success', errorType, errorCode, errorStatusCode, errorMessage, errorServiceName, errorRequestId: requestId, }); if (err && (!errorCode || !errorMessage)) { // 鏆傚瓨鍏ㄩ噺err涓€娈垫椂闂� 瑙傚療鏄惁鎵€鏈塭rr鏍煎紡閮藉彲琚В鏋� this.params.fullError = err ? JSON.stringify(err) : ''; } if (this.params.name === 'getObject') { this.params.size = data ? data.headers && data.headers['content-length'] : -1; } if (this.params.reqUrl) { try { const execRes = /^http(s)?:\/\/(.*?)\//.exec(this.params.reqUrl); this.params.host = execRes[2]; } catch (e) { this.params.host = this.params.reqUrl; } } this.sendEvents(); } // 璁剧疆褰撳墠閾捐矾鐨勫弬鏁� setParams(params) { Object.assign(this.params, params); } // 浣跨敤鐏寤舵椂涓婃姤 sendEvents() { // DeepTracker妯″紡涓嬫墠浼氫笂鎶ュ垎鍧椾笂浼犲唴閮ㄧ粏鑺� if (sliceUploadMethods.includes(this.params.name) && !this.deepTracker) { return; } const eventCode = getEventCode(this.params.name); const formattedParams = formatParams(this.params); // 鍏滃簳澶勭悊 if (!this.beacon) { this.beacon = getBeacon(this.delay || 5000); } if (this.delay === 0) { // 瀹炴椂涓婃姤 this.beacon && this.beacon.onDirectUserAction(eventCode, formattedParams); } else { // 鍛ㄦ湡鎬т笂鎶� this.beacon && this.beacon.onUserAction(eventCode, formattedParams); } } // 鐢熸垚瀛愬疄渚嬶紝涓庣埗鎵€灞炰竴涓摼璺紝鍙敤浜庡垎鍧椾笂浼犲唴閮ㄦ祦绋嬩笂鎶ュ崟涓垎鍧楁搷浣� generateSubTracker(subParams) { Object.assign(subParams, { parent: this, deepTracker: this.deepTracker, traceId: this.params.traceId, bucket: this.params.bucket, region: this.params.region, fileKey: this.params.requestPath, customId: this.params.customId, delay: this.delay, }); return new Tracker(subParams); } } module.exports = Tracker;