Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add diag warning when metric name is invalid #2122

Merged
merged 11 commits into from
Apr 22, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ export class PrometheusSerializer {
if (this._prefix) {
name = `${this._prefix}${name}`;
}

if (
!name.endsWith('_total') &&
checkpoint.descriptor.metricKind === MetricKind.COUNTER
) {
name = name + '_total';
}

const help = `# HELP ${name} ${escapeString(
checkpoint.descriptor.description || 'description missing'
)}`;
Expand All @@ -179,6 +187,14 @@ export class PrometheusSerializer {

serializeRecord(name: string, record: MetricRecord): string {
let results = '';

if (
record.descriptor.metricKind === MetricKind.COUNTER &&
!name.endsWith('_total')
) {
name = name + '_total';
}

switch (record.aggregator.kind) {
case AggregatorKind.SUM:
case AggregatorKind.LAST_VALUE: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ describe('PrometheusExporter', () => {
});

it('should export a count aggregation', done => {
const counter = meter.createCounter('counter', {
const counter = meter.createCounter('counter_total', {
description: 'a test description',
});

Expand All @@ -251,13 +251,13 @@ describe('PrometheusExporter', () => {

assert.strictEqual(
lines[0],
'# HELP counter a test description'
'# HELP counter_total a test description'
);

assert.deepStrictEqual(lines, [
'# HELP counter a test description',
'# TYPE counter counter',
`counter{key1="labelValue1"} 20 ${mockedHrTimeMs}`,
'# HELP counter_total a test description',
'# TYPE counter_total counter',
`counter_total{key1="labelValue1"} 20 ${mockedHrTimeMs}`,
'',
]);

Expand Down Expand Up @@ -650,9 +650,9 @@ describe('PrometheusExporter', () => {
const lines = body.split('\n');

assert.deepStrictEqual(lines, [
'# HELP counter description missing',
'# TYPE counter counter',
`counter{key1="labelValue1"} 10 ${mockedHrTimeMs}`,
'# HELP counter_total description missing',
'# TYPE counter_total counter',
`counter_total{key1="labelValue1"} 10 ${mockedHrTimeMs}`,
'',
]);

Expand Down Expand Up @@ -680,9 +680,9 @@ describe('PrometheusExporter', () => {
const lines = body.split('\n');

assert.deepStrictEqual(lines, [
'# HELP counter description missing',
'# TYPE counter counter',
`counter{key1="labelValue1"} 10 ${mockedHrTimeMs}`,
'# HELP counter_total description missing',
'# TYPE counter_total counter',
`counter_total{key1="labelValue1"} 10 ${mockedHrTimeMs}`,
'',
]);

Expand Down Expand Up @@ -710,9 +710,9 @@ describe('PrometheusExporter', () => {
const lines = body.split('\n');

assert.deepStrictEqual(lines, [
'# HELP counter description missing',
'# TYPE counter counter',
'counter{key1="labelValue1"} 10',
'# HELP counter_total description missing',
'# TYPE counter_total counter',
'counter_total{key1="labelValue1"} 10',
'',
]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
UpDownCounterMetric,
ValueObserverMetric,
} from '@opentelemetry/metrics';
import { diag, DiagLogLevel } from '@opentelemetry/api';
import * as assert from 'assert';
import { Labels } from '@opentelemetry/api-metrics';
import { PrometheusSerializer } from '../src/PrometheusSerializer';
Expand Down Expand Up @@ -53,7 +54,7 @@ describe('PrometheusSerializer', () => {
const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test') as CounterMetric;
const counter = meter.createCounter('test_total') as CounterMetric;
counter.bind(labels).add(1);

const records = await counter.getMetricRecord();
Expand All @@ -65,7 +66,7 @@ describe('PrometheusSerializer', () => {
);
assert.strictEqual(
result,
`test{foo1="bar1",foo2="bar2"} 1 ${mockedHrTimeMs}\n`
`test_total{foo1="bar1",foo2="bar2"} 1 ${mockedHrTimeMs}\n`
);
});

Expand All @@ -75,7 +76,7 @@ describe('PrometheusSerializer', () => {
const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test') as CounterMetric;
const counter = meter.createCounter('test_total') as CounterMetric;
counter.bind(labels).add(1);

const records = await counter.getMetricRecord();
Expand All @@ -85,7 +86,7 @@ describe('PrometheusSerializer', () => {
record.descriptor.name,
record
);
assert.strictEqual(result, 'test{foo1="bar1",foo2="bar2"} 1\n');
assert.strictEqual(result, 'test_total{foo1="bar1",foo2="bar2"} 1\n');
});
});

Expand Down Expand Up @@ -155,6 +156,7 @@ describe('PrometheusSerializer', () => {
const recorder = meter.createValueRecorder('test', {
description: 'foobar',
}) as ValueRecorderMetric;

recorder.bind(labels).record(5);

const records = await recorder.getMetricRecord();
Expand Down Expand Up @@ -244,7 +246,7 @@ describe('PrometheusSerializer', () => {
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const processor = new PrometheusLabelsBatcher();
const counter = meter.createCounter('test', {
const counter = meter.createCounter('test_total', {
description: 'foobar',
}) as CounterMetric;
counter.bind({ val: '1' }).add(1);
Expand All @@ -257,10 +259,10 @@ describe('PrometheusSerializer', () => {
const result = serializer.serialize(checkPointSet);
assert.strictEqual(
result,
'# HELP test foobar\n' +
'# TYPE test counter\n' +
`test{val="1"} 1 ${mockedHrTimeMs}\n` +
`test{val="2"} 1 ${mockedHrTimeMs}\n`
'# HELP test_total foobar\n' +
'# TYPE test_total counter\n' +
`test_total{val="1"} 1 ${mockedHrTimeMs}\n` +
`test_total{val="2"} 1 ${mockedHrTimeMs}\n`
);
});

Expand All @@ -271,7 +273,7 @@ describe('PrometheusSerializer', () => {
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const processor = new PrometheusLabelsBatcher();
const counter = meter.createCounter('test', {
const counter = meter.createCounter('test_total', {
description: 'foobar',
}) as CounterMetric;
counter.bind({ val: '1' }).add(1);
Expand All @@ -284,10 +286,10 @@ describe('PrometheusSerializer', () => {
const result = serializer.serialize(checkPointSet);
assert.strictEqual(
result,
'# HELP test foobar\n' +
'# TYPE test counter\n' +
'test{val="1"} 1\n' +
'test{val="2"} 1\n'
'# HELP test_total foobar\n' +
'# TYPE test_total counter\n' +
'test_total{val="1"} 1\n' +
'test_total{val="2"} 1\n'
);
});
});
Expand Down Expand Up @@ -370,6 +372,54 @@ describe('PrometheusSerializer', () => {
});
});

describe('validate against metric conventions', () => {
mockAggregator(SumAggregator);

it('should rename metric of type counter when name misses _total suffix', async () => {
const serializer = new PrometheusSerializer();

const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test') as CounterMetric;
counter.bind({}).add(1);

const records = await counter.getMetricRecord();
const record = records[0];

const result = serializer.serializeRecord(record.descriptor.name, record);
assert.strictEqual(result, `test_total 1 ${mockedHrTimeMs}\n`);
});

it('should not warn for counter metrics with correct name', async () => {
let calledArgs: any[] = [];
const dummyLogger = {
verbose: () => {},
debug: (...args: any[]) => {
calledArgs = args;
},
info: () => {},
warn: () => {},
error: () => {},
};
diag.setLogger(dummyLogger, DiagLogLevel.ALL);
const serializer = new PrometheusSerializer();

const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test_total') as CounterMetric;
counter.bind({}).add(1);

const records = await counter.getMetricRecord();
const record = records[0];

const result = serializer.serializeRecord(record.descriptor.name, record);
assert.strictEqual(result, `test_total 1 ${mockedHrTimeMs}\n`);
assert.ok(calledArgs.length === 0);
});
});

describe('serialize non-normalized values', () => {
describe('with SumAggregator', () => {
mockAggregator(SumAggregator);
Expand All @@ -380,7 +430,7 @@ describe('PrometheusSerializer', () => {
const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test') as CounterMetric;
const counter = meter.createCounter('test_total') as CounterMetric;
counter.bind({}).add(1);

const records = await counter.getMetricRecord();
Expand All @@ -390,7 +440,7 @@ describe('PrometheusSerializer', () => {
record.descriptor.name,
record
);
assert.strictEqual(result, `test 1 ${mockedHrTimeMs}\n`);
assert.strictEqual(result, `test_total 1 ${mockedHrTimeMs}\n`);
});

it('should serialize non-string label values', async () => {
Expand All @@ -399,7 +449,7 @@ describe('PrometheusSerializer', () => {
const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test') as CounterMetric;
const counter = meter.createCounter('test_total') as CounterMetric;
counter
.bind(({
object: {},
Expand All @@ -417,7 +467,7 @@ describe('PrometheusSerializer', () => {
);
assert.strictEqual(
result,
`test{object="[object Object]",NaN="NaN",null="null",undefined="undefined"} 1 ${mockedHrTimeMs}\n`
`test_total{object="[object Object]",NaN="NaN",null="null",undefined="undefined"} 1 ${mockedHrTimeMs}\n`
);
});

Expand Down Expand Up @@ -457,7 +507,7 @@ describe('PrometheusSerializer', () => {
const meter = new MeterProvider({
processor: new ExactProcessor(SumAggregator),
}).getMeter('test');
const counter = meter.createCounter('test') as CounterMetric;
const counter = meter.createCounter('test_total') as CounterMetric;
counter
.bind(({
backslash: '\u005c', // \ => \\ (\u005c\u005c)
Expand All @@ -477,7 +527,7 @@ describe('PrometheusSerializer', () => {
);
assert.strictEqual(
result,
'test{' +
'test_total{' +
'backslash="\u005c\u005c",' +
'doubleQuote="\u005c\u0022",' +
'lineFeed="\u005c\u006e",' +
Expand Down