UNPKG

@genkit-ai/core

Version:

Genkit AI framework core libraries.

1 lines 15.2 kB
{"version":3,"sources":["../../src/tracing/instrumentation.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 ROOT_CONTEXT,\n SpanOptions,\n SpanStatusCode,\n trace,\n type Span as ApiSpan,\n type Link,\n} from '@opentelemetry/api';\nimport { performance } from 'node:perf_hooks';\nimport { getAsyncContext } from '../async-context.js';\nimport type { HasRegistry, Registry } from '../registry.js';\nimport { ensureBasicTelemetryInstrumentation } from '../tracing.js';\nimport type { PathMetadata, SpanMetadata, TraceMetadata } from './types.js';\n\nexport const spanMetadataAlsKey = 'core.tracing.instrumentation.span';\n\nexport const ATTR_PREFIX = 'genkit';\n/** @hidden */\nexport const SPAN_TYPE_ATTR = ATTR_PREFIX + ':type';\nconst TRACER_NAME = 'genkit-tracer';\nconst TRACER_VERSION = 'v1';\n\ntype SpanContext = {\n metadata: SpanMetadata;\n labels?: Record<string, string>;\n spanId?: string;\n} & TraceMetadata;\n\ninterface RunInNewSpanOpts {\n metadata: SpanMetadata;\n labels?: Record<string, string>;\n links?: Link[];\n}\n\ntype RunInNewSpanFn<T> = (\n metadata: SpanMetadata,\n otSpan: ApiSpan,\n isRoot: boolean\n) => Promise<T>;\n\n/**\n * Runs the provided function in a new span.\n * @deprecated\n * @hidden\n */\nexport async function runInNewSpan<T>(\n registry: Registry | HasRegistry,\n opts: RunInNewSpanOpts,\n fn: RunInNewSpanFn<T>\n): Promise<T>;\n\n/**\n * Runs the provided function in a new span.\n * @hidden\n */\nexport async function runInNewSpan<T>(\n opts: RunInNewSpanOpts,\n fn: RunInNewSpanFn<T>\n): Promise<T>;\n\n/**\n * Runs the provided function in a new span.\n * @hidden\n */\nexport async function runInNewSpan<T>(\n registryOrOprs: Registry | HasRegistry | RunInNewSpanOpts,\n optsOrFn: RunInNewSpanOpts | RunInNewSpanFn<T>,\n fnMaybe?: RunInNewSpanFn<T>\n): Promise<T> {\n let opts: RunInNewSpanOpts;\n let fn: RunInNewSpanFn<T>;\n if (arguments.length === 3) {\n opts = optsOrFn as RunInNewSpanOpts;\n fn = fnMaybe as RunInNewSpanFn<T>;\n } else {\n opts = registryOrOprs as RunInNewSpanOpts;\n fn = optsOrFn as RunInNewSpanFn<T>;\n }\n await ensureBasicTelemetryInstrumentation();\n const tracer = trace.getTracer(TRACER_NAME, TRACER_VERSION);\n const parentStep =\n getAsyncContext().getStore<SpanContext>(spanMetadataAlsKey);\n const isInRoot = parentStep?.metadata?.isRoot === true;\n if (!parentStep) opts.metadata.isRoot ||= true;\n\n const spanOptions: SpanOptions = {\n links: opts.links,\n attributes: opts.labels,\n };\n if (!isDisableRootSpanDetection()) {\n spanOptions.root = opts.metadata.isRoot;\n }\n\n return await tracer.startActiveSpan(\n opts.metadata.name,\n spanOptions,\n async (otSpan) => {\n const spanContext = {\n ...parentStep,\n metadata: opts.metadata,\n labels: opts.labels,\n } as SpanContext;\n try {\n opts.metadata.path = buildPath(\n opts.metadata.name,\n parentStep?.metadata?.path || '',\n opts.labels\n );\n\n const isGenkitSpan = !!opts.labels?.[SPAN_TYPE_ATTR];\n if (isGenkitSpan && parentStep) {\n const parentIsGenkit = !!parentStep.labels?.[SPAN_TYPE_ATTR];\n if (!parentIsGenkit && parentStep.spanId) {\n otSpan.setAttribute(\n ATTR_PREFIX + ':lastKnownParentSpanId',\n parentStep.spanId\n );\n }\n }\n\n // Store spanId in context for Genkit spans so nested spans can reference it\n if (isGenkitSpan) {\n spanContext.spanId = otSpan.spanContext().spanId;\n }\n\n const output = await getAsyncContext().run(\n spanMetadataAlsKey,\n spanContext,\n () => fn(opts.metadata, otSpan, isInRoot)\n );\n if (opts.metadata.state !== 'error') {\n opts.metadata.state = 'success';\n }\n\n recordPath(opts.metadata, spanContext);\n return output;\n } catch (e) {\n recordPath(opts.metadata, spanContext, e);\n opts.metadata.state = 'error';\n otSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: getErrorMessage(e),\n });\n if (e instanceof Error) {\n otSpan.recordException(e);\n }\n\n // Mark the first failing span as the source of failure. Prevent parent\n // spans that catch re-thrown exceptions from also claiming to be the\n // source.\n if (typeof e === 'object') {\n if (!(e as any).ignoreFailedSpan) {\n opts.metadata.isFailureSource = true;\n }\n (e as any).ignoreFailedSpan = true;\n }\n\n throw e;\n } finally {\n otSpan.setAttributes(metadataToAttributes(opts.metadata));\n otSpan.end();\n }\n }\n );\n}\n\n/**\n * Creates a new child span and attaches it to a previously created trace. This\n * is useful, for example, for adding deferred user engagement metadata.\n *\n * @hidden\n */\nexport async function appendSpan(\n traceId: string,\n parentSpanId: string,\n metadata: SpanMetadata,\n labels?: Record<string, string>\n) {\n await ensureBasicTelemetryInstrumentation();\n\n const tracer = trace.getTracer(TRACER_NAME, TRACER_VERSION);\n\n const spanContext = trace.setSpanContext(ROOT_CONTEXT, {\n traceId: traceId,\n traceFlags: 1, // sampled\n spanId: parentSpanId,\n });\n\n // TODO(abrook): add explicit start time to align with parent\n const span = tracer.startSpan(metadata.name, {}, spanContext);\n span.setAttributes(metadataToAttributes(metadata));\n if (labels) {\n span.setAttributes(labels);\n }\n span.end();\n}\n\nfunction getErrorMessage(e: any): string {\n if (e instanceof Error) {\n return e.message;\n }\n return `${e}`;\n}\n\nfunction metadataToAttributes(metadata: SpanMetadata): Record<string, string> {\n const out = {} as Record<string, string>;\n Object.keys(metadata).forEach((key) => {\n if (\n key === 'metadata' &&\n typeof metadata[key] === 'object' &&\n metadata.metadata\n ) {\n Object.entries(metadata.metadata).forEach(([metaKey, value]) => {\n out[ATTR_PREFIX + ':metadata:' + metaKey] = value;\n });\n } else if (key === 'input' || typeof metadata[key] === 'object') {\n out[ATTR_PREFIX + ':' + key] = JSON.stringify(metadata[key]);\n } else {\n out[ATTR_PREFIX + ':' + key] = metadata[key];\n }\n });\n return out;\n}\n\n/**\n * Sets provided attribute value in the current span.\n *\n * @hidden\n */\nexport function setCustomMetadataAttribute(key: string, value: string) {\n const currentStep = getCurrentSpan();\n if (!currentStep) {\n return;\n }\n if (!currentStep.metadata) {\n currentStep.metadata = {};\n }\n currentStep.metadata[key] = value;\n}\n\n/**\n * Sets provided attribute values in the current span.\n *\n * @hidden\n */\nexport function setCustomMetadataAttributes(values: Record<string, string>) {\n const currentStep = getCurrentSpan();\n if (!currentStep) {\n return;\n }\n if (!currentStep.metadata) {\n currentStep.metadata = {};\n }\n for (const [key, value] of Object.entries(values)) {\n currentStep.metadata[key] = value;\n }\n}\n\n/**\n * Converts a fully annotated path to a friendly display version for logs\n *\n * @hidden\n */\nexport function toDisplayPath(path: string): string {\n const pathPartRegex = /\\{([^\\,}]+),[^\\}]+\\}/g;\n return Array.from(path.matchAll(pathPartRegex), (m) => m[1]).join(' > ');\n}\n\nfunction getCurrentSpan(): SpanMetadata {\n const step = getAsyncContext().getStore<SpanContext>(spanMetadataAlsKey);\n if (!step) {\n throw new Error('running outside step context');\n }\n return step.metadata;\n}\n\nfunction buildPath(\n name: string,\n parentPath: string,\n labels?: Record<string, string>\n) {\n const stepType =\n labels && labels['genkit:type']\n ? `,t:${labels['genkit:metadata:subtype'] === 'flow' ? 'flow' : labels['genkit:type']}`\n : '';\n return parentPath + `/{${name}${stepType}}`;\n}\n\nfunction recordPath(\n spanMeta: SpanMetadata,\n spanContext: SpanContext,\n err?: any\n) {\n const path = spanMeta.path || '';\n const decoratedPath = decoratePathWithSubtype(spanMeta);\n // Only add the path if a child has not already been added. In the event that\n // an error is rethrown, we don't want to add each step in the unwind.\n const paths = Array.from(spanContext?.paths || new Set<PathMetadata>());\n const status = err ? 'failure' : 'success';\n if (!paths.some((p) => p.path.startsWith(path) && p.status === status)) {\n const now = performance.now();\n const start = spanContext?.timestamp || now;\n spanContext?.paths?.add({\n path: decoratedPath,\n error: err?.name,\n latency: now - start,\n status,\n });\n }\n spanMeta.path = decoratedPath;\n}\n\nfunction decoratePathWithSubtype(metadata: SpanMetadata): string {\n if (!metadata.path) {\n return '';\n }\n\n const pathComponents = metadata.path.split('}/{');\n\n if (pathComponents.length == 1) {\n return metadata.path;\n }\n\n const stepSubtype =\n metadata.metadata && metadata.metadata['subtype']\n ? `,s:${metadata.metadata['subtype']}`\n : '';\n const root = `${pathComponents.slice(0, -1).join('}/{')}}/`;\n const decoratedStep = `{${pathComponents.at(-1)?.slice(0, -1)}${stepSubtype}}`;\n return root + decoratedStep;\n}\n\nconst rootSpanDetectionKey = '__genkit_disableRootSpanDetection';\n\nfunction isDisableRootSpanDetection(): boolean {\n return global[rootSpanDetectionKey] === true;\n}\n\n/**\n * Disables Genkit's custom root span detection and leaves default Otel root span.\n *\n * This function attempts to control Genkit's internal OTel instrumentation behaviour,\n * since internal implementation details are subject to change at any time consider\n * this function \"unstable\" and subject to breaking changes as well.\n *\n * @hidden\n */\nexport function disableOTelRootSpanDetection() {\n global[rootSpanDetectionKey] = true;\n}\n"],"mappings":"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","names":[]}