UNPKG

applicationinsights

Version:

Microsoft Application Insights module for Node.js

264 lines 12.7 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentLoader = void 0; const identity_1 = require("@azure/identity"); const util_1 = require("../shared/util"); const consoleWriter_1 = require("./diagnostics/writers/consoleWriter"); const diagnosticLogger_1 = require("./diagnostics/diagnosticLogger"); const statusLogger_1 = require("./diagnostics/statusLogger"); const types_1 = require("./types"); const main_1 = require("../main"); const forceStart = process.env.APPLICATIONINSIGHTS_FORCE_START === "true"; // Azure Connection String const ENV_connectionString = "APPLICATIONINSIGHTS_CONNECTION_STRING"; const ENV_AZURE_PREFIX = "APPSETTING_"; // Azure adds this prefix to all environment variables const ENV_IKEY = "APPINSIGHTS_INSTRUMENTATIONKEY"; // This key is provided in the readme const LEGACY_ENV_IKEY = "APPINSIGHTS_INSTRUMENTATION_KEY"; const LINUX_USER_APPLICATION_INSIGHTS_PATH = "/node_modules/applicationinsights/out/applicationinsights.js"; class AgentLoader { constructor() { // Open Telemetry and AAD packages unsusable in older versions of Node.js runtime // https://github.com/open-telemetry/opentelemetry-js?tab=readme-ov-file#supported-runtimes if (types_1.NODE_JS_RUNTIME_MAJOR_VERSION < 14) { this._canLoad = false; } else { this._canLoad = true; this._aadCredential = this._getAuthenticationCredential(); // Default options this._options = { azureMonitorExporterOptions: { disableOfflineStorage: false, }, enableAutoCollectExceptions: true, enableAutoCollectPerformance: true, samplingRatio: 1, enableLiveMetrics: true, instrumentationOptions: { azureSdk: { enabled: true }, http: { enabled: true }, mongoDb: { enabled: true }, mySql: { enabled: true }, postgreSql: { enabled: true }, redis4: { enabled: true }, redis: { enabled: true }, } }; const connectionString = process.env[ENV_connectionString]; if (connectionString) { this._instrumentationKey = this._getInstrumentationKey(connectionString); } else { const instrumentationKey = process.env[ENV_IKEY] || process.env[ENV_AZURE_PREFIX + ENV_IKEY] || process.env[LEGACY_ENV_IKEY] || process.env[ENV_AZURE_PREFIX + LEGACY_ENV_IKEY]; this._instrumentationKey = instrumentationKey || "unknown"; } // Default diagnostic using console this._diagnosticLogger = new diagnosticLogger_1.DiagnosticLogger(this._instrumentationKey, new consoleWriter_1.ConsoleWriter()); this._statusLogger = new statusLogger_1.StatusLogger(this._instrumentationKey, new consoleWriter_1.ConsoleWriter()); this._isWindows = process.platform === 'win32'; this._isLinux = process.platform === 'linux'; } } _getInstrumentationKey(connectionString) { if (connectionString) { const kvPairs = connectionString.split(";"); for (let i = 0; i < kvPairs.length; i++) { const kvParts = kvPairs[i].split("="); if (kvParts.length === 2 && kvParts[0].toLowerCase() === "instrumentationkey") { return kvParts[1]; } } } return ""; } // Exposed so ETW logger could be provider in IPA code setLogger(logger) { this._diagnosticLogger = logger; } initialize() { if (!this._canLoad) { const msg = `Cannot load Azure Monitor Application Insights Distro because of unsupported Node.js runtime, currently running in version ${types_1.NODE_JS_RUNTIME_MAJOR_VERSION}`; console.log(msg); return; } if (this._validate()) { try { // Set environment variable to auto attach so the distro is aware of the attach state process.env[types_1.AZURE_MONITOR_AUTO_ATTACH] = "true"; // Initialize Distro this._options.azureMonitorExporterOptions.credential = this._aadCredential; (0, main_1.useAzureMonitor)(this._options); // Agent successfully initialized const diagnosticLog = { message: "Azure Monitor Application Insights Distro was started succesfully.", messageId: types_1.DiagnosticMessageId.attachSuccessful }; this._diagnosticLogger.logMessage(diagnosticLog); this._statusLogger.logStatus({ AgentInitializedSuccessfully: true }); } catch (error) { const msg = `Error initializaing Azure Monitor Application Insights Distro.${util_1.Util.getInstance().dumpObj(error)}`; const diagnosticLog = { message: msg, messageId: types_1.DiagnosticMessageId.unknownError }; this._diagnosticLogger.logMessage(diagnosticLog); this._statusLogger.logStatus({ AgentInitializedSuccessfully: false, Reason: msg }); } } } _validate() { try { if (!forceStart && this._sdkAlreadyExists()) { this._statusLogger.logStatus({ AgentInitializedSuccessfully: false, SDKPresent: true, Reason: "Azure Monitor Application Insights Distro already available." }); return false; } if (this._instrumentationKey === "unknown") { const diagnosticLog = { message: "Azure Monitor Application Insights Distro wanted to be started, but no Connection String was provided", messageId: types_1.DiagnosticMessageId.missingIkey }; this._diagnosticLogger.logMessage(diagnosticLog); this._statusLogger.logStatus({ AgentInitializedSuccessfully: false, Reason: diagnosticLog.message }); return false; } return true; } catch (err) { const msg = `Failed to validate Azure Monitor Application Insights Distro initialization.${util_1.Util.getInstance().dumpObj(err)}`; console.log(msg); if (this._diagnosticLogger) { const diagnosticLog = { message: msg, messageId: types_1.DiagnosticMessageId.unknownError }; this._diagnosticLogger.logMessage(diagnosticLog); } if (this._statusLogger) { this._statusLogger.logStatus({ AgentInitializedSuccessfully: false, Reason: msg }); } } } _getAuthenticationCredential() { let credential = undefined; // Try to add AAD Token Credential try { const authenticationString = process.env["APPLICATIONINSIGHTS_AUTHENTICATION_STRING"]; if (authenticationString) { const kvPairs = authenticationString.split(";"); const result = kvPairs.reduce((fields, kv) => { const kvParts = kv.split("="); if (kvParts.length === 2) { // only save fields with valid formats const key = kvParts[0].toLowerCase(); const value = kvParts[1]; fields[key] = value; } return fields; }, {}); if (result["authorization"] && result["authorization"] === "AAD") { const clientId = result["clientid"]; if (clientId) { console.log('AppInsightsAgent: ClientId found, trying to authenticate using Managed Identity.'); credential = new identity_1.ManagedIdentityCredential(clientId); } else { console.log('AppInsightsAgent: Trying to authenticate using System assigned Managed Identity.'); credential = new identity_1.ManagedIdentityCredential(); // System assigned identity } } } } catch (authError) { const msg = `Failed to get authentication credential and enable AAD.${util_1.Util.getInstance().dumpObj(authError)}`; console.log(msg); if (this._diagnosticLogger) { const diagnosticLog = { message: msg, messageId: types_1.DiagnosticMessageId.aadEnabled }; this._diagnosticLogger.logMessage(diagnosticLog); } } return credential; } _sdkAlreadyExists() { try { // appInstance should either resolve to user SDK or crash. If it resolves to attach SDK, user probably modified their NODE_PATH let shimInstance; let exporterInstance; try { // Node 8.9+ Windows if (this._isWindows) { shimInstance = require.resolve("applicationinsights", { paths: [process.cwd()] }); exporterInstance = require.resolve("@azure/monitor-opentelemetry-exporter", { paths: [process.cwd()] }); } // Node 8.9+ Linux else if (this._isLinux) { shimInstance = `${process.cwd()}${require.resolve("applicationinsights", { paths: [process.cwd()] })}`; exporterInstance = `${process.cwd()}${require.resolve("@azure/monitor-opentelemetry-exporter", { paths: [process.cwd()] })}`; } } catch (e) { // Node <8.9 shimInstance = require.resolve(`${process.cwd()}/node_modules/applicationinsights`); exporterInstance = require.resolve(`${process.cwd()}/node_modules/@azure/monitor-opentelemetry-exporter`); } /** * If loaded instance is in Azure machine home path do not attach the SDK, this means customer already instrumented their app. * Linux App Service doesn't append the full cwd to the require.resolve, so we need to check for the relative path we expect * if application insights is being imported in the user app code. */ if (shimInstance.indexOf("home") > -1 || exporterInstance.indexOf("home") > -1 || (shimInstance === LINUX_USER_APPLICATION_INSIGHTS_PATH && this._isLinux)) { const diagnosticLog = { message: `Azure Monitor Distro, Exporter, or Application Insights already exists. Module is already installed in this application; not re-attaching. Location: ${shimInstance}`, messageId: types_1.DiagnosticMessageId.sdkExists }; this._diagnosticLogger.logMessage(diagnosticLog); return true; } // ApplicationInsights or Azure Monitor Distro could be loaded outside of customer application, attach in this case return false; } catch (e) { // crashed while trying to resolve "applicationinsights", so SDK does not exist. Attach appinsights return false; } } } exports.AgentLoader = AgentLoader; //# sourceMappingURL=agentLoader.js.map