@genkit-ai/google-cloud
Version:
Genkit AI framework plugin for Google Cloud Platform including Firestore trace/state store and deployment helpers for Cloud Functions for Firebase.
1 lines • 22.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/gcpOpenTelemetry.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 {\n MetricExporter,\n type ExporterOptions,\n} from '@google-cloud/opentelemetry-cloud-monitoring-exporter';\nimport { TraceExporter } from '@google-cloud/opentelemetry-cloud-trace-exporter';\nimport { GcpDetectorSync } from '@google-cloud/opentelemetry-resource-util';\nimport { SpanStatusCode, TraceFlags, type Span } from '@opentelemetry/api';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { type ExportResult } from '@opentelemetry/core';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport { PinoInstrumentation } from '@opentelemetry/instrumentation-pino';\nimport { WinstonInstrumentation } from '@opentelemetry/instrumentation-winston';\nimport { Resource } from '@opentelemetry/resources';\nimport {\n AggregationTemporality,\n DefaultAggregation,\n ExponentialHistogramAggregation,\n InMemoryMetricExporter,\n InstrumentType,\n PeriodicExportingMetricReader,\n type PushMetricExporter,\n type ResourceMetrics,\n} from '@opentelemetry/sdk-metrics';\nimport type { NodeSDKConfiguration } from '@opentelemetry/sdk-node';\nimport {\n BatchSpanProcessor,\n InMemorySpanExporter,\n type ReadableSpan,\n type SpanExporter,\n} from '@opentelemetry/sdk-trace-base';\nimport { GENKIT_VERSION } from 'genkit';\nimport { logger } from 'genkit/logging';\nimport { actionTelemetry } from './telemetry/action.js';\nimport { engagementTelemetry } from './telemetry/engagement.js';\nimport { featuresTelemetry } from './telemetry/feature.js';\nimport { generateTelemetry } from './telemetry/generate.js';\nimport { pathsTelemetry } from './telemetry/path.js';\nimport type { GcpTelemetryConfig } from './types.js';\nimport {\n metricsDenied,\n metricsDeniedHelpText,\n tracingDenied,\n tracingDeniedHelpText,\n} from './utils.js';\n\nlet metricExporter: PushMetricExporter;\nlet spanProcessor: BatchSpanProcessor;\nlet spanExporter: AdjustingTraceExporter;\n\n/**\n * Provides a {TelemetryConfig} for exporting OpenTelemetry data (Traces,\n * Metrics, and Logs) to the Google Cloud Operations Suite.\n */\nexport class GcpOpenTelemetry {\n private readonly config: GcpTelemetryConfig;\n private readonly resource: Resource;\n\n constructor(config: GcpTelemetryConfig) {\n this.config = config;\n this.resource = new Resource({ type: 'global' }).merge(\n new GcpDetectorSync().detect()\n );\n }\n\n /**\n * Log hook for writing trace and span metadata to log messages in the format\n * required by GCP.\n */\n private gcpTraceLogHook = (span: Span, record: any) => {\n const spanContext = span.spanContext();\n const isSampled = !!(spanContext.traceFlags & TraceFlags.SAMPLED);\n const projectId = this.config.projectId;\n\n record['logging.googleapis.com/trace'] ??=\n `projects/${projectId}/traces/${spanContext.traceId}`;\n record['logging.googleapis.com/trace_sampled'] ??= isSampled ? '1' : '0';\n record['logging.googleapis.com/spanId'] ??= spanContext.spanId;\n\n // Clear out the duplicate trace and span information in the log metadata.\n // These will be incorrect for logs written during span export time since\n // the logs are written after the span has fully executed. Those logs are\n // explicitly tied to the correct span in createCommonLogAttributes in\n // utils.ts.\n delete record['span_id'];\n delete record['trace_id'];\n delete record['trace_flags'];\n };\n\n async getConfig(): Promise<Partial<NodeSDKConfiguration>> {\n spanProcessor = new BatchSpanProcessor(await this.createSpanExporter());\n return {\n resource: this.resource,\n spanProcessor: spanProcessor,\n sampler: this.config.sampler,\n instrumentations: this.getInstrumentations(),\n metricReader: await this.createMetricReader(),\n };\n }\n\n private async createSpanExporter(): Promise<SpanExporter> {\n spanExporter = new AdjustingTraceExporter(\n this.shouldExportTraces()\n ? new TraceExporter({\n // provided projectId should take precedence over env vars, etc\n projectId: this.config.projectId,\n // creds for non-GCP environments, in lieu of using ADC.\n credentials: this.config.credentials,\n })\n : new InMemorySpanExporter(),\n this.config.exportInputAndOutput,\n this.config.projectId,\n getErrorHandler(\n (err) => {\n return tracingDenied(err);\n },\n await tracingDeniedHelpText()\n )\n );\n return spanExporter;\n }\n\n /**\n * Creates a {MetricReader} for pushing metrics out to GCP via OpenTelemetry.\n */\n private async createMetricReader(): Promise<PeriodicExportingMetricReader> {\n metricExporter = await this.buildMetricExporter();\n return new PeriodicExportingMetricReader({\n exportIntervalMillis: this.config.metricExportIntervalMillis,\n exportTimeoutMillis: this.config.metricExportTimeoutMillis,\n exporter: metricExporter,\n });\n }\n\n /** Gets all open telemetry instrumentations as configured by the plugin. */\n private getInstrumentations() {\n let instrumentations: Instrumentation[] = [];\n\n if (this.config.autoInstrumentation) {\n instrumentations = getNodeAutoInstrumentations(\n this.config.autoInstrumentationConfig\n );\n }\n\n return instrumentations\n .concat(this.getDefaultLoggingInstrumentations())\n .concat(this.config.instrumentations ?? []);\n }\n\n private shouldExportTraces(): boolean {\n return this.config.export && !this.config.disableTraces;\n }\n\n private shouldExportMetrics(): boolean {\n return this.config.export && !this.config.disableMetrics;\n }\n\n /** Always configure the Pino and Winston instrumentations */\n private getDefaultLoggingInstrumentations(): Instrumentation[] {\n return [\n new WinstonInstrumentation({ logHook: this.gcpTraceLogHook }),\n new PinoInstrumentation({ logHook: this.gcpTraceLogHook }),\n ];\n }\n\n private async buildMetricExporter(): Promise<PushMetricExporter> {\n const exporter: PushMetricExporter = this.shouldExportMetrics()\n ? new MetricExporterWrapper(\n {\n userAgent: {\n product: 'genkit',\n version: GENKIT_VERSION,\n },\n // provided projectId should take precedence over env vars, etc\n projectId: this.config.projectId,\n // creds for non-GCP environments, in lieu of using ADC.\n credentials: this.config.credentials,\n },\n getErrorHandler(\n (err) => {\n return metricsDenied(err);\n },\n await metricsDeniedHelpText()\n )\n )\n : new InMemoryMetricExporter(AggregationTemporality.DELTA);\n return exporter;\n }\n}\n\n/**\n * Rewrites the export method to include an error handler which logs\n * helpful information about how to set up metrics/telemetry in GCP.\n */\nclass MetricExporterWrapper extends MetricExporter {\n private promise = new Promise<void>((resolve) => resolve());\n\n constructor(\n options?: ExporterOptions,\n private errorHandler?: (error: Error) => void\n ) {\n super(options);\n }\n\n async export(\n metrics: ResourceMetrics,\n resultCallback: (result: ExportResult) => void\n ): Promise<void> {\n await this.promise;\n this.modifyStartTimes(metrics);\n this.promise = new Promise<void>((resolve) => {\n super.export(metrics, (result) => {\n try {\n if (this.errorHandler && result.error) {\n this.errorHandler(result.error);\n }\n resultCallback(result);\n } finally {\n resolve();\n }\n });\n });\n }\n\n selectAggregation(instrumentType: InstrumentType) {\n if (instrumentType === InstrumentType.HISTOGRAM) {\n return new ExponentialHistogramAggregation();\n }\n return new DefaultAggregation();\n }\n\n selectAggregationTemporality(instrumentType: InstrumentType) {\n return AggregationTemporality.DELTA;\n }\n\n /**\n * Modify the start times of each data point to ensure no\n * overlap with previous exports.\n *\n * Cloud metrics do not support delta metrics for custom metrics\n * and will convert any DELTA aggregations to CUMULATIVE ones on\n * export. There is implicit overlap in the start/end times that\n * the Metric reader is sending -- the end_time of the previous\n * export will become the start_time of the current export. The\n * overlap in times means that only one of those records will\n * persist and the other will be overwritten. This\n * method adds a thousandth of a second to ensure discrete export\n * timeframes.\n */\n private modifyStartTimes(metrics: ResourceMetrics): void {\n metrics.scopeMetrics.forEach((scopeMetric) => {\n scopeMetric.metrics.forEach((metric) => {\n metric.dataPoints.forEach((dataPoint) => {\n dataPoint.startTime[1] = dataPoint.startTime[1] + 1_000_000;\n });\n });\n });\n }\n\n async shutdown(): Promise<void> {\n return await this.forceFlush();\n }\n\n async forceFlush(): Promise<void> {\n await this.promise;\n }\n}\n\n/**\n * Adjusts spans before exporting to GCP. Redacts model input\n * and output content, and augments span attributes before sending to GCP.\n */\nclass AdjustingTraceExporter implements SpanExporter {\n constructor(\n private exporter: SpanExporter,\n private logInputAndOutput: boolean,\n private projectId?: string,\n private errorHandler?: (error: Error) => void\n ) {}\n\n export(\n spans: ReadableSpan[],\n resultCallback: (result: ExportResult) => void\n ): void {\n this.exporter?.export(this.adjust(spans), (result) => {\n if (this.errorHandler && result.error) {\n this.errorHandler(result.error);\n }\n resultCallback(result);\n });\n }\n\n shutdown(): Promise<void> {\n return this.exporter?.shutdown();\n }\n\n getExporter(): SpanExporter {\n return this.exporter;\n }\n\n forceFlush(): Promise<void> {\n if (this.exporter?.forceFlush) {\n return this.exporter.forceFlush();\n }\n return Promise.resolve();\n }\n\n private adjust(spans: ReadableSpan[]): ReadableSpan[] {\n return spans.map((span) => {\n this.tickTelemetry(span);\n\n span = this.redactInputOutput(span);\n span = this.markErrorSpanAsError(span);\n span = this.markFailedSpan(span);\n span = this.markGenkitFeature(span);\n span = this.markGenkitModel(span);\n span = this.normalizeLabels(span);\n return span;\n });\n }\n\n private tickTelemetry(span: ReadableSpan) {\n const attributes = span.attributes;\n if (!Object.keys(attributes).includes('genkit:type')) {\n return;\n }\n\n const type = attributes['genkit:type'] as string;\n const subtype = attributes['genkit:metadata:subtype'] as string;\n const isRoot = !!span.attributes['genkit:isRoot'];\n\n pathsTelemetry.tick(span, this.logInputAndOutput, this.projectId);\n if (isRoot) {\n // Report top level feature request and latency only for root spans\n // Log input to and output from to the feature\n featuresTelemetry.tick(span, this.logInputAndOutput, this.projectId);\n // Set root status explicitly\n span.attributes['genkit:rootState'] = span.attributes['genkit:state'];\n } else {\n if (type === 'action' && subtype === 'model') {\n // Report generate metrics () for all model actions\n generateTelemetry.tick(span, this.logInputAndOutput, this.projectId);\n }\n if (type === 'action' && subtype === 'tool') {\n // TODO: Report input and output for tool actions\n }\n if (\n type === 'action' ||\n type === 'flow' ||\n type == 'flowStep' ||\n type == 'util'\n ) {\n // Report request and latency metrics for all actions\n actionTelemetry.tick(span, this.logInputAndOutput, this.projectId);\n }\n }\n if (type === 'userEngagement') {\n // Report user acceptance and feedback metrics\n engagementTelemetry.tick(span, this.logInputAndOutput, this.projectId);\n }\n }\n\n private redactInputOutput(span: ReadableSpan): ReadableSpan {\n const hasInput = 'genkit:input' in span.attributes;\n const hasOutput = 'genkit:output' in span.attributes;\n\n return !hasInput && !hasOutput\n ? span\n : {\n ...span,\n spanContext: span.spanContext,\n attributes: {\n ...span.attributes,\n 'genkit:input': '<redacted>',\n 'genkit:output': '<redacted>',\n },\n };\n }\n\n // This is a workaround for GCP Trace to mark a span with a red\n // exclamation mark indicating that it is an error.\n private markErrorSpanAsError(span: ReadableSpan): ReadableSpan {\n return span.status.code !== SpanStatusCode.ERROR\n ? span\n : {\n ...span,\n spanContext: span.spanContext,\n attributes: {\n ...span.attributes,\n '/http/status_code': '599',\n },\n };\n }\n\n private normalizeLabels(span: ReadableSpan): ReadableSpan {\n const normalized = {} as Record<string, any>;\n for (const [key, value] of Object.entries(span.attributes)) {\n normalized[key.replace(/\\:/g, '/')] = value;\n }\n return {\n ...span,\n spanContext: span.spanContext,\n attributes: normalized,\n };\n }\n\n private markFailedSpan(span: ReadableSpan): ReadableSpan {\n if (span.attributes['genkit:isFailureSource']) {\n span.attributes['genkit:failedSpan'] = span.attributes['genkit:name'];\n span.attributes['genkit:failedPath'] = span.attributes['genkit:path'];\n }\n return span;\n }\n\n private markGenkitFeature(span: ReadableSpan): ReadableSpan {\n if (span.attributes['genkit:isRoot'] && !!span.attributes['genkit:name']) {\n span.attributes['genkit:feature'] = span.attributes['genkit:name'];\n }\n return span;\n }\n\n private markGenkitModel(span: ReadableSpan): ReadableSpan {\n if (\n span.attributes['genkit:metadata:subtype'] === 'model' &&\n !!span.attributes['genkit:name']\n ) {\n span.attributes['genkit:model'] = span.attributes['genkit:name'];\n }\n return span;\n }\n}\n\nfunction getErrorHandler(\n shouldLogFn: (err: Error) => boolean,\n helpText: string\n): (err: Error) => void {\n // only log the first time\n let instructionsLogged = false;\n\n return (err) => {\n // Use the defaultLogger so that logs don't get swallowed by the open\n // telemetry exporter\n const defaultLogger = logger.defaultLogger;\n if (err && shouldLogFn(err)) {\n if (!instructionsLogged) {\n instructionsLogged = true;\n defaultLogger.error(\n `Unable to send telemetry to Google Cloud: ${err.message}\\n\\n${helpText}\\n`\n );\n }\n } else if (err) {\n defaultLogger.error(`Unable to send telemetry to Google Cloud: ${err}`);\n }\n };\n}\n\n/** @hidden */\nexport function __getMetricExporterForTesting(): InMemoryMetricExporter {\n return metricExporter as InMemoryMetricExporter;\n}\n\n/** @hidden */\nexport function __getSpanExporterForTesting(): InMemorySpanExporter {\n return spanExporter.getExporter() as InMemorySpanExporter;\n}\n\n/** @hidden */\nexport function __forceFlushSpansForTesting() {\n spanProcessor.forceFlush();\n}\n"],"mappings":"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","names":[]}