clientapm.js 3.44 KB
const queryParse = require('../lib/query-parse');
const _ = require('lodash');
const {
    handleClientError,
    handleClientFirst,
    handleClientTiming,
    handleClientResource
} = require('./clientapm-service');
const routeDecode = require('./route-decode');

const logger = global.yoho.logger;
const crypto = global.yoho.crypto;

const decodeUid = _.memoize(function(r) {
    r = r.replace(/ /g, '+');
    return crypto.decrypt(null, decodeURIComponent(r));
});

module.exports = (req, res, next) => {
    if (!req.query.l) {
        logger.error('[client] query l is undefined');
        return res.send();
    }

    logger.debug('[client] request coming [%s]', req.query.l);

    const scope = {
        app: req.query.s || 'unknown',
        useragent: req.get('user-agent') || 'unknown',
        ip: req.clientIp || 'unknown'
    };

    if (!scope.useragent || /Baiduspider/.test(scope.useragent)) {
        return res.send();
    }

    try {
        const report = queryParse.parse(req.query.l);

        if (!report) {
            logger.error('[client] report can not be parse [%s]', req.query.l);
            return res.send();
        }

        report.forEach(item => {
            // url
            if (item.pt && item.pt.indexOf('openby:yohobuy') >= 0) {
                item.opt = item.pt; // pt 原始数据
                item.pt = item.pt.substring(0, item.pt.indexOf('openby:yohobuy'));
            }

            // uid
            if (item.u) {
                item.ou = item.u; // uid 原始数据
                try {
                    item.u = decodeUid(item.u);
                    item.u = _.parseInt(item.u);

                    if (!item.u) {
                        item.u = 0;
                    }
                } catch (e) {
                    // 有 yohomars, yohonow 使用未经加密过的uid,解密不成功不处理
                    // logger.error('[client] decode uid error [%j], scope [%j]', item, scope);
                }
            } else {
                item.u = 0;
            }

            // server route
            if (item.r) {
                try {
                    item.r = decodeURIComponent(item.r);
                    item.r = routeDecode(item.r);
                } catch (e) {
                    logger.error('[client] decode server route error [%j], scope [%j]', item, scope);
                }
            }

            if (!item.tp) {
                return;
            }

            switch (item.tp) {
                case 'err': {
                    handleClientError(scope, item);
                    break;
                }
                case 'pf': {
                    break;
                }
                case 'dcl':
                case 'ld':
                case 'fs': {
                    handleClientFirst(scope, item);
                    break;
                }
                case 'tm': {
                    handleClientTiming(scope, item);
                    break;
                }
                case 'rs': {
                    handleClientResource(scope, item);
                    break;
                }
                default: {
                    logger.error('[client] not handle client info [%j], scope [%j]', item, scope);
                    break;
                }
            }
        });

        res.send();

        logger.debug('[client] handle OK [%s]', req.query.l);
    } catch (e) {
        logger.error('[client] handle ERROR [%s]', e);
        return next(e);
    }
};