mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-29 15:12:58 +03:00
190ebcd684
ref https://linear.app/ghost/issue/ENG-1746/enable-ghost-to-push-metrics-to-a-pushgateway - We'd like to use prometheus to expose metrics from Ghost, but the "standard" approach of having prometheus scrape the `/metrics` endpoint adds some complexity and additional challenges on Pro. - A suggested simpler alternative is to use a pushgateway, to have Ghost _push_ metrics to prometheus, rather than have prometheus scrape the running instances. - This PR introduces this functionality behind a configuration. - It also includes a refactor to the current metrics-server implementation so all the related code for prometheus is colocated, and the configuration is a bit more organized. `@tryghost/metrics-server` has been renamed to `@tryghost/prometheus-metrics`, and it now includes the metrics server and prometheus-client code itself (including the pushgateway code) - To enable the prometheus client alone, `prometheus:enabled` must be true. This will _not_ enable the metrics server or the pushgateway — it will essentially collect the metrics, but not do anything with them. - To enable the metrics server, set `prometheus:metrics_server:enabled` to true. You can also configure the host and port that the metrics server should export the `/metrics` endpoint on in the `prometheus:metrics_server` block. - To enable the pushgateway, set `prometheus:pushgateway:enabled` to true. You can also configure the pushgateway's `url`, the `interval` it should push metrics in (in milliseconds) and the `jobName` in the `prometheus:pushgateway` block.
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import assert from 'assert/strict';
|
|
import {MetricsServer} from '../src';
|
|
import request from 'supertest';
|
|
import express from 'express';
|
|
import * as sinon from 'sinon';
|
|
|
|
describe('Metrics Server', function () {
|
|
let metricsServer: MetricsServer;
|
|
let serverConfig = {
|
|
host: '127.0.0.1',
|
|
port: 9416
|
|
};
|
|
let handler = (req: express.Request, res: express.Response) => {
|
|
res.send('metrics');
|
|
};
|
|
|
|
afterEach(async function () {
|
|
await metricsServer.stop();
|
|
});
|
|
|
|
after(async function () {
|
|
await metricsServer.shutdown();
|
|
});
|
|
|
|
describe('constructor', function () {
|
|
it('should create a new instance', function () {
|
|
metricsServer = new MetricsServer({serverConfig, handler});
|
|
assert.ok(metricsServer);
|
|
});
|
|
});
|
|
|
|
describe('start', function () {
|
|
before(function () {
|
|
metricsServer = new MetricsServer({serverConfig, handler});
|
|
});
|
|
it('should start the server', async function () {
|
|
const server = await metricsServer.start();
|
|
assert.ok(server);
|
|
});
|
|
|
|
it('should use the provided handler', async function () {
|
|
const {app} = await metricsServer.start();
|
|
const response = await request(app).get('/metrics');
|
|
assert.ok(response.status === 200);
|
|
assert.ok(response.text === 'metrics');
|
|
});
|
|
});
|
|
|
|
describe('stop', function () {
|
|
before(function () {
|
|
metricsServer = new MetricsServer({serverConfig, handler});
|
|
});
|
|
it('should stop the server', async function () {
|
|
const server = await metricsServer.start();
|
|
await metricsServer.stop();
|
|
assert.ok(server);
|
|
});
|
|
});
|
|
|
|
describe('shutdown', function () {
|
|
before(function () {
|
|
metricsServer = new MetricsServer({serverConfig, handler});
|
|
});
|
|
it('should shutdown the server', async function () {
|
|
const server = await metricsServer.start();
|
|
await metricsServer.shutdown();
|
|
assert.ok(server);
|
|
});
|
|
|
|
it('should not shutdown the server if it is already shutting down', async function () {
|
|
const stopSpy = sinon.spy(metricsServer, 'stop');
|
|
await metricsServer.start();
|
|
// Call shutdown multiple times simultaneously
|
|
Promise.all([metricsServer.shutdown(), metricsServer.shutdown()]);
|
|
// It should only call stop() once
|
|
sinon.assert.calledOnce(stopSpy);
|
|
});
|
|
});
|
|
});
|