{"version":3,"sources":["../src/metrics.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Counter, Histogram, Meter, metrics } from '@opentelemetry/api';\nimport { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport { PathMetadata } from 'genkit/tracing';\n\nexport const METER_NAME = 'genkit';\nexport const METRIC_NAME_PREFIX = 'genkit';\nconst METRIC_DIMENSION_MAX_CHARS = 32;\n\nexport function internalMetricNamespaceWrap(...namespaces) {\n  return [METRIC_NAME_PREFIX, ...namespaces].join('/');\n}\n\ntype MetricCreateFn<T> = (meter: Meter) => T;\n\n/**\n * Wrapper for OpenTelemetry metrics.\n *\n * The OpenTelemetry {MeterProvider} can only be accessed through the metrics\n * API after the NodeSDK library has been initialized. To prevent race\n * conditions we defer the instantiation of the metric to when it is first\n * ticked.\n */\nclass Metric<T> {\n  readonly createFn: MetricCreateFn<T>;\n  readonly meterName: string;\n  metric?: T;\n\n  constructor(createFn: MetricCreateFn<T>, meterName: string = METER_NAME) {\n    this.meterName = meterName;\n    this.createFn = createFn;\n  }\n\n  get(): T {\n    if (!this.metric) {\n      this.metric = this.createFn(\n        metrics.getMeterProvider().getMeter(this.meterName)\n      );\n    }\n\n    return this.metric;\n  }\n}\n\n/**\n * Wrapper for an OpenTelemetry Counter.\n *\n * By using this wrapper, we defer initialization of the counter until it is\n * need, which ensures that the OpenTelemetry SDK has been initialized before\n * the metric has been defined.\n */\nexport class MetricCounter extends Metric<Counter> {\n  constructor(name: string, options: any) {\n    super((meter) => meter.createCounter(name, options));\n  }\n\n  add(val?: number, opts?: any) {\n    if (val) {\n      truncateDimensions(opts);\n      this.get().add(val, opts);\n    }\n  }\n}\n\n/**\n * Wrapper for an OpenTelemetry Histogram.\n *\n * By using this wrapper, we defer initialization of the counter until it is\n * need, which ensures that the OpenTelemetry SDK has been initialized before\n * the metric has been defined.\n */\nexport class MetricHistogram extends Metric<Histogram> {\n  constructor(name: string, options: any) {\n    super((meter) => meter.createHistogram(name, options));\n  }\n\n  record(val?: number, opts?: any) {\n    if (val) {\n      truncateDimensions(opts);\n      this.get().record(val, opts);\n    }\n  }\n}\n\n/**\n * Truncates all of the metric dimensions to avoid long, high-cardinality\n * dimensions being added to metrics.\n */\nfunction truncateDimensions(opts?: any) {\n  if (opts) {\n    Object.keys(opts).forEach((k) => {\n      // We don't want to truncate paths. They are known to be long but with\n      // relatively low cardinality, and are useful for downstream monitoring.\n      if (!k.startsWith('path') && typeof opts[k] == 'string') {\n        opts[k] = opts[k].substring(0, METRIC_DIMENSION_MAX_CHARS);\n      }\n    });\n  }\n}\n\nexport interface Telemetry {\n  tick(\n    span: ReadableSpan,\n    paths: Set<PathMetadata>,\n    logIO: boolean,\n    projectId?: string\n  ): void;\n}\n"],"mappings":"AAgBA,SAAoC,eAAe;AAI5C,MAAM,aAAa;AACnB,MAAM,qBAAqB;AAClC,MAAM,6BAA6B;AAE5B,SAAS,+BAA+B,YAAY;AACzD,SAAO,CAAC,oBAAoB,GAAG,UAAU,EAAE,KAAK,GAAG;AACrD;AAYA,MAAM,OAAU;AAAA,EACL;AAAA,EACA;AAAA,EACT;AAAA,EAEA,YAAY,UAA6B,YAAoB,YAAY;AACvE,SAAK,YAAY;AACjB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAS;AACP,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK;AAAA,QACjB,QAAQ,iBAAiB,EAAE,SAAS,KAAK,SAAS;AAAA,MACpD;AAAA,IACF;AAEA,WAAO,KAAK;AAAA,EACd;AACF;AASO,MAAM,sBAAsB,OAAgB;AAAA,EACjD,YAAY,MAAc,SAAc;AACtC,UAAM,CAAC,UAAU,MAAM,cAAc,MAAM,OAAO,CAAC;AAAA,EACrD;AAAA,EAEA,IAAI,KAAc,MAAY;AAC5B,QAAI,KAAK;AACP,yBAAmB,IAAI;AACvB,WAAK,IAAI,EAAE,IAAI,KAAK,IAAI;AAAA,IAC1B;AAAA,EACF;AACF;AASO,MAAM,wBAAwB,OAAkB;AAAA,EACrD,YAAY,MAAc,SAAc;AACtC,UAAM,CAAC,UAAU,MAAM,gBAAgB,MAAM,OAAO,CAAC;AAAA,EACvD;AAAA,EAEA,OAAO,KAAc,MAAY;AAC/B,QAAI,KAAK;AACP,yBAAmB,IAAI;AACvB,WAAK,IAAI,EAAE,OAAO,KAAK,IAAI;AAAA,IAC7B;AAAA,EACF;AACF;AAMA,SAAS,mBAAmB,MAAY;AACtC,MAAI,MAAM;AACR,WAAO,KAAK,IAAI,EAAE,QAAQ,CAAC,MAAM;AAG/B,UAAI,CAAC,EAAE,WAAW,MAAM,KAAK,OAAO,KAAK,CAAC,KAAK,UAAU;AACvD,aAAK,CAAC,IAAI,KAAK,CAAC,EAAE,UAAU,GAAG,0BAA0B;AAAA,MAC3D;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":[]}