applicationinsights
Version:
Microsoft Application Insights module for Node.js
264 lines • 12.7 kB
JavaScript
"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/ /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