UNPKG

@aws/aws-distro-opentelemetry-node-autoinstrumentation

Version:

This package provides Amazon Web Services distribution of the OpenTelemetry Node Instrumentation, which allows for auto-instrumentation of NodeJS applications.

122 lines 6.01 kB
"use strict"; // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 Object.defineProperty(exports, "__esModule", { value: true }); exports.VercelAIInstrumentation = exports.INSTRUMENTATION_SHORT_NAME = exports.INSTRUMENTATION_NAME = void 0; /* eslint-disable @typescript-eslint/no-explicit-any */ const util_1 = require("util"); const instrumentation_1 = require("@opentelemetry/instrumentation"); const version_1 = require("../../version"); const span_processor_1 = require("./span-processor"); const utils_1 = require("../../utils"); exports.INSTRUMENTATION_NAME = '@aws/aws-distro-opentelemetry-instrumentation-vercel-ai'; exports.INSTRUMENTATION_SHORT_NAME = 'aws_vercel_ai'; const SUPPORTED_VERSIONS = ['>=3.3.0 <7.0.0']; class VercelAIInstrumentation extends instrumentation_1.InstrumentationBase { constructor(config = {}) { super(exports.INSTRUMENTATION_NAME, version_1.LIB_VERSION, config); this._spanProcessorRegistered = false; } setConfig(config = {}) { super.setConfig(Object.assign(Object.assign({}, config), { captureMessageContent: !!config.captureMessageContent })); } enable() { if ((0, utils_1.isInstrumentationDisabled)(exports.INSTRUMENTATION_SHORT_NAME)) { this._diag.debug(`${exports.INSTRUMENTATION_NAME} is disabled`); return; } if (!(0, utils_1.isAgenticInstrumentationOptIn)()) { const conflict = (0, utils_1.detectConflictingInstrumentation)(exports.INSTRUMENTATION_SHORT_NAME); if (conflict) { this._diag.info(`Skipping ${exports.INSTRUMENTATION_NAME}: third-party '${conflict}' detected. ` + 'Set AWS_AGENTIC_INSTRUMENTATION_OPT_IN=true to override.'); return; } } super.enable(); } setTracerProvider(provider) { var _a, _b, _c; if (!this._spanProcessorRegistered) { const delegate = (_b = (_a = provider.getDelegate) === null || _a === void 0 ? void 0 : _a.call(provider)) !== null && _b !== void 0 ? _b : provider; const processors = (_c = delegate._activeSpanProcessor) === null || _c === void 0 ? void 0 : _c._spanProcessors; if (!Array.isArray(processors)) { this._diag.warn('Failed to register VercelAISpanProcessor'); } else { processors.unshift(new span_processor_1.VercelAISpanProcessor()); this._spanProcessorRegistered = true; this._diag.debug('Registered VercelAISpanProcessor'); } } super.setTracerProvider(provider); } init() { return [ new instrumentation_1.InstrumentationNodeModuleDefinition('ai', SUPPORTED_VERSIONS, (moduleExports) => this._enableTelemetryByDefaultWrapper(moduleExports), (_moduleExports) => this._enableTelemetryByDefaultUnwrap()), ]; } _enableTelemetryByDefaultWrapper(moduleExports) { // The exports we are trying to patch in CJS have non-configurable properties, // so we must copy them into a plain object. However in ESM exports are wrappable directly. const isESM = util_1.types.isProxy(moduleExports); const exports = isESM ? moduleExports : Object.assign({}, moduleExports); for (const fnName of VercelAIInstrumentation.FUNCTIONS_TO_PATCH) { if (typeof exports[fnName] === 'function') { this._wrap(exports, fnName, (original) => { const instrumentation = this; return function (options) { options = instrumentation._autoInjectTelemetryEnabled(options); return original.call(this, options); }; }); this._diag.debug(`Patched ai.${fnName}`); } } this._patchedExports = exports; return exports; } _enableTelemetryByDefaultUnwrap() { if (this._patchedExports) { for (const fnName of VercelAIInstrumentation.FUNCTIONS_TO_PATCH) { if (typeof this._patchedExports[fnName] === 'function') { this._unwrap(this._patchedExports, fnName); } } this._patchedExports = undefined; } } // automatically enables SDK telemetry to always be on // see: https://github.com/vercel/ai/blob/6a06fde/packages/ai/core/telemetry/get-tracer.ts#L4-L13 _autoInjectTelemetryEnabled(options) { var _a; if (!options || typeof options !== 'object') { return options; } const existing = options.experimental_telemetry; if ((existing === null || existing === void 0 ? void 0 : existing.isEnabled) === false) { return options; } const captureContent = (_a = this.getConfig().captureMessageContent) !== null && _a !== void 0 ? _a : false; options.experimental_telemetry = Object.assign({ isEnabled: true, recordInputs: captureContent, recordOutputs: captureContent }, existing); return options; } } // Vercel AI SDK provides native OTel integration but uses its own // semantic conventions rather than the standard OTel GenAI conventions. // See: https://ai-sdk.dev/docs/ai-sdk-core/telemetry#semantic-conventions // // This instrumentation does two things: // // - Patches their code always enable telemetry generation. By default the Vercel AI SDK has // telemetry disabled and requires users to explicitly opt in by setting // experimental_telemetry.isEnabled = true on every call. // - Registers a VercelAISpanProcessor that translates the VerceL span attributes into OTel semantic conventions. VercelAIInstrumentation.FUNCTIONS_TO_PATCH = [ 'generateText', 'streamText', 'generateObject', 'streamObject', ]; exports.VercelAIInstrumentation = VercelAIInstrumentation; //# sourceMappingURL=instrumentation.js.map