UNPKG

monitor-nodejs

Version:
223 lines (167 loc) 4.47 kB
'use strict' const Transaction = require('./models/transaction') const Segment = require('./models/segment') const { Handler, AxiosHandler } = require('./libs/handler') const stacktrace = require('./libs/stacktrace') async function parseErrorData(e, handled) { const rawStack = e.stack.split('\n') let firstLine = rawStack.shift().split(':') let data = { class: firstLine[0], message: firstLine[1].trim(), file: undefined, line: undefined, code: 1, stack: [], handled, } for (const [index, line] of rawStack.entries()) { let lineObj = stacktrace.stackLineParser(line) lineObj.code = await stacktrace.getCodeOfStackElement(lineObj) if (index === 0) { data.file = lineObj.file data.line = lineObj.line } data.stack.push(lineObj) } return data } function Monitor() { this._recording = true this._handler = undefined this._transaction = undefined this._segments = [] this.isRecording = () => { return this._recording } this.startRecording = () => { this._recording = true return this } this.stopRecording = () => { this._recording = false return this } this.getHandler = () => { return this._handler } this.setHandler = (handler) => { this._handler = handler return this } this.getSegments = () => { return this._segments } this.transaction = () => { return this._transaction } this.hasTransaction = () => { return this._transaction instanceof Transaction } this.needTransaction = () => { return this.isRecording() && !this.transaction() } this.canAddSegments = () => { return this.isRecording() && this.transaction() } this.startTransaction = (name) => { if (!this.isRecording()) { throw new Error('You must turn on recording to start a transaction.') } this._transaction = new Transaction(name) this._transaction.start() // TODO: Catch exception return this._transaction } this.startSegment = (type, label) => { if (!this.hasTransaction()) { const transaction = new Transaction('dummy') transaction.start() const segment = new Segment(transaction, type, label) segment.start() return segment } const segment = new Segment(this._transaction, type, label) segment.start() this._segments.push(segment) return segment } this.addSegment = async (callback, type, label, throwE = false) => { if (!this.canAddSegments()) { return callback() } let segment try { segment = this.startSegment(type, label) const result = await callback() segment.end() return result } catch (error) { if (segment) { segment.end() } if (throwE) { throw error } return this.report(error) } } this.report = async function (e, handled = false) { if (this.needTransaction()) { this.startTransaction(e.name) .setType(Transaction.TYPE_UNEXPECTED) .markAsFailed() } const segment = this.startSegment(Segment.TYPE_ERROR, e.message) segment.addContext('_monitor', { error: await parseErrorData(e, handled), }) segment.end() return segment } this.flush = async () => { const entries = [ this._transaction, ...this._segments, ].filter(entry => entry) for (const entry of entries) { if (!entry.isEnded()) { entry.end() } } if (typeof this._handler === 'function') { await this._handler(entries) } else if (this._handler instanceof Handler) { await this._handler.handle(entries) } this._transaction = null this.clear() return this } this.clear = () => { this._transaction = undefined this._segments = [] return this } } const packageData = require('../package.json') Monitor.VERSION = packageData['version'] Monitor.create = (key, options = {}) => { const base = options.url || 'https://ingest.dailydesk.app' // TODO: trim / at the end of base const url = base + '/entries' const version = options.version || Monitor.VERSION // const maxItems = options.maxItems || 1000 const handler = new AxiosHandler({ url: url, ingestionKey: key, version: version, // maxItems: maxItems, }) const monitor = new Monitor() monitor.setHandler(handler) return monitor } module.exports = Monitor