UNPKG

@azure/monitor-opentelemetry

Version:
149 lines 6.9 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { createAzureSdkInstrumentation } from "@azure/opentelemetry-instrumentation-azure-sdk"; import * as coreTracing from "@azure/core-tracing"; import { AzureMonitorTraceExporter, RateLimitedSampler, } from "@azure/monitor-opentelemetry-exporter"; import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"; import { HttpInstrumentation } from "@opentelemetry/instrumentation-http"; import { MongoDBInstrumentation } from "@opentelemetry/instrumentation-mongodb"; import { MySQLInstrumentation } from "@opentelemetry/instrumentation-mysql"; import { PgInstrumentation } from "@opentelemetry/instrumentation-pg"; import { RedisInstrumentation } from "@opentelemetry/instrumentation-redis"; import { ignoreOutgoingRequestHook } from "../utils/common.js"; import { AzureMonitorSpanProcessor } from "./spanProcessor.js"; import { AzureFunctionsHook } from "./azureFnHook.js"; import { ApplicationInsightsSampler } from "./sampler.js"; import { Logger } from "../shared/logging/index.js"; /** * Azure Monitor OpenTelemetry Trace Handler */ export class TraceHandler { _batchSpanProcessor; _azureSpanProcessor; _azureExporter; _instrumentations; _config; _metricHandler; _azureFunctionsHook; _sampler; /** * Initializes a new instance of the TraceHandler class. * @param _config - Configuration. * @param _metricHandler - MetricHandler. */ constructor(config, metricHandler) { this._config = config; this._metricHandler = metricHandler; this._instrumentations = []; // Check sampler precedence if (this._config.sampler) { this._sampler = this._config.sampler; } else if (this._config.tracesPerSecond && this._config.tracesPerSecond > 0) { // If tracesPerSecond is set to a positive number, use RateLimitedSampler this._sampler = new RateLimitedSampler(this._config.tracesPerSecond); } else { // Otherwise, use PercentageSampler with samplingRatio this._sampler = new ApplicationInsightsSampler(this._config.samplingRatio); } this._azureExporter = new AzureMonitorTraceExporter(this._config.azureMonitorExporterOptions); const bufferConfig = { maxExportBatchSize: 512, scheduledDelayMillis: 5000, exportTimeoutMillis: 30000, maxQueueSize: 2048, }; this._batchSpanProcessor = new BatchSpanProcessor(this._azureExporter, bufferConfig); this._azureSpanProcessor = new AzureMonitorSpanProcessor(this._metricHandler); this._azureFunctionsHook = new AzureFunctionsHook(); this._initializeInstrumentations(); } getSampler() { return this._sampler; } getBatchSpanProcessor() { return this._batchSpanProcessor; } getAzureMonitorSpanProcessor() { return this._azureSpanProcessor; } getInstrumentations() { return this._instrumentations; } /** * Shutdown handler */ async shutdown() { this._azureFunctionsHook.shutdown(); await this._batchSpanProcessor.shutdown(); await this._azureSpanProcessor.shutdown(); await this._azureExporter.shutdown(); } /** * Start auto collection of telemetry */ _initializeInstrumentations() { if (this._config.instrumentationOptions.http?.enabled) { const httpinstrumentationOptions = this._config.instrumentationOptions .http; const providedIgnoreOutgoingRequestHook = httpinstrumentationOptions.ignoreOutgoingRequestHook; const mergedIgnoreOutgoingRequestHook = (request) => { const result = ignoreOutgoingRequestHook(request); if (!result) { // Not internal call if (providedIgnoreOutgoingRequestHook) { // Provided hook in config return providedIgnoreOutgoingRequestHook(request); } } return result; }; httpinstrumentationOptions.ignoreOutgoingRequestHook = mergedIgnoreOutgoingRequestHook; this._instrumentations.push(new HttpInstrumentation(this._config.instrumentationOptions.http)); } if (this._config.instrumentationOptions.azureSdk?.enabled) { const azureSdkInstrumentation = createAzureSdkInstrumentation(this._config.instrumentationOptions.azureSdk); this._instrumentations.push(azureSdkInstrumentation); this._wireAzureSdkInstrumenter(azureSdkInstrumentation); } if (this._config.instrumentationOptions.mongoDb?.enabled) { this._instrumentations.push(new MongoDBInstrumentation(this._config.instrumentationOptions.mongoDb)); } if (this._config.instrumentationOptions.mySql?.enabled) { this._instrumentations.push(new MySQLInstrumentation(this._config.instrumentationOptions.mySql)); } if (this._config.instrumentationOptions.postgreSql?.enabled) { this._instrumentations.push(new PgInstrumentation(this._config.instrumentationOptions.postgreSql)); } if (this._config.instrumentationOptions.redis?.enabled || this._config.instrumentationOptions.redis4?.enabled) { this._instrumentations.push(new RedisInstrumentation(this._config.instrumentationOptions.redis)); } } /** * Wire the Azure SDK instrumenter into `@azure/core-tracing` directly. * * The Azure SDK instrumentation registers its instrumenter through an OpenTelemetry * module-patch hook that only fires via `require`/`import`-in-the-middle. In ESM hosts * where the OpenTelemetry loader cannot be registered up front (for example, Azure * Functions, which controls the Node.js start command), that hook never runs, so Azure * SDK dependency spans are missing. Because `@azure/core-tracing` resolves its * instrumenter lazily at span-creation time from shared module-local state, applying * the same patch directly here enables Azure SDK tracing regardless of module system. */ _wireAzureSdkInstrumenter(instrumentation) { try { const moduleDefinitions = instrumentation.getModuleDefinitions?.() ?? []; for (const moduleDefinition of moduleDefinitions) { if (moduleDefinition.name === "@azure/core-tracing" && moduleDefinition.patch) { moduleDefinition.patch(coreTracing); } } } catch (error) { Logger.getInstance().warn("Failed to enable Azure SDK tracing for ESM applications", error); } } } //# sourceMappingURL=handler.js.map