trace.js 2.72 KB
/**
 * 跟踪监控工具, 将监控数据写入influxdb
 *
 * @author: jiangfeng<jeff.jiang@yoho.cn>
 * @date: 16/8/1
 */

'use strict';

const dgram = require('dgram');
const influx = require('influx');
const _ = require('lodash');

class Trace {

    /**
     * influxdb connection config
     *
     * @param options
     */
    constructor(options) {
        this.options = options;
    }

    report(name, keys, data) {
        if (this.options.appName) {
            keys.appName = this.options.appName;
        }

        let line = `${this._escape(name)},${this._makeLine(keys, false)} ${this._makeLine(data, true)}`;
        return this._send(line);
    }

    /**
     * make the data with influxdb's line protocol.
     * @see https://docs.influxdata.com/influxdb/v0.13/write_protocols/line/
     *
     * @param data {object}
     * @param withNoQuote {boolean}
     * @returns {string}
     * @private
     */
    _makeLine(data, withNoQuote) {
        if (_.isObject(data)) {
            return Object.keys(data).map(key => {
                return key + '=' + this._escape(data[key], withNoQuote);
            }).join(',');
        } else if (_.isArray(data)) {
            return data.map(d => {
                return this._makeLine(d, escape);
            }).join(' ');
        } else if (!_.isNil(data)) {
            return 'value=' + this._escape(data, withNoQuote);
        } else {
            return '';
        }
    }

    /**
     * upd send.
     * @param line {string} @see infulxdb's line protocol
     * @returns {Promise}
     * @private
     */
    _send(line) {
        let self = this;

        return new Promise((resolve, reject) => {
            let socket = dgram.createSocket('udp4');
            let buff = new Buffer(line);

            socket.send(buff, 0, buff.length, self.options.port, self.options.host, (err) => {
                socket.close();

                if (err) {
                    reject(err);
                } else {
                    resolve();
                }
            });
        });
    }

    _escape(value, withQuote) {
        if (_.isString(value)) {
            if (withQuote) {
                value = '"' + value + '"';
            } else {
                value = _.replace(value, /,/g, '\\,');
                value = _.replace(value, /=/g, '\\=');
                value = _.replace(value, /\s/g, '\\ ');
            }
        } else if (_.isInteger(value)) {
            if (withQuote) {
                value = value;
            }
        } else if (_.isObject(value)) {
            value = '"' + _.replace(JSON.stringify(value), /"/g, '\\"') + '"';
        } else if (_.isNull(value) || _.isNil(value)) {
            value = '""';
        }

        return value;
    }
}

module.exports = Trace;