clientapm.js 2.72 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('query l is undefined');
        return res.send();
    }

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

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

        if (!report) {
            logger.error('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.pt = item.pt.substring(0, item.pt.indexOf('openby:yohobuy'));
            }

            // uid
            if (item.u) {
                try {
                    item.u = decodeUid(item.u);
                    item.u = _.parseInt(item.u);
                } catch (e) {
                    logger.error('decode uid error [%s]', item.u);
                }
            }

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

            if (!item.tp) {
                return;
            }

            switch (item.tp) {
                case 'err': {
                    handleClientError(scope, item);
                    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('not handle client info [%s]', JSON.stringify(item));
                    break;
                }
            }
        });

        res.send();
    } catch (e) {
        logger.error('not handle client info [%s]', e);
        return next(e);
    }
};