UNPKG

@flarelabs-net/workers-observability-utils

Version:

A collection of Utilities for Capturing Logs and Metrics from Cloudflare Workers

122 lines (121 loc) 4.44 kB
import { calculateHistogramValue, calculatePercentile } from "./utils/maths"; import { MetricType, } from "./types"; function serializeTags(tags) { return Object.entries(tags) .sort(([keyA], [keyB]) => keyA.localeCompare(keyB)) .map(([key, value]) => `${key}:${value}`) .join(","); } export class MetricsDb { metrics = new Map(); getMetricKey(metric) { const tagKey = serializeTags(metric.tags); return `${metric.name}:${metric.type}:${tagKey}`; } storeMetric(metric) { const key = this.getMetricKey(metric); const existingMetric = this.metrics.get(key); switch (metric.type) { case MetricType.COUNT: { const newValue = existingMetric ? existingMetric.value + Number(metric.value) : Number(metric.value); this.metrics.set(key, { type: metric.type, name: metric.name, tags: metric.tags, value: newValue, lastUpdated: metric.timestamp, }); break; } case MetricType.GAUGE: { this.metrics.set(key, { type: metric.type, name: metric.name, tags: metric.tags, value: Number(metric.value), lastUpdated: metric.timestamp, }); break; } case MetricType.HISTOGRAM: { const existingValue = existingMetric ? existingMetric.value : []; this.metrics.set(key, { type: metric.type, name: metric.name, tags: metric.tags, percentiles: metric.options?.percentiles, aggregates: metric.options?.aggregates, value: [...existingValue, metric.value], lastUpdated: metric.timestamp, }); } } } storeMetrics(metrics) { for (const metric of metrics) { this.storeMetric(metric); } } /** * Get all stored metrics */ getAllMetrics() { return Array.from(this.metrics.values()); } clearAll() { this.metrics.clear(); } getMetricCount() { return this.metrics.size; } /** * Get the Metrics in a format ready to export to various different sinks * @param flushWindowS */ toMetricPayloads() { const payloads = []; const flushTimestamp = Date.now(); for (const metric of this.metrics.values()) { switch (metric.type) { case MetricType.COUNT: case MetricType.GAUGE: payloads.push({ type: metric.type, name: metric.name, value: metric.value, tags: metric.tags, timestamp: flushTimestamp, }); break; case MetricType.HISTOGRAM: { const sortedArray = [...metric.value].sort(); for (const percentile of metric.percentiles || []) { const value = calculatePercentile(sortedArray, percentile); payloads.push({ type: MetricType.GAUGE, name: `${metric.name}.p${Math.round(percentile * 100)}`, value: value, tags: metric.tags, timestamp: flushTimestamp, }); } for (const aggregate of metric.aggregates || []) { const value = calculateHistogramValue(aggregate, metric.value); payloads.push({ type: aggregate === "count" ? MetricType.COUNT : MetricType.GAUGE, name: `${metric.name}.${aggregate}`, value: value, tags: metric.tags, timestamp: flushTimestamp, }); } } } } return payloads; } }