unleash-server
Version:
Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.
102 lines • 3.96 kB
JavaScript
export class CustomMetricsStore {
constructor(config) {
this.customMetricsStore = new Map();
this.logger = config.getLogger('custom-metrics-store');
}
roundToMinute(date) {
const rounded = new Date(date);
rounded.setSeconds(0);
rounded.setMilliseconds(0);
return rounded;
}
getMetricKey(metric, timestamp) {
const roundedTimestamp = this.roundToMinute(timestamp);
const timeKey = roundedTimestamp.toISOString();
let key = `${metric.name}:${timeKey}`;
if (metric.labels && Object.keys(metric.labels).length > 0) {
const labelEntries = Object.entries(metric.labels).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
const labelString = labelEntries
.map(([key, value]) => `${key}=${value}`)
.join(',');
key += `:${labelString}`;
}
return key;
}
addMetric(metric) {
const now = new Date();
const roundedTimestamp = this.roundToMinute(now);
const metricKey = this.getMetricKey(metric, now);
const storedMetric = {
...metric,
timestamp: roundedTimestamp,
};
this.customMetricsStore.set(metricKey, storedMetric);
}
addMetrics(metrics) {
let storedCount = 0;
metrics.forEach((metric) => {
this.addMetric(metric);
storedCount++;
});
this.logger.debug(`Stored ${storedCount} custom metrics`);
}
getMetrics() {
return Array.from(this.customMetricsStore.values());
}
getMetricsByName(name) {
return Array.from(this.customMetricsStore.values()).filter((metric) => metric.name === name);
}
getMetricNames() {
const names = new Set();
for (const metric of this.customMetricsStore.values()) {
names.add(metric.name);
}
return Array.from(names);
}
getPrometheusMetrics() {
let output = '';
const metricsByName = new Map();
for (const metric of this.customMetricsStore.values()) {
if (!metricsByName.has(metric.name)) {
metricsByName.set(metric.name, new Map());
}
let labelKey = '';
if (metric.labels && Object.keys(metric.labels).length > 0) {
const labelEntries = Object.entries(metric.labels).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
labelKey = labelEntries
.map(([key, value]) => `${key}=${value}`)
.join(',');
}
const metricsForName = metricsByName.get(metric.name);
if (!metricsForName.has(labelKey) ||
metricsForName.get(labelKey).timestamp < metric.timestamp) {
metricsForName.set(labelKey, metric);
}
}
for (const [metricName, metricsMap] of metricsByName.entries()) {
if (metricsMap.size === 0)
continue;
output += `# HELP ${metricName} Custom metric reported to Unleash\n`;
output += `# TYPE ${metricName} counter\n`;
for (const metric of metricsMap.values()) {
let labelStr = '';
if (metric.labels && Object.keys(metric.labels).length > 0) {
const labelParts = Object.entries(metric.labels)
.map(([key, value]) => `${key}="${this.escapePrometheusString(value)}"`)
.join(',');
labelStr = `{${labelParts}}`;
}
output += `${metricName}${labelStr} ${metric.value}\n`;
}
output += '\n';
}
return output;
}
escapePrometheusString(str) {
return str
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n');
}
}
//# sourceMappingURL=custom-metrics-store.js.map