n1ru4l / envelop

Envelop is a lightweight library allowing developers to easily develop, share, collaborate and extend their GraphQL execution layer. Envelop is the missing GraphQL plugin system.
https://envelop.dev
MIT License
785 stars 127 forks source link

Configure context derived labels for all metrics #2245

Open ethanrcohen opened 4 months ago

ethanrcohen commented 4 months ago

Is your feature request related to a problem? Please describe.

Users may wish to apply some labels to all metrics based on the specific request context -- for example, a server that acts as a backend for multiple front-end clients may wish to label metrics according to the client type.

RIght now, the best way that I can see to do this is to provide createHistogram/createSummary/createCounter functions for each metric collected, ex:

usePrometheus({
            endpoint: false,
            requestCount: createCounter({
                registry,
                counter: {
                    name: "graphql_request_count",
                    help: "Number of GraphQL requests",
                    labelNames: ["operationName", "operationType"],
                },
                fillLabelsFn: (params, rawContext) => {
                    return {
                        operationName: params.operationName,
                        operationType: params.operationType,
                        clientType: getClientTypeFromContext(rawContext),
                    };
                },
            }),
            requestTotalDuration: createHistogram({
                registry,
                histogram: {
                    name: "graphql_request_duration_seconds",
                    help: "Duration of GraphQL requests in seconds",
                    labelNames: ["operationName", "operationType"],
                },
                fillLabelsFn: (params, rawContext) => {
                    return {
                        operationName: params.operationName,
                        operationType: params.operationType,
                        clientType: getClientTypeFromContext(rawContext),
                    };
                },
            }),
            ...

Describe the solution you'd like

It would be nice if there were a configuration option on the plugin that allowed the user to provide a function that takes the context and returns some labels.

contextLabels?: (context: TUserContext) =>  Record<LabelNames, string | number>;

Describe alternatives you've considered

It's possible that I'm missing something that allows one to do this already. If so, apologies.

Additional context

EmrysMyrddin commented 4 months ago

Thank you for your proposal!

The solution today is, as you found out, to use metric customization (just don't forget to add your new label to the labelNames configuration field).

The use case you are describing is totally understandable and I also think it could be awesome to have a better API for this than forcing users to re-define every metrics.

That being said, we have to be very careful about it here, since this plugin is actually exists in different variants, each one based on the previous one:

If we want to add global labels applied to every metrics, we also to take in account these other variants, so every metrics actually get the label, not only the Envelop ones.

EmrysMyrddin commented 4 months ago

After some discussion, we definitely want to have this feature :slightly_smiling_face: But we will probably not tackle this immediately. If you want, PR are very welcome and we are here to help if you have any questions or need any guidance.

We can even offer to open a channel in our private slack, this way we could continue to discus about your use case in a more confidential environment :slightly_smiling_face:

ethanrcohen commented 4 months ago

Awesome, thanks!

The solution today is, as you found out, to use metric customization (just don't forget to add your new label to the labelNames configuration field).

🙏 posted this before testing, good eye!

That being said, we have to be very careful about it here, since this plugin is actually exists in different variants

Ack, we're using through Yoga, but I wasn't familiar with the Mesh plugin. Will take a look

After some discussion, we definitely want to have this feature 🙂 But we will probably not tackle this immediately. If you want, PR are very welcome and we are here to help if you have any questions or need any guidance.

We can even offer to open a channel in our private slack, this way we could continue to discus about your use case in a more confidential environment 🙂

I'm a bit slammed right now but could probably put up a PR in a week or two