diff --git a/changelog.d/362.feature b/changelog.d/362.feature new file mode 100644 index 00000000..d114c11e --- /dev/null +++ b/changelog.d/362.feature @@ -0,0 +1 @@ +Add `bridge_app_version` metric, and utility functions to get the bridge app version. \ No newline at end of file diff --git a/package.json b/package.json index 7e86efd7..f44070ba 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "nedb": "^1.8.0", "nopt": "^5.0.0", "p-queue": "^6.6.2", - "prom-client": "^13.1.0", + "prom-client": "^14.0.0", "winston": "^3.3.3", "winston-daily-rotate-file": "^4.5.1" }, @@ -59,7 +59,7 @@ "nyc": "^15.1.0", "ts-node": "^10.2.1", "typedoc": "^0.20.36", - "typescript": "^4.2.3", + "typescript": "^4.4.3", "winston-transport": "^4.4.0" } } diff --git a/src/bridge.ts b/src/bridge.ts index 419d6fb5..5373066a 100644 --- a/src/bridge.ts +++ b/src/bridge.ts @@ -1571,6 +1571,10 @@ export class Bridge { * serve the "/metrics" page in the usual way. * The instance will automatically register the Matrix SDK metrics by calling * {PrometheusMetrics~registerMatrixSdkMetrics}. + * + * Ensure that `PackageInfo.getBridgeVersion` is returns the correct version before calling this, + * as changes to the bridge version after metric instantiation will not be detected. + * * @param {boolean} registerEndpoint Register the /metrics endpoint on the appservice HTTP server. Defaults to true. * Note: `listen()` must have been called if this is true or this will throw. * @param {Registry?} registry Optionally provide an alternative registry for metrics. diff --git a/src/components/app-service-bot.ts b/src/components/app-service-bot.ts index 62d351b4..cf5352fb 100644 --- a/src/components/app-service-bot.ts +++ b/src/components/app-service-bot.ts @@ -17,7 +17,7 @@ limitations under the License. import { AppServiceRegistration } from "matrix-appservice"; import { MembershipCache, UserProfile } from "./membership-cache"; import { StateLookupEvent } from ".."; -import { MatrixClient, MatrixProfileInfo } from "matrix-bot-sdk"; +import { MatrixClient } from "matrix-bot-sdk"; /** * Construct an AS bot user which has various helper methods. diff --git a/src/components/prometheusmetrics.ts b/src/components/prometheusmetrics.ts index 875a4a36..7f94984d 100644 --- a/src/components/prometheusmetrics.ts +++ b/src/components/prometheusmetrics.ts @@ -19,7 +19,8 @@ import { Request, Response } from "express"; import { Bridge } from ".."; import Logger from "./logging"; import { Appservice as BotSdkAppservice, FunctionCallContext, METRIC_MATRIX_CLIENT_FAILED_FUNCTION_CALL, - METRIC_MATRIX_CLIENT_FUNCTION_CALL, METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL } from "matrix-bot-sdk"; + METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL } from "matrix-bot-sdk"; +import { getBridgeVersion } from "../utils/package-info"; type CollectorFunction = () => Promise|void; export interface BridgeGaugesCounts { @@ -111,8 +112,20 @@ export class PrometheusMetrics { private counters: {[name: string]: PromClient.Counter} = {}; private collectors: CollectorFunction[] = []; private register: Registry; + /** + * Constructs a new Prometheus Metrics instance. + * The metric `app_version` will be set here, so ensure that `getBridgeVersion` + * will return the correct bridge version. + * @param register A custom registry to provide, if not using the global default. + */ constructor(register?: Registry) { this.register = register || PromClient.register; + this.addCounter({ + name: "app_version", + help: "Version number of the bridge", + labels: ["version"], + }); + this.counters["app_version"].inc({ version: getBridgeVersion()}); PromClient.collectDefaultMetrics({ register: this.register }); } diff --git a/src/index.ts b/src/index.ts index 1afed51e..10c17fc4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -58,6 +58,8 @@ export * from "./components/bridge-info-state"; export * from "./components/user-activity"; export * from "./components/bridge-blocker"; +export * from "./utils/package-info"; + export { AppServiceRegistration, AppService, AppServiceOutput } from "matrix-appservice"; diff --git a/src/utils/package-info.ts b/src/utils/package-info.ts new file mode 100644 index 00000000..d46d59f7 --- /dev/null +++ b/src/utils/package-info.ts @@ -0,0 +1,33 @@ +import { join, resolve } from "path"; +let BridgeVersion: string; + +/** + * Forcibly set the version of the bridge, for use by other components. + * This will override `getBridgeVersion`s default behaviour of fetching the + * version from package.json. + * @param version A version string e.g. `v1.0.0` + */ +export function setBridgeVersion(version: string): void { + BridgeVersion = version; +} + +/** + * Get the current version of the bridge from the package.json file. + * @param packageJsonPath The path to the package.json of the bridge. + * @returns Either the version number, or unknown. + */ +export function getBridgeVersion(packageJsonPath = "./package.json"): string { + if (BridgeVersion) { + return BridgeVersion; + } + packageJsonPath = join(resolve(packageJsonPath)); + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const nodePackage = require(packageJsonPath); + BridgeVersion = nodePackage.version; + } + catch (err) { + BridgeVersion = "unknown"; + } + return BridgeVersion; +} diff --git a/tsconfig.json b/tsconfig.json index c8254cc4..e9bbc49e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,8 @@ "strict": true, "esModuleInterop": true, "strictNullChecks": true, + /* We don't support this yet */ + "useUnknownInCatchVariables": false, "skipLibCheck": true, /* matrix-js-sdk throws up errors */ }, "include": [ diff --git a/yarn.lock b/yarn.lock index ec5f69e6..f85d0a09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2906,10 +2906,10 @@ progress@^2.0.0, progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@^13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-13.1.0.tgz#1185caffd8691e28d32e373972e662964e3dba45" - integrity sha512-jT9VccZCWrJWXdyEtQddCDszYsiuWj5T0ekrPszi/WEegj3IZy6Mm09iOOVM86A4IKMWq8hZkT2dD9MaSe+sng== +prom-client@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.0.tgz#7af5a0f8f544743f0dee4447c06ac9bb0d052719" + integrity sha512-etPa4SMO4j6qTn2uaSZy7+uahGK0kXUZwO7WhoDpTf3yZ837I3jqUDYmG6N0caxuU6cyqrg0xmOxh+yneczvyA== dependencies: tdigest "^0.1.1" @@ -3646,10 +3646,10 @@ typedoc@^0.20.36: shiki "^0.9.3" typedoc-default-themes "^0.12.10" -typescript@^4.2.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== +typescript@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== uglify-js@^3.1.4: version "3.13.4"