@azure/monitor-opentelemetry
Version:
Azure Monitor OpenTelemetry (Node.js)
94 lines • 3.59 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { trace } from "@opentelemetry/api";
import { Logger } from "../shared/logging/index.js";
import { GEN_AI_OPERATION_INVOKE_AGENT, GEN_AI_OPERATION_NAME, MAIN_AGENT_ONEND_MAPPING, MAIN_AGENT_ONSTART_MAPPING, } from "../utils/genaiAttributes.js";
/**
* Azure Monitor Span Processor.
* @internal
*/
export class AzureMonitorSpanProcessor {
_metricHandler;
constructor(metricHandler) {
this._metricHandler = metricHandler;
}
forceFlush() {
return Promise.resolve();
}
onStart(span, parentContext) {
try {
this._propagateMainAgentAttributesFromParent(span, parentContext);
}
catch (error) {
Logger.getInstance().warn("Error while propagating main agent attributes onStart", error);
}
this._metricHandler.markSpanAsProcessed(span);
}
onEnd(span) {
try {
this._applyInvokeAgentMainAgentFallback(span);
}
catch (error) {
Logger.getInstance().warn("Error while applying main agent fallback onEnd", error);
}
try {
this._metricHandler.recordSpan(span);
}
catch (error) {
Logger.getInstance().warn("Error while recording span", error);
}
}
_propagateMainAgentAttributesFromParent(span, parentContext) {
const parentSpan = trace.getSpan(parentContext);
if (!parentSpan) {
return;
}
// The Span returned by trace.getSpan may be a non-recording span or a
// foreign implementation that does not expose `attributes`. Only proceed
// when the parent looks like a ReadableSpan with readable attributes.
const parentAttributes = parentSpan.attributes;
if (!parentAttributes) {
return;
}
for (const { target, primary, fallback } of MAIN_AGENT_ONSTART_MAPPING) {
const primaryValue = parentAttributes[primary];
if (primaryValue !== undefined) {
span.setAttribute(target, primaryValue);
continue;
}
const fallbackValue = parentAttributes[fallback];
if (fallbackValue !== undefined) {
span.setAttribute(target, fallbackValue);
}
}
}
_applyInvokeAgentMainAgentFallback(span) {
const attributes = span.attributes;
if (!attributes || attributes[GEN_AI_OPERATION_NAME] !== GEN_AI_OPERATION_INVOKE_AGENT) {
return;
}
// Only check the four target attributes defined by the spec rather than
// scanning every key on the span.
for (const { target } of MAIN_AGENT_ONEND_MAPPING) {
if (attributes[target] !== undefined) {
return;
}
}
// The processor runs before BatchSpanProcessor, so mutating the span's
// attributes map here is observed by the exporter. Assigning into
// `attributes` directly avoids depending on the ReadableSpan also being a
// writable Span (and on `setAttribute` being a no-op once the span has
// ended).
const writableAttributes = attributes;
for (const { target, source } of MAIN_AGENT_ONEND_MAPPING) {
const value = attributes[source];
if (value !== undefined) {
writableAttributes[target] = value;
}
}
}
shutdown() {
return Promise.resolve();
}
}
//# sourceMappingURL=spanProcessor.js.map