предисловие
Я до сих пор помню, как в моей прошлой компании некий начальник построил систему мониторинга, которая была потрясающей, и мне очень хотелось изучить, как он ее придумал. Конечно, мы не из тех людей, которые гладят себя по голове и работают, и мы не можем делать то, что делают другие. Давайте сначала представим преимущества такой платформы.
задний план
Во-первых, зачем нам делать front-end систему?Посмотрите на таблицу ниже.Очевидно, что производительность front-end сильно влияет на стоимость продукта, но если мы сможем собрать эту информацию в режиме реального времени и внедрить его Нашей целью является мониторинг и поддержание эффективной работы всего продукта в линейке продуктов.
представление | доход |
---|---|
задержка Google400ms | Количество запросов падает0.59% |
Задержка Bing2s | снижение доходов4.3% |
задержка Yahoo400ms | трафик падает5-9% |
Страница Mozilla открывается меньше2.2s | Количество загрузок увеличивается15.4% |
Netflix включает Gzip | Повышение производительности на 13,25 % при снижении пропускной способности.50% |
Во-вторых, это также выгодно для продуктов, которые мы освобождаем, и мы можем найти наши ошибки вовремя. Если продукт находится в новой итерации, возникает неописуемая ошибка.
правильно! Просто неописуемо. Ждать отзывов и жалоб от пользователей у нас невозможно, а лилейник к тому времени уже остынет.
Начинать
Исходя из вышеизложенного начинаем строить фронтальный мониторпростоплатформа управления. (Хотя сейчас на рынке много таких систем, например ELK, я все равно не могу с собой поделать.)
Можно только простой.
Братья, простите меня, я могу только помочь вам здесь.
Пожалуйста, смотрите дальше.
Выше приведены некоторые из вещей, которые нам нужно сделать.
Собирать информацию
Чтобы сделать систему мониторинга, сначала у нас должен быть объект. Объекты, за которыми мы следим! объект! объект! объект.
Я написал такую страницу в своей системе,
<body>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
</body>
Правильно, это страница, которую мы хотим отслеживать. Это... дело не в том, что я ленивый.
Затем я разработал в общей сложности 3 части данных
- время загрузки страницы
- Статистика по пользовательскому оборудованию
- Статистика ошибок
время загрузки страницы
window.logInfo = {}; //统计页面加载时间
window.logInfo.openTime = performance.timing.navigationStart;
window.logInfo.whiteScreenTime = +new Date() - window.logInfo.openTime;
document.addEventListener('DOMContentLoaded',function (event) {
window.logInfo.readyTime = +new Date() - window.logInfo.openTime;
});
window.onload = function () {
window.logInfo.allloadTime = +new Date() - window.logInfo.openTime;
window.logInfo.nowTime = new Date().getTime();
var timname = {
whiteScreenTime: '白屏时间',
readyTime: '用户可操作时间',
allloadTime: '总下载时间',
mobile: '使用设备',
nowTime: '时间',
};
var logStr = '';
for (var i in timname) {
console.warn(timname[i] + ':' + window.logInfo[i] + 'ms');
if (i === 'mobile') {
logStr += '&' + i + '=' + window.logInfo[i];
} else {
logStr += '&' + i + '=' + window.logInfo[i];
}
}
(new Image()).src = '/action?' + logStr;
};
Статистика по пользовательскому оборудованию
window.logInfo.mobile = mobileType();
function mobileType() {
var u = navigator.userAgent, app = navigator.appVersion;
var type = {// 移动终端浏览器版本信息
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
iPad: u.indexOf('iPad') > -1, //是否iPad
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器
trident: u.indexOf('Trident') > -1, //IE内核
presto: u.indexOf('Presto') > -1, //opera内核
webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile/i) || !!u.match(/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/), //是否为移动终端
webApp: u.indexOf('Safari') == -1 //是否web应该程序,没有头部与底部
};
var lists = Object.keys(type);
for(var i = 0; i < lists.length; i++) {
if(type[lists[i]]) {
return lists[i];
}
}
}
Статистика ошибок
window.onload = function () {
window.logInfo.allloadTime = +new Date() - window.logInfo.openTime;
window.logInfo.nowTime = new Date().getTime();
var timname = {
whiteScreenTime: '白屏时间',
readyTime: '用户可操作时间',
allloadTime: '总下载时间',
mobile: '使用设备',
nowTime: '时间',
};
var logStr = '';
for (var i in timname) {
console.warn(timname[i] + ':' + window.logInfo[i] + 'ms');
if (i === 'mobile') {
logStr += '&' + i + '=' + window.logInfo[i];
} else {
logStr += '&' + i + '=' + window.logInfo[i];
}
}
(new Image()).src = '/action?' + logStr;
};
var defaults = {
msg:'', // 错误的具体信息
url:'', // 错误所在的url
line:'', // 错误所在的行
col:'', // 错误所在的列
nowTime: '',// 时间
};
window.onerror = function(msg,url,line,col,error) {
col = col || (window.event && window.event.errorCharacter) || 0;
defaults.url = url;
defaults.line = line;
defaults.col = col;
defaults.nowTime = new Date().getTime();
if (error && error.stack){
// 如果浏览器有堆栈信息,直接使用
defaults.msg = error.stack.toString();
}else if (arguments.callee){
// 尝试通过callee拿堆栈信息
var ext = [];
var fn = arguments.callee.caller;
var floor = 3;
while (fn && (--floor>0)) {
ext.push(fn.toString());
if (fn === fn.caller) {
break;
}
fn = fn.caller;
}
ext = ext.join(",");
defaults.msg = error.stack.toString();
}
var str = ''
for(var i in defaults) {
// console.log(i,defaults[i]);
if(defaults[i] === null || defaults[i] === undefined) {
defaults[i] = 'null';
}
str += '&'+ i + '=' + defaults[i].toString();
}
srt = str.replace('&', '').replace('\n','').replace(/\s/g, '');
(new Image()).src = '/error?' + srt;
}
Все вышесказанное касается сбора данных, отправив запрос /action или запрос /error, их можно настроить, я говорю только о том, как реализован весь процесс.
Затем все запросы обрабатываются и записываются через один из моих бэкендов express.js.Записываемые данные выглядят так.
user_ip=127.0.0.1&whiteScreenTime=185&readyTime=192&allloadTime=208&mobile=webKit&nowTime=1513071388941
обработка данных
Здесь я анализирую написанный мной скрипт parse.js, который здесь не объясняется, просто взгляните на исходный код. Показываю обработанные данные.
Я храню его в формате данных cvs.Из-за необходимости диаграммы позже я также поддерживаю экспорт в формате json, но вам нужно будет настроить визуальный интерфейс позже самостоятельно.
Данные такие.
charts/csvData/2017-12-16time.csv
时间,白屏时间,用户可操作时间,总下载时间
1513427051482,137,137,153
1513427065080,470,471,507
1513427080040,127,127,143
1513428714345,274,275,323
1513428733583,267,268,317
1513428743167,268,268,317
1513428754796,276,276,328
Отображение данных
Здесь я используюhighcharts.js
Я не буду объяснять конкретную конфигурацию, вы можете сами проверить ее на официальном сайте.
Ниже представлена наглядная диаграмма, показывающая информацию для каждого временного периода дня.
Интерфейс может быть не особо красивым, прошу меня простить.
окружающая обстановка
node >= 6.0.0
redis >= 2.6.0
Я объясню здесь, потому что, если это развернуто в онлайн-среде, если каждая запись будет записана, это будет потреблять много памяти, поэтому я настроил слой Redis, чтобы предотвратить влияние большого трафика, а затем каждое хранилище за определенный период времени.
const express = require('express');
const performance = require('./lib/performance.js');
const app = express();
const router = express.Router();
router.get('/', function (req, res, next) {
req.url = './index.html';
next();
});
app.use(router);
app.use(performance({
time: 10, // 秒为单位
originalDir: './originalData', // 数据的目录
errorDir: './errorData' // 报错的目录
}))
app.use(express.static('./'));
const server = app.listen(3000)
Здесь можно установить время по умолчанию, я использую 10 секунд в качестве единицы измерения ради демонстрационного эффекта. Обычно я использую одно хранилище в минуту.
Кодовый адрес:GitHub.com/flower1995116/…
Если у вас есть хорошие предложения и оптимизированные решения, пожалуйста, дайте им мне по вопросам.
Расширенный (практичный каштан с использованием платформы мониторинга)
Я использовал эту платформу для мониторинга одного из моих проектов. Если вы просто играете, пожалуйста, прочитайте только исходный системный адрес выше, вы можете игнорировать мой абзац, в конце концов, моя система не идеальна.
Онлайн-демонстрация:www.qiufengh.com/#/
Демонстрация монитора:qiufengh.com:8080/
проект:GitHub.com/flower1995116/…
Здесь я устанавливаю запись журнала каждую 1 минуту.
// 监控引入
app.use(performance({
time: 60, // 秒为单位
originalDir: './originalData', // 数据的目录
errorDir: './errorData' // 报错的目录
}))
и разбор каждые 10 минут.
function setPrase() {
setInterval(function(){
parseData();
}, 1000 * 60 * 10);
}
2017-12-20
Эта статья просто дает идею, если вы хотите быть профессионалом, вы можете использоватьELKпрофессиональные инструменты статистического анализа.