@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
JavaScript
;
// 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