UNPKG

@cran/gql.koa

Version:

Cran/GraphQL Koa Server

108 lines (107 loc) 3.94 kB
/* eslint-disable max-lines */ import { SpanStatusCode } from "@opentelemetry/api"; import { isatty } from "tty"; import { snakeCase } from "lodash"; import { Counter, Histogram, Summary, collectDefaultMetrics } from "prom-client"; import { ExportResultCode, hrTimeToMilliseconds } from "@opentelemetry/core"; export class MetricSpanExporter { metrics = {}; config; constructor(config) { collectDefaultMetrics({ prefix: config.prefix, }); this.config = { prefix: "", trace: MetricSpanExporter.defaultTracer, ...config, relabel: { ...MetricSpanExporter.defaultRelabel, ...config.relabel, }, }; } export(spans, done) { return void this.send(spans, done); } async shutdown() { this.send([]); } format(span) { return { ok: span.status.code !== SpanStatusCode.ERROR, name: span.name, timestamp: hrTimeToMilliseconds(span.startTime), duration: hrTimeToMilliseconds(span.duration), attributes: span.attributes, }; } send(spans, done) { for (const span of spans) { const result = this.format(span); this.config.trace(result); this.metric(result.name, result.duration, span); } if (done) { return void done({ code: ExportResultCode.SUCCESS, }); } } metric(name, value, span) { const config = { library: span.instrumentationLibrary.name, name, }; const relabel = this.config.relabel[config.name] || this.config.relabel[config.library]; if (!relabel) { return; } const labels = relabel(span.attributes, config); if (!labels) { return; } const metric = this.metrics[name] || (this.metrics[name] = this.newMetric(config, Object.keys(labels))); metric.counter.inc(labels); metric.histogram.observe(labels, value); metric.summary.observe(labels, value); } newMetric({ library, name, }, labelNames) { const metricName = this.config.prefix + snakeCase(name); const help = `${name} (${library})`; return { counter: new Counter({ name: `${metricName}_counter`, help, labelNames, }), summary: new Summary({ name: `${metricName}_summary`, help, labelNames, }), histogram: new Histogram({ name: `${metricName}_histogram`, help, labelNames, buckets: [0.1, 0.25, 0.5, 1, 2.5, 5, 7,], }), }; } } (function (MetricSpanExporter) { MetricSpanExporter.ttyPrint = isatty(process.stdout.fd) ? function identity(value) { return value; } : JSON.stringify.bind(JSON); function defaultTracer(value) { // eslint-disable-next-line no-console console.log(MetricSpanExporter.ttyPrint(value)); } MetricSpanExporter.defaultTracer = defaultTracer; function relabelAll(attributes) { return Object.entries(attributes).reduce(function reduceLabel(acc, [key, val,]) { acc[snakeCase(key)] = String(val); return acc; }, {}); } MetricSpanExporter.relabelAll = relabelAll; MetricSpanExporter.defaultRelabel = { "@opentelemetry/instrumentation-koa": relabelAll, "middleware - allowedMethods"() { return null; }, "middleware - "() { return null; }, "@opentelemetry/instrumentation-http"(attributes) { return { route: attributes["http.route"], status_code: attributes["http.status_code"], }; }, "@opentelemetry/instrumentation-graphql"() { return {}; }, "graphql.resolve"() { return null; }, }; })(MetricSpanExporter || (MetricSpanExporter = {}));