Authored by 毕凯

Merge branch 'feature/error-report' into 'master'

Feature/error report



See merge request !4
{
"name": "yas-jssdk",
"version": "2.4.2",
"version": "2.4.6",
"description": "YOHO!采集系统的前端js的开发包",
"keywords": [
"YOHO!",
... ...
/**
* cookies 操作
*/
var util = require('./util');
module.exports = function(name, value, options) {
if (typeof value != 'undefined') {
... ... @@ -32,7 +31,7 @@ module.exports = function(name, value, options) {
if (document.cookie) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = util.trim(cookies[i]);
var cookie = (cookies[i] || '').trim();
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
... ...
var cookies = require('../cookie');
var reporter = require('./reporter');
var errorKey = '_errLog';
var errReporter = {
writeError: function(msg, source, lineno, colno, error) {
var errorList = JSON.parse(cookies(errorKey) || '[]');
errorList.push({
tp: 'err',
msg: msg,
sc: source,
ln: lineno,
cn: colno,
pt: location.href,
u: reporter.getUid(),
ud: reporter.getUdid(),
rid: reporter.getReqId(),
st: JSON.stringify(error && error.stack)
});
cookies(errorKey, JSON.stringify(errorList));
if (errorList.length >= 5) {
this.reportError();
}
},
clearError: function() {
cookies(errorKey, '[]');
},
reportError: function() {
var self = this;
var errorList = JSON.parse(cookies(errorKey) || '[]');
var errStr = reporter.stringify(errorList);
reporter.report(errStr, function() {
self.clearError();
});
},
init: function() {
var self = this;
window.onerror = function(msg, source, lineno, colno, error) {
self.writeError(msg, source, lineno, colno, error);
};
// 上报未上报的事件
this.reportError();
}
};
module.exports = errReporter;
... ...
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
}
// 速度数据
var errReporter = require('./err-reporter');
var speed = require('./speed');
errReporter.init();
speed.init();
... ...
var cookies = require('../cookie');
var reporter = {
config: {
reportUrl: '//badjs.yoho.cn/apm/yas.gif'
},
stringify: function(list) {
/*
[{a1:1, a2:1}, {a1:2, a2:2}]
=>
'a1::1$$a2::1**a1::2$$a2::2'
*/
var data = [];
for (var i = 0; i < list.length; i++) {
var obj = list[i];
var params = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
params.push(prop + '::' + obj[prop]);
}
}
data.push(params.join('$$'));
}
return data.join('**');
},
report: function(str, cb) {
if (!str) {
return;
}
var imgElem = new Image();
imgElem.src = this.config.reportUrl + '?l=' + str + '&t=' + (new Date()).getTime();
cb && cb();
},
getUdid: function() {
var udid = (cookies('yohobuy_session') || '').slice(2).split('.')[0];
return udid || 0;
},
getUid: function() {
var uid = (cookies('_UID') || '').split('::')[1];
return uid || 0;
},
getReqId: function() {
return cookies('docreqid') || 0;
}
};
module.exports = reporter;
... ...
var reporter = require('./reporter');
// 首屏时间获取:
// 1,获取首屏基线高度
// 2,计算出基线dom元素之上的所有图片元素
// 3,所有图片onload之后为首屏显示时间
// 参考 https://www.zhihu.com/question/23212408/answer/56647975
function getOffsetTop(ele) {
var offsetTop = ele.offsetTop;
if (ele.offsetParent !== null) {
offsetTop += getOffsetTop(ele.offsetParent);
}
return offsetTop;
}
var firstScreenHeight = window.screen.height;
var firstScreenImgs = [];
var isFindLastImg = false;
var allImgLoaded = false;
var firstScreenLoadTime = 0;
var t = setInterval(function() {
var i, img;
if (isFindLastImg) {
if (firstScreenImgs.length) {
for (i = 0; i < firstScreenImgs.length; i++) {
img = firstScreenImgs[i];
if (!img.complete) {
allImgLoaded = false;
break;
} else {
allImgLoaded = true;
}
}
} else {
allImgLoaded = true;
}
if (allImgLoaded) {
firstScreenLoadTime = (new Date()).getTime() - _timeStart
clearInterval(t);
}
} else {
var imgs = document.body.querySelector('img') || [];
for (i = 0; i < imgs.length; i++) {
img = imgs[i];
var imgOffsetTop = getOffsetTop(img);
if (imgOffsetTop > firstScreenHeight) {
isFindLastImg = true;
break;
} else if (imgOffsetTop <= firstScreenHeight && !img.hasPushed) {
img.hasPushed = 1;
firstScreenImgs.push(img);
}
}
}
}, 0);
var speedReporter = {
reportTime: function(speedList) {
var speedStr = reporter.stringify(speedList);
reporter.report(speedStr);
},
addEvent: function() {
var self = this;
var timeList = [];
var pt = location.href;
var u = reporter.getUid();
var ud = reporter.getUdid();
var rid = reporter.getReqId();
var pStart = window.performance && window.performance.timing.navigationStart || 0;
_timeStart = window._timeStart || 0;
document.addEventListener && document.addEventListener('DOMContentLoaded', function(event) {
timeList.push({
tp: 'dcl', // DOMContentLoaded
t: (new Date()).getTime() - _timeStart,
pt: pt,
u: u,
ud: ud,
rid: rid
});
// 首屏加载速度
var imgs = document.body.querySelector('img') || [];
if (!imgs.length) {
isFindLastImg = true;
}
}, false);
window.addEventListener && window.addEventListener('load', function(event) {
timeList.push({
tp: 'ld', // load
t: (new Date()).getTime() - _timeStart,
pt: pt,
u: u,
ud: ud,
rid: rid
});
// 首屏加载速度
allImgLoaded = true;
isFindLastImg = true;
if (t) {
clearInterval(t);
}
if (firstScreenLoadTime) {
timeList.push({
tp: 'fs', // firstScreenLoadTime
t: firstScreenLoadTime,
pt: pt,
u: u,
ud: ud,
rid: rid
});
}
timeList.push({
tp: 'pf', // performance
dcl: (window.performance && window.performance.timing.domComplete || 0) - pStart,
ld: (window.performance && window.performance.timing.loadEventStart || 0) - pStart,
pt: pt,
u: u,
ud: ud,
rid: rid
});
self.reportTime(timeList);
}, false);
},
init: function() {
this.addEvent();
}
};
module.exports = speedReporter;
\ No newline at end of file
... ...
... ... @@ -217,6 +217,20 @@ var channelMap = {
"bing.com": 100000000000057,
"m.sm.cn": 100000000000059,
"google.com": 100000000000061
};
var isMobile = 'm.yohobuy.com' === location.hostname || /\.m\.yohobuy\.com$/.test(location.hostname);
if (!isMobile) {
// PC 使用单独的推广码
channelMap = {
"baidu.com": 100000000008051,
"so.com": 100000000008043,
"sogou.com": 100000000008049,
"bing.com": 100000000008045,
"m.sm.cn": 100000000008053,
"google.com": 100000000008047
};
}
exports.getMktcBySeo = function() {
... ...
... ... @@ -195,26 +195,26 @@ var _yas = function(initTime, version, tid, uid, geo, selector) {
});
}
onerror = handleErr;
var txt = "";
function handleErr(msg, url, l) {
txt = "This page contains error! \n\n";
txt += "Error message is:" + msg + "\n";
txt += "URL is: " + url + "\n";
txt += "Line is:" + l + "\n\n";
var errString = JSON.stringify({
'er': txt
});
cookies('_yaserror', errString, {
path: '/',
domain: yasDomain,
expires: 365 * 200
});
return false;
}
// onerror = handleErr;
// var txt = "";
//
// function handleErr(msg, url, l) {
// txt = "This page contains error! \n\n";
// txt += "Error message is:" + msg + "\n";
// txt += "URL is: " + url + "\n";
// txt += "Line is:" + l + "\n\n";
// var errString = JSON.stringify({
// 'er': txt
// });
// cookies('_yaserror', errString, {
// path: '/',
// domain: yasDomain,
// expires: 365 * 200
// });
// return false;
// }
};
... ... @@ -250,16 +250,16 @@ function send(callback) {
}
// 页面error信息
var _yasErrorStr = cookies('_yaserror');
if (_yasErrorStr) {
var errorJson = JSON.parse(_yasErrorStr);
info = util.merge(info, errorJson);
cookies('_yaserror', null, {
path: "/",
domain: config.yasDomain,
expires: 365 * 200
});
}
// var _yasErrorStr = cookies('_yaserror');
// if (_yasErrorStr) {
// var errorJson = JSON.parse(_yasErrorStr);
// info = util.merge(info, errorJson);
// cookies('_yaserror', null, {
// path: "/",
// domain: config.yasDomain,
// expires: 365 * 200
// });
// }
var param = util.genParam(info);
callback = callback ? callback : function() {};
... ...
... ... @@ -9,7 +9,8 @@ const os = require('os');
module.exports = {
entry: {
'yas': './yas.js'
'yas': './yas.js',
'reporter': './src/reporter/index.js'
},
output: {
path: path.join('dist', 'yas-jssdk', version), // absolute path
... ...