Skip to content

Commit

Permalink
Add basic support for metrics (#203)
Browse files Browse the repository at this point in the history
* Add basic support for metrics.

* Add metrics config
  • Loading branch information
Half-Shot authored Dec 5, 2023
1 parent d20c012 commit fc271d6
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 4 deletions.
7 changes: 6 additions & 1 deletion config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -308,4 +308,9 @@ ircBridge: null
#channelPrefix: '#conference-'

templatesPath: ./srv
runMode: normal
runMode: normal

metrics:
enabled: false
port: 8081
address: 127.0.0.1
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"moment": "^2.29.4",
"node-fetch": "^2.6.1",
"pg": "^8.9.0",
"prom-client": "^15.0.0",
"qs": "^6.11.2",
"rfc4648": "^1.4.0",
"xss": "^1.0.14"
Expand Down
5 changes: 5 additions & 0 deletions spec/util/e2e-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ export class E2ETestEnv {
managementRoom: mgmntRoom,
templatesPath: '/dev/null',
mode: RunMode.normal,
metrics: {
enabled: false,
address: '0.0.0.0',
port: 0,
},
...providedConfig,
};
const conferenceBot = await ConferenceBot.start(config);
Expand Down
46 changes: 45 additions & 1 deletion src/ConferenceMatrixClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { IStorageProvider, IdentityClient, MatrixClient } from "matrix-bot-sdk";
import { FunctionCallContext, IStorageProvider, IdentityClient, METRIC_IDENTITY_CLIENT_FAILED_FUNCTION_CALL, METRIC_IDENTITY_CLIENT_SUCCESSFUL_FUNCTION_CALL, METRIC_MATRIX_CLIENT_FAILED_FUNCTION_CALL, METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL, MatrixClient } from "matrix-bot-sdk";
import { IConfig } from "./config";
import { Counter } from "prom-client";

const matrixApiCalls = new Counter({ name: "matrix_api_calls", help: "The number of Matrix client API calls made.", labelNames: ["method"]});
const matrixApiCallsFailed = new Counter({ name: "matrix_api_calls_failed", help: "The number of Matrix client API calls which failed.", labelNames: ["method"]});
const matrixIdentityApiCalls = new Counter({ name: "matrix_identity_api_calls", help: "The number of Matrix identity API calls made.", labelNames: ["method"]});
const matrixIdentityApiCallsFailed = new Counter({ name: "matrix_identity_api_calls_failed", help: "The number of Matrix identity API calls which failed.", labelNames: ["method"]});


export class ConferenceMatrixClient extends MatrixClient {
static async create(confConfig: IConfig, storage?: IStorageProvider) {
Expand All @@ -21,5 +28,42 @@ export class ConferenceMatrixClient extends MatrixClient {
public readonly managementRoom: string,
storage?: IStorageProvider) {
super(homeserverUrl, accessToken, storage);
this.metrics.registerListener({
onStartMetric: () => {
// Not used yet.
},
onEndMetric: () => {
// Not used yet.
},
onIncrement: (metricName, context) => {
if (metricName === METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL) {
const ctx = context as FunctionCallContext;
matrixApiCalls.inc({method: ctx.functionName});
}
if (metricName === METRIC_MATRIX_CLIENT_FAILED_FUNCTION_CALL) {
const ctx = context as FunctionCallContext;
matrixApiCallsFailed.inc({method: ctx.functionName});
}
if (metricName === METRIC_IDENTITY_CLIENT_SUCCESSFUL_FUNCTION_CALL) {
const ctx = context as FunctionCallContext;
matrixIdentityApiCalls.inc({method: ctx.functionName});
}
if (metricName === METRIC_IDENTITY_CLIENT_FAILED_FUNCTION_CALL) {
const ctx = context as FunctionCallContext;
matrixIdentityApiCallsFailed.inc({method: ctx.functionName});
}
},
onDecrement: () => {
// Not used yet.
},
onReset: (metricName) => {
if (metricName === METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL) {
matrixApiCalls.reset();
}
if (metricName === METRIC_MATRIX_CLIENT_FAILED_FUNCTION_CALL) {
matrixApiCallsFailed.reset();
}
},
})
}
}
5 changes: 4 additions & 1 deletion src/Scheduler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import { Talk } from "./models/Talk";
import { CheckInMap } from "./CheckInMap";
import { ConferenceMatrixClient } from "./ConferenceMatrixClient";
import { IConfig } from "./config";
import { Counter } from "prom-client";

const matrixIdentityApiCallsFailed = new Counter({ name: "confbot_scheduler_last_run", help: "The last time the Scheduler ran its tasks."});

export enum ScheduledTaskType {
TalkStart = "talk_start",
Expand Down Expand Up @@ -193,7 +196,7 @@ export class Scheduler {
private async runTasks() {
try {
const now = (new Date()).getTime();
// const pentaDb = await this.conference.getPentaDb();
matrixIdentityApiCallsFailed.inc(now);
await this.lock.acquireAsync();
LogService.info("Scheduler", "Scheduling tasks");
try {
Expand Down
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export interface IConfig {
publicBaseUrl: string;
additionalAssetsPath: string;
};
metrics: {
enabled: boolean;
address: string;
port: number;
};
conference: {
id: string;
name: string;
Expand Down
20 changes: 19 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import { StatusCommand } from "./commands/StatusCommand";
import { CachingBackend } from "./backends/CachingBackend";
import { ConferenceMatrixClient } from "./ConferenceMatrixClient";
import { Server } from "http";
import { collectDefaultMetrics, register } from "prom-client";

LogService.setLogger(new CustomLogger());
LogService.setLevel(LogLevel.DEBUG);
Expand Down Expand Up @@ -101,6 +102,7 @@ export class ConferenceBot {
}

private webServerInstance?: Server;
private metricsServerInstance?: Server;

private constructor(
private readonly config: IConfig,
Expand Down Expand Up @@ -139,6 +141,22 @@ export class ConferenceBot {
// Setup the webserver first.
await this.setupWebserver();

// Setup metrics
if (this.config.metrics?.enabled) {
collectDefaultMetrics();
const metricsApp = express();
metricsApp.get('/metrics', (_req, res) => {
register.metrics().then(
(m) => res.type('text/plain').send((m))
).catch((err) => {
LogService.info("index", "Failed to fetch metrics: ", err);
res.status(500).send('Could not fetch metrics due to an error');
});
});
this.metricsServerInstance = metricsApp.listen(this.config.metrics.port, this.config.metrics.address);
LogService.info("index", `Metrics listening on ${this.config.metrics.address}:${this.config.metrics.port}`)
}

await this.client.joinRoom(this.config.managementRoom);
await this.conference.construct();

Expand Down Expand Up @@ -177,7 +195,6 @@ export class ConferenceBot {
);
}


await this.scheduler.prepare();

// Needs to happen after the sync loop has started
Expand Down Expand Up @@ -289,6 +306,7 @@ export class ConferenceBot {
await this.scheduler.stop();
this.client.stop();
this.webServer?.close();
this.metricsServerInstance?.close();
}
}

Expand Down
25 changes: 25 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,11 @@
https-proxy-agent "^5.0.1"
node-downloader-helper "^2.1.5"

"@opentelemetry/api@^1.4.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.7.0.tgz#b139c81999c23e3c8d3c0a7234480e945920fc40"
integrity sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==

"@selderee/plugin-htmlparser2@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz#27e994afd1c2cb647ceb5406a185a5574188069d"
Expand Down Expand Up @@ -1471,6 +1476,11 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==

[email protected]:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.2.tgz#49f896d6e858a4a499df85c38fb399b9aff840f8"
integrity sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==

bluebird@^3.5.0:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
Expand Down Expand Up @@ -4715,6 +4725,14 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==

prom-client@^15.0.0:
version "15.0.0"
resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.0.0.tgz#067da874a2aa5d2e21bd5cdba9f24a8178bdab6a"
integrity sha512-UocpgIrKyA2TKLVZDSfm8rGkL13C19YrQBAiG3xo3aDFWcHedxRxI3z+cIcucoxpSO0h5lff5iv/SXoxyeopeA==
dependencies:
"@opentelemetry/api" "^1.4.0"
tdigest "^0.1.1"

prompts@^2.0.1:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
Expand Down Expand Up @@ -5450,6 +5468,13 @@ tapable@^2.1.1, tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==

tdigest@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.2.tgz#96c64bac4ff10746b910b0e23b515794e12faced"
integrity sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==
dependencies:
bintrees "1.0.2"

terser-webpack-plugin@^5.3.7:
version "5.3.9"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1"
Expand Down

0 comments on commit fc271d6

Please sign in to comment.