Skip to content

Instantly share code, notes, and snippets.

@micwehrle
Last active September 17, 2019 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micwehrle/a363510b0f2627f5b3e5386a3bf35d5e to your computer and use it in GitHub Desktop.
Save micwehrle/a363510b0f2627f5b3e5386a3bf35d5e to your computer and use it in GitHub Desktop.
import { ClientConfig } from '../Core/types';
import Http from '../utils/Http';
import Url from '../utils/Url';
import { ResourceResult, AutofiServices } from './types';
import Resource from './AbstractResource';
export interface MetricOpts extends ClientConfig {
autofiService: string;
metadata: any;
processInterval: number;
}
interface TimeEvent {
readonly key: string;
readonly duration: number;
readonly metadata: object;
}
export default class Metric extends Resource {
public metadata: any;
private autofiService: AutofiServices | string;
private processing = false;
private processInterval: number;
private queue: TimeEvent[] = [];
private statsMap: Map<string, number> = new Map();
public constructor(opts: MetricOpts) {
super('metric');
this.autofiService = opts.autofiService;
this.baseUri = opts.uris.METRIC_SERVICE_URI;
this.metadata = opts.metadata;
this.processInterval = opts.processInterval || 5000;
}
private formatKey(key: string): string {
return `${this.autofiService}:${key}`;
}
private initializeQueue(): void {
setInterval(this.processQueue.bind(this), this.processInterval);
this.processing = true;
}
private processQueue(): void {
if (this.queue.length === 0) {
return;
}
Http.fetch(Url.stringify(this.baseUri, `/metrics/stats`), {
method: 'POST',
body: JSON.stringify({ data: this.queue }),
headers: { 'Content-Type': 'application/json' },
});
this.queue = [];
}
/**
* Mark the start of a performance timer
*
* @param {string} key <scope:event> e.g., scraper:ui-handoff
* @returns {void}
* @memberof Metric
*/
public mark(key: string): void {
this.statsMap.set(this.formatKey(key), Date.now());
}
/**
* Time a performance event
*
* @param {string} key <scope:event> e.g., scraper:ui-handoff
* @param {object?} metadata
* @returns {void}
* @memberof Metric
*/
public timing(key: string, metadata?: object): void {
const now = Date.now();
const formattedKey = this.formatKey(key);
const startTime = this.statsMap.get(formattedKey);
if (!startTime) {
return;
}
const duration = now - startTime;
if (!this.processing) {
this.initializeQueue();
}
const combinedMetadata = { ...this.metadata, ...metadata };
this.queue.push({ key: formattedKey, duration, metadata: combinedMetadata });
this.statsMap.delete(formattedKey);
}
/**
* Create a heartbeat
*
* @param {AutofiServices} [key]
* @param {any} data
* @returns {Promise<ResourceResult>}
* @memberof Metric
*/
public async heartbeat(
key: AutofiServices | string = AutofiServices.None,
data?: any
): Promise<ResourceResult> {
return Http.fetch(Url.stringify(this.baseUri, `/metrics/heartbeat`), {
method: 'POST',
body: JSON.stringify({
data,
key,
}),
headers: {
'Content-Type': 'application/json',
},
});
}
/**
* Returns metric data
*
* @param {any} data
* @returns {Promise<ResourceResult>}
* @memberof Metric
*/
public async data(): Promise<ResourceResult> {
return Http.fetch(Url.stringify(this.baseUri, `/metrics/data`));
}
}
/*************************************************************************/
// express endpoint
const Metric = require('...');
...
app.get('/', () => {
metricsClient = Metric.create({
autofiService: 'Service Name',
... other config options
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment