UNPKG

newrelic

Version:
153 lines (126 loc) 3.76 kB
/* * Copyright 2020 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' const Aggregator = require('./base-aggregator') const logger = require('../logger').child({ component: 'event_aggregator' }) const PriorityQueue = require('../priority-queue') /** * Aggregates events up to a certain limit. * * @private * @class */ class EventAggregator extends Aggregator { constructor(opts, agent) { const { metrics, collector, harvester } = agent super(opts, collector, harvester) // EventEmitter inits an _events collection. So we have to avoid collision this._items = new PriorityQueue(opts.limit) this._metricNames = opts.metricNames this._metrics = metrics } get seen() { return this._items.seen } get length() { return this._items.length } get overflow() { return this._items.overflow() } get events() { return this._items } _merge() { return this.mergeEvents.apply(this, arguments) } add() { this._metrics.getOrCreateMetric(this._metricNames.SEEN).incrementCallCount() const didAdd = this.addEvent.apply(this, arguments) if (didAdd && this._items.overflow() === 0) { this._metrics.getOrCreateMetric(this._metricNames.SENT).incrementCallCount() } else { this._metrics.getOrCreateMetric(this._metricNames.DROPPED).incrementCallCount() } return didAdd } _getMergeData() { return this._items } clear() { return this.clearEvents.apply(this, arguments) } /** * */ getQueue() { return this._items } /** * Fetches all the span events aggregated. * * @returns {Array.<Event>} An array of span events from the aggregator. */ getEvents() { return this._items.toArray() } /** * Resets the contents of the aggregator and all counters. */ clearEvents() { // ???: might be more efficient to clear here and come up with an efficient way to // serialize the events and priorities this._items = new PriorityQueue(this._items.limit) } reconfigure(config) { super.reconfigure(config) const newSettings = config.getAggregatorConfig(this.method) if (newSettings) { this.periodMs = newSettings.periodMs this.limit = newSettings.limit this._items.setLimit(this.limit) } else { this.periodMs = this.defaultPeriod this.limit = this.defaultLimit } } addEvent(event, priority) { return this._items.add(event, priority) } /** * Merges a set of events back into the aggregator. * * This should only be used after a failed harvest with the `PriorityQueue` * returned from `EventAggregator#clearEvents`. * * @param {?PriorityQueue} events - The collection of events to re-merge. */ mergeEvents(events) { if (!events) { return } // We calculate the number that will be merged for the log, but we try to // add every event because we want the ones with the highest priority, not // the first `n` events. const toMerge = Math.min(events.length, this.limit - this.length) logger.warn( 'Merging %d of %d events into %s for next harvest', toMerge, events.length, this.constructor.name ) const seen = events.length const sent = toMerge const dropped = seen - sent this._metrics.getOrCreateMetric(this._metricNames.SEEN).incrementCallCount(seen) this._metrics.getOrCreateMetric(this._metricNames.SENT).incrementCallCount(sent) if (dropped > 0) { this._metrics.getOrCreateMetric(this._metricNames.DROPPED).incrementCallCount(dropped) } // merge modifies incoming events collection. this._items.merge(events) } } module.exports = EventAggregator