@azure/monitor-opentelemetry
Version:
Azure Monitor OpenTelemetry (Node.js)
159 lines • 8.12 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAzureMonitor = useAzureMonitor;
exports.shutdownAzureMonitor = shutdownAzureMonitor;
exports._getSdkInstance = _getSdkInstance;
const api_1 = require("@opentelemetry/api");
const api_logs_1 = require("@opentelemetry/api-logs");
const sdk_node_1 = require("@opentelemetry/sdk-node");
const config_js_1 = require("./shared/config.js");
const index_js_1 = require("./metrics/index.js");
const handler_js_1 = require("./traces/handler.js");
const index_js_2 = require("./logs/index.js");
const types_js_1 = require("./types.js");
const browserSdkLoader_js_1 = require("./browserSdkLoader/browserSdkLoader.js");
const utils_js_1 = require("./metrics/quickpulse/utils.js");
const statsbeat_js_1 = require("./utils/statsbeat.js");
const opentelemetryInstrumentationPatcher_js_1 = require("./utils/opentelemetryInstrumentationPatcher.js");
const azureSdkTracingBridge_js_1 = require("./utils/azureSdkTracingBridge.js");
const common_js_1 = require("./utils/common.js");
const index_js_3 = require("./shared/logging/index.js");
const types_js_2 = require("./types.js");
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
/**
* Semantic attribute for cloud resource ID, defined by \@opentelemetry/resource-detector-azure
* @internal
*/
const CLOUD_RESOURCE_ID_ATTRIBUTE = "cloud.resource_id";
process.env["AZURE_MONITOR_DISTRO_VERSION"] = types_js_1.AZURE_MONITOR_OPENTELEMETRY_VERSION;
let sdk;
let browserSdkLoader;
/**
* Check if auto-attach (autoinstrumentation) is enabled and warn about double instrumentation.
*/
function sendAttachWarning() {
if (process.env[types_js_2.AZURE_MONITOR_AUTO_ATTACH] === "true" && !(0, common_js_1.isFunctionApp)()) {
// TODO: When AKS attach is public, update this message with disablement instructions for AKS
const message = "Distro detected that automatic instrumentation may have occurred. Only use autoinstrumentation if you " +
"are not using manual instrumentation of OpenTelemetry in your code, such as with " +
"@azure/monitor-opentelemetry or @azure/monitor-opentelemetry-exporter. For App Service resources, disable " +
"autoinstrumentation in the Application Insights experience on your App Service resource or by setting " +
"the ApplicationInsightsAgent_EXTENSION_VERSION app setting to 'disabled'.";
// Surface in the log stream
console.warn(message);
// Also log via diagnostic logging
index_js_3.Logger.getInstance().warn(message);
}
}
/**
* Initialize Azure Monitor Distro
* @param options - Azure Monitor OpenTelemetry Options
*/
function useAzureMonitor(options) {
const config = new config_js_1.InternalConfig(options);
(0, opentelemetryInstrumentationPatcher_js_1.patchOpenTelemetryInstrumentationEnable)();
const statsbeatInstrumentations = {
// Instrumentations
azureSdk: config.instrumentationOptions?.azureSdk?.enabled,
mongoDb: config.instrumentationOptions?.mongoDb?.enabled,
mySql: config.instrumentationOptions?.mySql?.enabled,
postgreSql: config.instrumentationOptions?.postgreSql?.enabled,
redis: config.instrumentationOptions?.redis?.enabled,
bunyan: config.instrumentationOptions?.bunyan?.enabled,
winston: config.instrumentationOptions?.winston?.enabled,
};
// Check if the AKS resource detector successfully populated specific resource attributes
// (k8s.cluster.name or cloud.resource_id) beyond the basic cloud.platform/cloud.provider
// Derive from config.resource.attributes which already includes the AKS detector results
const resourceAttributes = config.resource.attributes;
const aksResourceDetected = semantic_conventions_1.SEMRESATTRS_K8S_CLUSTER_NAME in resourceAttributes ||
CLOUD_RESOURCE_ID_ATTRIBUTE in resourceAttributes;
const statsbeatFeatures = {
browserSdkLoader: config.browserSdkLoaderOptions.enabled,
aadHandling: !!config.azureMonitorExporterOptions?.credential,
diskRetry: !config.azureMonitorExporterOptions?.disableOfflineStorage,
customerSdkStats: process.env[types_js_1.APPLICATIONINSIGHTS_SDKSTATS_DISABLED]?.toLowerCase() === "true",
aksResourceDetectorPopulation: aksResourceDetected,
};
(0, statsbeat_js_1.getInstance)().setStatsbeatFeatures(statsbeatInstrumentations, statsbeatFeatures);
if (config.browserSdkLoaderOptions.enabled) {
browserSdkLoader = new browserSdkLoader_js_1.BrowserSdkLoader(config);
}
// Remove global providers in OpenTelemetry, these would be overridden if present
api_1.metrics.disable();
api_1.trace.disable();
api_logs_1.logs.disable();
// Clear the entire OpenTelemetry API global state to avoid version conflicts.
// The disable() calls above remove individual providers but leave the `version` field
// on the global object intact. If a different version of @opentelemetry/api was loaded
// first (e.g. by a VS Code extension host or another extension), the stale version
// causes registerGlobal() in sdk.start() to fail with "All API registration versions
// must match", resulting in Noop providers. Deleting the global object forces
// registerGlobal() to create a fresh one with the correct version.
const globalOpentelemetryApiKey = Symbol.for("opentelemetry.js.api.1");
Reflect.deleteProperty(globalThis, globalOpentelemetryApiKey);
// Create internal handlers
const metricHandler = new index_js_1.MetricHandler(config);
const traceHandler = new handler_js_1.TraceHandler(config, metricHandler);
const logHandler = new index_js_2.LogHandler(config, metricHandler);
const instrumentations = traceHandler
.getInstrumentations()
.concat(logHandler.getInstrumentations());
const resourceDetectorsList = (0, common_js_1.parseResourceDetectorsFromEnvVar)();
// Add extra SpanProcessors, and logRecordProcessors from user configuration
const spanProcessors = options?.spanProcessors || [];
const logRecordProcessors = options?.logRecordProcessors || [];
const customViews = options?.views || [];
// Prepare metric readers - always include Azure Monitor
const metricReaders = [
metricHandler.getMetricReader(),
...(options?.metricReaders || []),
];
const views = metricHandler.getViews().concat(customViews);
// Initialize OpenTelemetry SDK
const sdkConfig = {
autoDetectResources: true,
metricReaders: metricReaders,
views,
instrumentations: instrumentations,
logRecordProcessors: [
logHandler.getAzureLogRecordProcessor(),
...logRecordProcessors,
logHandler.getBatchLogRecordProcessor(),
],
resource: config.resource,
sampler: traceHandler.getSampler(),
spanProcessors: [
traceHandler.getAzureMonitorSpanProcessor(),
...spanProcessors,
traceHandler.getBatchSpanProcessor(),
],
resourceDetectors: resourceDetectorsList,
};
sdk = new sdk_node_1.NodeSDK(sdkConfig);
(0, utils_js_1.setSdkPrefix)();
sendAttachWarning();
sdk.start();
// Eagerly install the Azure SDK tracing bridge in case @azure/core-tracing
// was loaded before useAzureMonitor() (the RITM hook misses it otherwise).
(0, azureSdkTracingBridge_js_1.ensureAzureSdkTracingBridge)();
}
/**
* Shutdown Azure Monitor Open Telemetry Distro
* @see https://github.com/open-telemetry/opentelemetry-js/blob/0229434cb5a3179f63c021105f36270ae7897929/experimental/packages/opentelemetry-sdk-node/src/sdk.ts#L398
*/
function shutdownAzureMonitor() {
browserSdkLoader?.dispose();
return sdk?.shutdown();
}
/**
* Get the internal SDK instance for testing purposes
* @internal
*/
// eslint-disable-next-line no-underscore-dangle
function _getSdkInstance() {
return sdk;
}
//# sourceMappingURL=index.js.map