apm.js 2.99 KB
const queryParse = require('../lib/query-parse');
const sourceMapParse = require('../lib/sourcemap-parse');
const Sender = require('influx-batch-sender');
const url = require('url');
const _ = require('lodash');
const logger = global.yoho.logger;
const config = global.yoho.config;

const durationType = {
    dcl: 'DOMContentLoaded',
    ld: 'load',
    fs: 'firstscreen'
};

const influxSender = new Sender(config.report);

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

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

        if (!report) {
            logger.error('report can not be parse:', req.query.l);
            return res.send();
        }
        report.forEach(item => {
            const referer = url.parse(req.get('referer') || item.pt || '');
            let data = {
                tags: {
                    app: referer.hostname,
                    reqID: item.rid,
                    uid: item.u,
                    udid: item.ud,
                    route: item.pt
                }
            };

            if (item.tp === 'err') {
                sourceMapParse.parse({
                    url: item.sc,
                    line: parseInt(item.ln, 10),
                    column: parseInt(item.cn, 10)
                }).then(originError => {
                    let fields = {};

                    if (!originError) {
                        logger.error('sourcemap can not be parse', item);
                        fields = {
                            script: item.sc,
                            line: _.parseInt(item.ln),
                            column: _.parseInt(item.cn),
                        };
                    } else {
                        fields = {
                            script: originError.source,
                            line: _.parseInt(originError.line),
                            column: _.parseInt(originError.column),
                        };
                    }
                    influxSender.addMessage(_.merge(data, {
                        measurement: 'error-report',
                        tags: {
                            type: 'client'
                        },
                        fields: Object.assign({
                            message: item.msg,
                            stack: item.st.replace(/"/g, '')
                        }, fields)
                    }));
                });
            } else {
                if (durationType[item.tp]) {
                    influxSender.addMessage(_.merge(data, {
                        measurement: 'web-duration',
                        tags: {
                            type: durationType[item.tp]
                        },
                        fields: {
                            duration: _.parseInt(item.t)
                        }
                    }));
                }
            }
        });

        res.json();
    } catch (e) {
        return next(e);
    }
};