UNPKG

@graphql-yoga/plugin-prometheus

Version:
104 lines (103 loc) 4.12 kB
import { usePrometheus as useEnvelopPrometheus, createCounter, createHistogram, createSummary, } from '@envelop/prometheus'; import { getOperationAST } from 'graphql'; import { Histogram, register as defaultRegistry } from 'prom-client'; export { createCounter, createHistogram, createSummary }; function headersToObj(headers) { const obj = {}; headers.forEach((value, key) => { obj[key] = value; }); return obj; } export function usePrometheus(options) { const endpoint = options.endpoint || '/metrics'; const registry = options.registry || defaultRegistry; let httpHistogram; if (options.http) { const labelNames = [ 'url', 'method', 'statusCode', 'statusText', 'operationName', 'operationType', ]; if (options.httpRequestHeaders) { labelNames.push('requestHeaders'); } if (options.httpResponseHeaders) { labelNames.push('responseHeaders'); } httpHistogram = typeof options.http === 'object' ? options.http : createHistogram({ histogram: new Histogram({ name: 'graphql_yoga_http_duration', help: 'Time spent on HTTP connection', labelNames, registers: [registry], }), fillLabelsFn(params, { request, response }) { const labels = { operationName: params.operationName || 'Anonymous', url: request.url, method: request.method, statusCode: response.status, statusText: response.statusText, }; if (params?.operationType) { labels.operationType = params.operationType; } if (options.httpRequestHeaders) { labels.requestHeaders = JSON.stringify(headersToObj(request.headers)); } if (options.httpResponseHeaders) { labels.responseHeaders = JSON.stringify(headersToObj(response.headers)); } return labels; }, }); } const startByRequest = new WeakMap(); const paramsByRequest = new WeakMap(); return { onPluginInit({ addPlugin }) { addPlugin(useEnvelopPrometheus({ ...options, registry })); }, async onRequest({ request, url, fetchAPI, endResponse }) { startByRequest.set(request, Date.now()); if (url.pathname === endpoint) { const metrics = await registry.metrics(); const response = new fetchAPI.Response(metrics, { headers: { 'Content-Type': registry.contentType, }, }); endResponse(response); } }, onExecute({ args }) { const operationAST = getOperationAST(args.document, args.operationName); const operationType = operationAST?.operation; const operationName = operationAST?.name?.value; paramsByRequest.set(args.contextValue.request, { document: args.document, operationName, operationType, }); }, onResponse({ request, response, serverContext }) { const start = startByRequest.get(request); if (start) { const duration = Date.now() - start; const params = paramsByRequest.get(request); httpHistogram?.histogram.observe(httpHistogram.fillLabelsFn(params || {}, { ...serverContext, request, response, }), duration); } }, }; }