unleash-server
Version:
Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.
226 lines • 9.09 kB
JavaScript
import { MetricsTranslator } from './metrics-translator.js';
import { Registry } from 'prom-client';
describe('MetricsTranslator', () => {
let translator;
beforeEach(() => {
translator = new MetricsTranslator(new Registry());
});
describe('sanitizeName', () => {
it('should not modify valid names', () => {
expect(translator.sanitizeName('valid_name')).toBe('valid_name');
expect(translator.sanitizeName('validName')).toBe('validName');
expect(translator.sanitizeName('_valid_name')).toBe('_valid_name');
});
it('should replace invalid characters with underscores', () => {
expect(translator.sanitizeName('invalid-name')).toBe('invalid_name');
expect(translator.sanitizeName('invalid.name')).toBe('invalid_name');
expect(translator.sanitizeName('invalid@name')).toBe('invalid_name');
expect(translator.sanitizeName('invalid name')).toBe('invalid_name');
expect(translator.sanitizeName('invalid:name')).toBe('invalid_name');
});
});
it('should translate counters, gauges, and histograms', async () => {
const result = await translator.translateAndSerializeMetrics([
{
name: 'labeled_counter',
help: 'with labels',
type: 'counter',
samples: [{ labels: { foo: 'bar' }, value: 5 }],
},
{
name: 'test_gauge',
help: 'gauge test',
type: 'gauge',
samples: [{ labels: { env: 'prod' }, value: 10 }],
},
{
name: 'response_time',
help: 'response time',
type: 'histogram',
samples: [
{
labels: { service: 'api' },
count: 5,
sum: 2.5,
buckets: [
{ le: 1, count: 3 },
{ le: '+Inf', count: 5 },
],
},
],
},
]);
expect(result).toContain('labeled_counter{origin="sdk",metric_type="counter",foo="bar"} 5');
expect(result).toContain('test_gauge{origin="sdk",metric_type="gauge",env="prod"} 10');
expect(result).toContain('response_time_bucket{metric_type="histogram",origin="sdk",service="api",le="1"} 3');
});
it('should skip histograms with empty samples', async () => {
const result = await translator.translateAndSerializeMetrics([
{
name: 'test_counter',
help: 'test counter',
type: 'counter',
samples: [{ value: 1 }],
},
{
name: 'empty_histogram',
help: 'empty',
type: 'histogram',
samples: [],
},
]);
expect(result).toContain('# HELP test_counter test counter');
expect(result).not.toContain('empty_histogram');
});
it('should sanitize metric names and label names', async () => {
const result = await translator.translateAndSerializeMetrics([
{
name: 'invalid-metric-name',
help: 'metric with invalid name',
type: 'counter',
samples: [
{
labels: { 'invalid-label': 'value', '1numeric': 123 },
value: 5,
},
],
},
{
name: '_valid_metric',
help: 'metric with valid prefix',
type: 'gauge',
samples: [
{
labels: {
'invalid:colon': 'value',
'space label': 'test',
},
value: 10,
},
],
},
]);
expect(result).toContain('# HELP invalid_metric_name');
expect(result).toContain('invalid_metric_name{origin="sdk",metric_type="counter",invalid_label="value"} 5');
expect(result).toContain('_valid_metric{origin="sdk",metric_type="gauge",invalid_colon="value",space_label="test"} 10');
});
it('should handle re-labeling of metrics', async () => {
await translator.translateAndSerializeMetrics([
{
name: 'counter_with_labels',
help: 'counter with labels',
type: 'counter',
samples: [{ labels: { foo: 'bar' }, value: 5 }],
},
{
name: 'gauge_with_labels',
help: 'gauge with labels',
type: 'gauge',
samples: [{ labels: { env: 'prod' }, value: 10 }],
},
{
name: 'histogram_with_labels',
help: 'histogram with labels',
type: 'histogram',
samples: [
{
labels: { service: 'api' },
count: 5,
sum: 2.5,
buckets: [
{ le: 1, count: 3 },
{ le: '+Inf', count: 5 },
],
},
],
},
]);
const result = await translator.translateAndSerializeMetrics([
{
name: 'counter_with_labels',
help: 'counter with labels',
type: 'counter',
samples: [{ labels: { foo: 'bar', baz: 'qux' }, value: 15 }],
},
{
name: 'gauge_with_labels',
help: 'gauge with labels',
type: 'gauge',
samples: [
{ labels: { env: 'prod', region: 'us-east' }, value: 20 },
],
},
{
name: 'histogram_with_labels',
help: 'histogram with labels',
type: 'histogram',
samples: [
{
labels: { service: 'api', region: 'us-east' },
count: 3,
sum: 1.8,
buckets: [
{ le: 1, count: 2 },
{ le: '+Inf', count: 3 },
],
},
],
},
]);
expect(result).toContain('counter_with_labels{origin="sdk",metric_type="counter",foo="bar",baz="qux"} 15');
expect(result).toContain('gauge_with_labels{origin="sdk",metric_type="gauge",env="prod",region="us-east"} 20');
expect(result).toContain('histogram_with_labels_count{metric_type="histogram",origin="sdk",region="us-east",service="api"} 3');
expect(result).not.toContain('histogram_with_labels_count{metric_type="histogram",origin="sdk",service="api"} 5');
});
it('should handle histogram bucket changes', async () => {
await translator.translateAndSerializeMetrics([
{
name: 'test_histogram',
help: 'test histogram',
type: 'histogram',
samples: [
{
count: 5,
sum: 2.5,
buckets: [
{ le: 1, count: 3 },
{ le: '+Inf', count: 5 },
],
},
],
},
]);
const result = await translator.translateAndSerializeMetrics([
{
name: 'test_histogram',
help: 'test histogram',
type: 'histogram',
samples: [
{
count: 7,
sum: 3.5,
buckets: [
{ le: 0.5, count: 4 }, // Different bucket boundary
{ le: '+Inf', count: 7 },
],
},
],
},
]);
expect(result).toContain('test_histogram_bucket{metric_type="histogram",origin="sdk",le="0.5"} 4');
expect(result).toContain('test_histogram_count{metric_type="histogram",origin="sdk"} 7');
expect(result).not.toContain('test_histogram_count{metric_type="histogram",origin="sdk"} 5');
});
it('should skip metrics with names starting with a number', async () => {
const result = await translator.translateAndSerializeMetrics([
{
name: '1numeric-metric',
help: 'metric with numeric prefix',
type: 'gauge',
samples: [{ value: 10 }],
},
]);
expect(result).not.toContain('1numeric');
});
});
//# sourceMappingURL=metrics-translator.test.js.map