{"version":3,"sources":["../../src/telemetry/path.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 { ValueType } from '@opentelemetry/api';\nimport { hrTimeDuration, hrTimeToMilliseconds } from '@opentelemetry/core';\nimport { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport { GENKIT_VERSION } from 'genkit';\nimport { logger } from 'genkit/logging';\nimport { PathMetadata, toDisplayPath } from 'genkit/tracing';\nimport {\n  MetricCounter,\n  MetricHistogram,\n  Telemetry,\n  internalMetricNamespaceWrap,\n} from '../metrics.js';\nimport {\n  createCommonLogAttributes,\n  extractErrorMessage,\n  extractErrorName,\n  extractErrorStack,\n  truncatePath,\n} from '../utils.js';\n\nclass PathsTelemetry implements Telemetry {\n  /**\n   * Wraps the declared metrics in a Genkit-specific, internal namespace.\n   */\n  private _N = internalMetricNamespaceWrap.bind(null, 'feature');\n\n  private pathCounter = new MetricCounter(this._N('path/requests'), {\n    description: 'Tracks unique flow paths per flow.',\n    valueType: ValueType.INT,\n  });\n\n  private pathLatencies = new MetricHistogram(this._N('path/latency'), {\n    description: 'Latencies per flow path.',\n    ValueType: ValueType.DOUBLE,\n    unit: 'ms',\n  });\n\n  tick(\n    span: ReadableSpan,\n    paths: Set<PathMetadata>,\n    logInputAndOutput: boolean,\n    projectId?: string\n  ): void {\n    const attributes = span.attributes;\n    const name = attributes['genkit:name'] as string;\n    const path = attributes['genkit:path'] as string;\n    const sessionId = attributes['genkit:sessionId'] as string;\n    const threadName = attributes['genkit:threadName'] as string;\n\n    const latencyMs = hrTimeToMilliseconds(\n      hrTimeDuration(span.startTime, span.endTime)\n    );\n    const state = attributes['genkit:state'] as string;\n\n    if (state === 'success') {\n      this.writePathSuccess(\n        span,\n        paths!,\n        name,\n        path,\n        latencyMs,\n        projectId,\n        sessionId,\n        threadName\n      );\n      return;\n    }\n\n    if (state === 'error') {\n      const errorName = extractErrorName(span.events) || '<unknown>';\n      const errorMessage = extractErrorMessage(span.events) || '<unknown>';\n      const errorStack = extractErrorStack(span.events) || '';\n\n      this.writePathFailure(\n        span,\n        paths!,\n        name,\n        path,\n        latencyMs,\n        errorName,\n        projectId,\n        sessionId,\n        threadName\n      );\n      this.recordError(\n        span,\n        path,\n        errorName,\n        errorMessage,\n        errorStack,\n        projectId,\n        sessionId,\n        threadName\n      );\n      return;\n    }\n\n    logger.warn(`Unknown state; ${state}`);\n  }\n\n  private recordError(\n    span: ReadableSpan,\n    path: string,\n    errorName: string,\n    errorMessage: string,\n    errorStack: string,\n    projectId?: string,\n    sessionId?: string,\n    threadName?: string\n  ) {\n    const displayPath = truncatePath(toDisplayPath(path));\n    logger.logStructuredError(`Error[${displayPath}, ${errorName}]`, {\n      ...createCommonLogAttributes(span, projectId),\n      path: displayPath,\n      qualifiedPath: path,\n      name: errorName,\n      message: errorMessage,\n      stack: errorStack,\n      source: 'ts',\n      sourceVersion: GENKIT_VERSION,\n      sessionId,\n      threadName,\n    });\n  }\n\n  private writePathSuccess(\n    span: ReadableSpan,\n    paths: Set<PathMetadata>,\n    featureName: string,\n    path: string,\n    latencyMs: number,\n    projectId?: string,\n    sessionId?: string,\n    threadName?: string\n  ) {\n    this.writePathMetrics(\n      span,\n      path,\n      paths,\n      featureName,\n      latencyMs,\n      undefined,\n      projectId,\n      sessionId,\n      threadName\n    );\n  }\n\n  private writePathFailure(\n    span: ReadableSpan,\n    paths: Set<PathMetadata>,\n    featureName: string,\n    path: string,\n    latencyMs: number,\n    errorName: string,\n    projectId?: string,\n    sessionId?: string,\n    threadName?: string\n  ) {\n    this.writePathMetrics(\n      span,\n      path,\n      paths,\n      featureName,\n      latencyMs,\n      errorName,\n      projectId,\n      sessionId,\n      threadName\n    );\n  }\n\n  /** Writes all path-level metrics stored in the current flow execution. */\n  private writePathMetrics(\n    span: ReadableSpan,\n    rootPath: string,\n    paths: Set<PathMetadata>,\n    featureName: string,\n    latencyMs: number,\n    err?: string,\n    projectId?: string,\n    sessionId?: string,\n    threadName?: string\n  ) {\n    const flowPaths = Array.from(paths).filter((meta) =>\n      meta.path.includes(featureName)\n    );\n\n    if (flowPaths) {\n      logger.logStructured(`Paths[${featureName}]`, {\n        ...createCommonLogAttributes(span, projectId),\n        flowName: featureName,\n        sessionId,\n        threadName,\n        paths: flowPaths.map((p) => truncatePath(toDisplayPath(p.path))),\n      });\n\n      flowPaths.forEach((p) => this.writePathMetric(featureName, p));\n      // If we're writing a failure, but none of the stored paths have failed,\n      // this means the root flow threw the error.\n      if (err && !flowPaths.some((p) => p.status === 'failure')) {\n        this.writePathMetric(featureName, {\n          status: 'failure',\n          path: rootPath,\n          error: err,\n          latency: latencyMs,\n        });\n      }\n    }\n  }\n\n  /** Writes metrics for a single PathMetadata */\n  private writePathMetric(featureName: string, meta: PathMetadata) {\n    const pathDimensions = {\n      featureName: featureName,\n      status: meta.status,\n      error: meta.error,\n      path: meta.path,\n      source: 'ts',\n      sourceVersion: GENKIT_VERSION,\n    };\n    this.pathCounter.add(1, pathDimensions);\n    this.pathLatencies.record(meta.latency, pathDimensions);\n  }\n}\n\nconst pathsTelemetry = new PathsTelemetry();\nexport { pathsTelemetry };\n"],"mappings":"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","names":[]}