metric.ts
import {
Counter,
Histogram,
Gauge,
Summary,
Pushgateway,
Registry,
} from 'prom-client';
type MetricData = {
name: string;
labels: Record<string, string>;
labelNames: string[];
type: string;
help: string;
value?: number;
buckets?: number[];
percentiles?: number[];
};
export enum MetricType {
CounterType = 'counter',
HistogramType = 'histogram',
GaugeType = 'gauge',
SummaryType = 'summary',
}
const register = new Registry();
// 上报到平台
export async function pushGateway() {
try {
const gateway = new Pushgateway(
'https://xxx',
[],
register
);
const { resp, body } = await gateway.push({ jobName: 'pipeline test' });
console.log(
`push gateway successfully, status code is ${
(resp as any).statusCode
}, body is ${body}`
);
} catch (err) {
console.log('push gateway failed:', err);
}
}
// 创建指标类别
function createCounter(metricData: MetricData) {
const { name, help, labelNames } = metricData;
let counter = register.getSingleMetric(name) as Counter<string>;
if (!counter) {
counter = new Counter({
name,
help,
labelNames,
registers: [register],
});
}
return counter;
}
function createHistogram(metricData: MetricData) {
const { name, help, labelNames, buckets } = metricData;
let histogram = register.getSingleMetric(name) as Histogram<string>;
if (!histogram) {
histogram = new Histogram({
name,
help,
labelNames,
buckets,
registers: [register],
});
}
return histogram;
}
function createSummary(metricData: MetricData) {
const { name, help, labelNames, percentiles } = metricData;
let summary = register.getSingleMetric(name) as Summary<string>;
if (!summary) {
summary = new Summary({
name,
help,
labelNames,
percentiles,
registers: [register],
});
}
return summary;
}
function createGauge(metricData: MetricData) {
const { name, help, labelNames } = metricData;
let gauge = register.getSingleMetric(name) as Gauge<string>;
if (!gauge) {
gauge = new Gauge({
name,
help,
labelNames,
registers: [register],
});
}
return gauge;
}
export function handleMetric(metricData: MetricData) {
const { type: metricType, value, labels } = metricData;
const newValue = value || 1;
if (metricType === MetricType.CounterType) {
const counter = createCounter(metricData);
register.registerMetric(counter);
counter.inc(labels, newValue);
} else if (metricType === MetricType.HistogramType) {
const histogram = createHistogram(metricData);
register.registerMetric(histogram);
histogram.observe(labels, newValue);
} else if (metricType === MetricType.SummaryType) {
const summary = createSummary(metricData);
register.registerMetric(summary);
summary.observe(labels, newValue);
} else if (metricType === MetricType.GaugeType) {
const gauge = createGauge(metricData);
register.registerMetric(gauge);
gauge.set(labels, newValue);
}
}
使用:
async function collectMetrics(name: string) {
try {
// 先获取指标原始数据
// 比如需要掉接口拉取
// await getList()...
const labels = {
labels: {
name,
env
},
labelNames: [
'name',
'env',
],
};
const counterMetric = {
name: 'pipeline_run_total',
help: 'pipeline run total',
type: MetricType.CounterType,
...labels,
};
const histogramMetric = {
name: 'pipeline_run_duration',
help: 'pipeline run finished',
value: duration,
buckets: [
30000, 60000, 75000, 90000, 105000, 120000, 135000, 150000, 165000,
180000, 195000, 210000, 225000, 240000, 270000, 300000, 330000,
360000,
],
type: MetricType.HistogramType,
...labels,
};
// 处理指标
[counterMetric, histogramMetric].forEach((metric) =>
handleMetric(metric)
);
}
} catch (err) {
// err
}
}
(async () => {
// collect metrics
const testNames=['test1','test2']
await Promise.all(testNames.map((name) => collectMetrics(name)));
// export to metric store
await pushGateway();
})()
.catch((e) => console.log(e.message || e))