willsoto/nestjs-prometheus

How to inject app/custom dependencies into PrometheusModule

Closed this issue ยท 6 comments

Hi there. Thank you very much for your work! So far everything is working great. However, I wanted to add a call to update gauges whenever the metrics are scraped. I thought I could use Custom Controller for this but I can't find a way to inject a dependency for my custom controller into the PrometheusModule.

Example

@Controller()
export class AppPrometheusController extends PrometheusController {
  constructor(private readonly someService: SomeService) {
    super();
  }
  @Get()
  async index(@Res({ passthrough: true }) response: Response): Promise<string> {
    await this.someService.updateGauges();
    return super.index(response);
  }
}

Usage

    PrometheusModule.register({
      controller: AppPrometheusController,
      // can't put `providers` or `imports` here?
    }),

Error

{"context":"ExceptionHandler","stack":["Error: Nest can't resolve dependencies of the AppPrometheusController (?).
Please make sure that the argument SomeService at index [0] is available in the PrometheusModule context.
Potential solutions:
- If SomeService is a provider, is it part of the current PrometheusModule?
- If SomeService is exported from a separate @Module, is that module imported within PrometheusModule?
...

I saw there is also registerAsync, createAsyncProviders and createAsyncOptionsProvider but as they are not well documented, I'm not sure if they would be of any help.

Probably registerAsync + useFactory is what you want. They are not documented here because they are fundamental NestJS concepts: https://docs.nestjs.com/fundamentals/async-providers

PrometheusModule.registerAsync is not a NestJS concept. It requires me to define useClass or useExisting that want a Type<PrometheusOptionsFactory> which I don't know how to construct. I tried looking through your tests but it doesn't fully make sense to me. I also don't see how it would solve my problem? I don't want to create the prometheus module / PrometheusOptions asynchronously but inject my dependency into the controller.

Yes it is, it's a pattern used all over NestJS. Here is an example from an official module (name is different, concept is the same): https://docs.nestjs.com/graphql/quick-start#async-configuration

Check out the Custom Providers as well.

It would solve your problem because your controller would now be able to inject dependencies. So probably what you want here is some combination to create the controller outside of the PrometheusModule context with whatever dependencies you need (async) and then you would PrometheusModule.registerAsync to inject the controller.

This pattern is common to NestJS, true. But what @bijancn is referring to is PrometheusAsyncOptions is defined as

export interface PrometheusAsyncOptions extends Pick<ModuleMetadata, "imports"> {
    useExisting?: Type<PrometheusOptionsFactory>;
    useClass?: Type<PrometheusOptionsFactory>;
    inject?: any[];
    /** {@inheritDoc PrometheusOptions.controller} */
    controller?: PrometheusOptions["controller"];
}

Which does not allow to use useFactory:

TS2345: Argument of type '{ inject: (typeof ConfigService)[]; useFactory: (configService: ConfigService) => {...}' is not assignable to parameter of type 'PrometheusAsyncOptions'.   Object literal may only specify known properties, and 'useFactory' does not exist in type 'PrometheusAsyncOptions'.

Which makes it impossible to use factory at this point.

Ah yes. Well at the time I wrote this, I couldn't find a way to get the result of useFactory:

/**
* 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 || [],
// };
// }

I can take a look again (or you are welcome to) since it really should be supported if possible.

๐ŸŽ‰ This issue has been resolved in version 5.3.0 ๐ŸŽ‰

The release is available on:

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€