Skip to content

Commit

Permalink
feat: support useFactory
Browse files Browse the repository at this point in the history
Closes #1776

Signed-off-by: Will Soto <willsoto@users.noreply.github.com>
  • Loading branch information
willsoto committed Aug 12, 2023
1 parent 009891c commit b4608da
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 37 deletions.
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@
* @internal
*/
export const PROMETHEUS_OPTIONS = Symbol("PROMETHEUS_OPTIONS");

/**
* @internal
*/
export const PROM_CLIENT = Symbol("PROM_CLIENT");
9 changes: 3 additions & 6 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,7 @@ export interface PrometheusAsyncOptions

/** {@inheritDoc PrometheusOptions.controller} */
controller?: PrometheusOptions["controller"];
/**
* Not currently supported since there doesn't seem to be a way to get
* the result of the function during configuration.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// useFactory?(...args: any[]): Promise<PrometheusOptions> | PrometheusOptions;
useFactory?(
...args: unknown[]
): Promise<PrometheusOptions> | PrometheusOptions;
}
47 changes: 26 additions & 21 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Provider,
} from "@nestjs/common";
import * as promClient from "prom-client";
import { PROMETHEUS_OPTIONS } from "./constants";
import { PROMETHEUS_OPTIONS, PROM_CLIENT } from "./constants";
import { PrometheusController } from "./controller";
import {
PrometheusAsyncOptions,
Expand Down Expand Up @@ -55,15 +55,28 @@ export class PrometheusModule {
module: PrometheusModule,
controllers: [controller],
imports: options.imports,
providers: providers,
exports: providers,
providers: [
...providers,
{
provide: PROM_CLIENT,
inject: [PROMETHEUS_OPTIONS],
useFactory(userOptions: PrometheusOptions) {
const opts = PrometheusModule.makeDefaultOptions(userOptions);

PrometheusModule.configureServer(opts);

return promClient;
},
},
],
exports: [...providers],
};
}

public static createAsyncProviders(
options: PrometheusAsyncOptions,
): Provider[] {
if (options.useExisting) {
if (options.useExisting || options.useFactory) {
return [
this.createAsyncOptionsProvider(options),
PrometheusModule.createPushgatewayProvider(),
Expand All @@ -87,17 +100,14 @@ export class PrometheusModule {
public static createAsyncOptionsProvider(
options: PrometheusAsyncOptions,
): Provider {
/**
* Not currently supported since there doesn't seem to be a way to get
* the result of the function during configuration.
*/
// if (options.useFactory) {
// return {
// provide: PROMETHEUS_OPTIONS,
// useFactory: options.useFactory,
// inject: options.inject || [],
// };
// }
if (options.useFactory) {
return {
provide: PROMETHEUS_OPTIONS,
// eslint-disable-next-line @typescript-eslint/unbound-method
useFactory: options.useFactory,
inject: options.inject || [],
};
}

const inject = options.useClass || options.useExisting;

Expand All @@ -112,12 +122,7 @@ export class PrometheusModule {
async useFactory(
optionsFactory: PrometheusOptionsFactory,
): Promise<PrometheusOptions> {
const userOptions = await optionsFactory.createPrometheusOptions();
const opts = PrometheusModule.makeDefaultOptions(userOptions);

PrometheusModule.configureServer(opts);

return opts;
return optionsFactory.createPrometheusOptions();
},
inject: [inject],
};
Expand Down
67 changes: 57 additions & 10 deletions test/module.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { Injectable, Module } from "@nestjs/common";
import { TestingModule } from "@nestjs/testing";
import { expect } from "chai";
import { register } from "prom-client";
import { PrometheusModule, PrometheusOptionsFactory } from "../src";
import { Pushgateway, register } from "prom-client";
import {
PrometheusModule,
PrometheusOptions,
PrometheusOptionsFactory,
} from "../src";
import {
Agent,
App,
Expand All @@ -12,12 +17,18 @@ import {
describe("PrometheusModule", function () {
let agent: Agent;
let app: App;
let testingModule: TestingModule;

afterEach(async function () {
register.clear();

if (app) {
register.clear();
await app.close();
}

if (testingModule) {
await testingModule.close();
}
});

describe("#register", function () {
Expand Down Expand Up @@ -97,11 +108,6 @@ describe("PrometheusModule", function () {
const response = await agent.get("/metrics");

expect(response).to.have.property("status").to.eql(200);
});

it("collects default metrics", async function () {
const response = await agent.get("/metrics");

expect(response)
.to.have.property("text")
.to.contain("process_cpu_user_seconds_total");
Expand All @@ -120,15 +126,56 @@ describe("PrometheusModule", function () {
const response = await agent.get("/metrics");

expect(response).to.have.property("status").to.eql(200);
expect(response)
.to.have.property("text")
.to.contain("process_cpu_user_seconds_total");
});
});

describe("useFactory", function () {
@Injectable()
class MyConfigService {
options(): PrometheusOptions {
return {
path: "/my/custom/path/metrics",
pushgateway: {
url: "http://127.0.0.1:9091",
},
};
}
}

@Module({
providers: [MyConfigService],
exports: [MyConfigService],
})
class MyConfigModule {}

beforeEach(async function () {
({ agent, app, testingModule } = await createAsyncPrometheusModule({
imports: [MyConfigModule],
inject: [MyConfigService],
useFactory(config: MyConfigService) {
return config.options();
},
}));
});

it("collects default metrics", async function () {
const response = await agent.get("/metrics");
it("registers a custom endpoint", async function () {
const response = await agent.get("/my/custom/path/metrics");

expect(response).to.have.property("status").to.eql(200);
expect(response)
.to.have.property("text")
.to.contain("process_cpu_user_seconds_total");
});

it("should register the push gateway", function () {
const gateway = testingModule.get(Pushgateway);

expect(gateway).to.be.instanceOf(Pushgateway);
expect(gateway).to.have.property("gatewayUrl", "http://127.0.0.1:9091");
});
});
});

Expand Down

0 comments on commit b4608da

Please sign in to comment.