Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iKey env variable deprecation #952

Merged
merged 2 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 15 additions & 18 deletions Bootstrap/Default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,22 @@ import azureCore = require("@azure/core-http");
import * as types from "../applicationinsights";
import * as Helpers from "./Helpers";
import Constants = require("../Declarations/Constants");
import { StatusLogger, StatusContract } from "./StatusLogger";
import { StatusLogger } from "./StatusLogger";
import { DiagnosticLogger } from "./DiagnosticLogger";
import { JsonConfig } from "../Library/JsonConfig";
import Config = require("../Library/Config");

// Private configuration vars
let _appInsights: typeof types | null;
let _prefix = "ad_"; // App Services, Default
let _logger: DiagnosticLogger = new DiagnosticLogger(console);
let _statusLogger: StatusLogger = new StatusLogger(console);

export const defaultConfig = new Config(); // Will read env variables, expose for Agent initialization
const _instrumentationKey = defaultConfig.instrumentationKey;
let _logger: DiagnosticLogger = new DiagnosticLogger(console, _instrumentationKey);
let _statusLogger: StatusLogger = new StatusLogger(console, _instrumentationKey);

// Env var local constants
const _setupString = JsonConfig.getInstance().connectionString || process.env.APPINSIGHTS_INSTRUMENTATIONKEY;
const forceStart = process.env.APPLICATIONINSIGHTS_FORCE_START === "true";

// Other local constants
const defaultStatus: StatusContract = {
...StatusLogger.DEFAULT_STATUS,
Ikey: _setupString
};

/**
* Sets the attach-time logger
Expand All @@ -45,13 +42,13 @@ export function setStatusLogger(statusLogger: StatusLogger) {

/**
* Try to setup and start this app insights instance if attach is enabled.
* @param setupString connection string or instrumentation key
* @param setupString connection string
*/
export function setupAndStart(setupString = _setupString, aadTokenCredential?: azureCore.TokenCredential): typeof types | null {
export function setupAndStart(setupString?: string, aadTokenCredential?: azureCore.TokenCredential): typeof types | null {
// If app already contains SDK, skip agent attach
if (!forceStart && Helpers.sdkAlreadyExists(_logger)) {
_statusLogger.logStatus({
...defaultStatus,
...StatusLogger.DEFAULT_STATUS,
AgentInitializedSuccessfully: false,
SDKPresent: true,
Reason: "SDK already exists"
Expand All @@ -60,10 +57,10 @@ export function setupAndStart(setupString = _setupString, aadTokenCredential?: a
}

if (!setupString) {
const message = "Application Insights wanted to be started, but no Connection String or Instrumentation Key was provided";
const message = "Application Insights wanted to be started, but no Connection String was provided";
_logger.logError(message);
_statusLogger.logStatus({
...defaultStatus,
...StatusLogger.DEFAULT_STATUS,
AgentInitializedSuccessfully: false,
Reason: message
});
Expand Down Expand Up @@ -108,7 +105,7 @@ export function setupAndStart(setupString = _setupString, aadTokenCredential?: a
_logger.logMessage("Using AAD Token Credential");
_appInsights.defaultClient.config.aadTokenCredential = aadTokenCredential;
}

_appInsights.start();
// Add attach flag in Statsbeat
let statsbeat = _appInsights.defaultClient.getStatsbeat();
Expand All @@ -119,13 +116,13 @@ export function setupAndStart(setupString = _setupString, aadTokenCredential?: a
// Agent successfully instrumented the SDK
_logger.logMessage("Application Insights was started with setupString: " + setupString);
_statusLogger.logStatus({
...defaultStatus,
...StatusLogger.DEFAULT_STATUS,
AgentInitializedSuccessfully: true
});
} catch (e) {
_logger.logError("Error setting up Application Insights", e);
_statusLogger.logStatus({
...defaultStatus,
...StatusLogger.DEFAULT_STATUS,
AgentInitializedSuccessfully: false,
Reason: `Error setting up Application Insights: ${e && e.message}`
})
Expand Down
6 changes: 4 additions & 2 deletions Bootstrap/DiagnosticLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ export class DiagnosticLogger {
language: "nodejs",
operation: "Startup",
siteName: process.env.WEBSITE_SITE_NAME,
ikey: process.env.APPINSIGHTS_INSTRUMENTATIONKEY,
ikey: "unknown",
MSNev marked this conversation as resolved.
Show resolved Hide resolved
extensionVersion: process.env.ApplicationInsightsAgent_EXTENSION_VERSION,
sdkVersion: APPLICATION_INSIGHTS_SDK_VERSION,
subscriptionId: process.env.WEBSITE_OWNER_NAME ? process.env.WEBSITE_OWNER_NAME.split("+")[0] : null
}
}

constructor(private _writer: DataModel.AgentLogger = console) { }
constructor(private _writer: DataModel.AgentLogger = console, instrumentationKey: string = "unknown") {
DiagnosticLogger.DefaultEnvelope.properties.ikey = instrumentationKey;
}

logMessage(message: DataModel.DiagnosticLog | string, cb?: (err: Error) => void) {
if (typeof cb === "function" && this._writer instanceof FileWriter) {
Expand Down
4 changes: 3 additions & 1 deletion Bootstrap/StatusLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export class StatusLogger {
PID: String(process.pid)
}

constructor(public _writer: DataModel.AgentLogger = console) {}
constructor(public _writer: DataModel.AgentLogger = console, instrumentationKey: string = "unknown") {
StatusLogger.DEFAULT_STATUS.Ikey = instrumentationKey;
}

public logStatus(data: StatusContract, cb?: (err: Error) => void) {
if (typeof cb === "function" && this._writer instanceof FileWriter) {
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
# How to contribute to the Application Insights Node.js SDK

1. Install all dependencies with `npm install`.
2. Set an environment variable to your instrumentation key (optional).
2. Set an environment variable to your Connection String (optional).
```bash
// windows
set APPINSIGHTS_INSTRUMENTATIONKEY=<insert_your_instrumentation_key_here>
set APPINSIGHTS_INSTRUAPPLICATIONINSIGHTS_CONNECTION_STRINGMENTATIONKEY=<YOUR_CONNECTION_STRING>
// linux/macos
export APPINSIGHTS_INSTRUMENTATIONKEY=<insert_your_instrumentation_key_here>
export APPLICATIONINSIGHTS_CONNECTION_STRING=<YOUR_CONNECTION_STRING>
```
3. Run tests
```bash
Expand Down
24 changes: 9 additions & 15 deletions Library/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Config implements IConfig {
private _setCorrelationId: (v: string) => void;
private _profileQueryEndpoint: string;
private _instrumentationKey: string;



constructor(setupString?: string) {
Expand All @@ -77,7 +77,13 @@ class Config implements IConfig {
? null // CS was valid but instrumentation key was not provided, null and grab from env var
: setupString; // CS was invalid, so it must be an ikey

this.instrumentationKey = csCode.instrumentationkey || iKeyCode /* === instrumentationKey */ || csEnv.instrumentationkey || Config._getInstrumentationKey();
const instrumentationKeyEnv: string | undefined = this._instrumentationKey;
this.instrumentationKey = csCode.instrumentationkey || iKeyCode /* === instrumentationKey */ || csEnv.instrumentationkey || instrumentationKeyEnv;

if (!this.instrumentationKey || this.instrumentationKey == "") {
throw new Error("Instrumentation key not found, please provide a connection string before starting the server");
}

let endpoint = `${this.endpointUrl || csCode.ingestionendpoint || csEnv.ingestionendpoint || this._endpointBase}`;
if (endpoint.endsWith("/")) {
// Remove extra '/' if present
Expand Down Expand Up @@ -136,6 +142,7 @@ class Config implements IConfig {
private _mergeConfig() {
let jsonConfig = JsonConfig.getInstance();
this._connectionString = jsonConfig.connectionString;
this._instrumentationKey = jsonConfig.instrumentationKey;
this.correlationHeaderExcludedDomains = jsonConfig.correlationHeaderExcludedDomains;
this.correlationIdRetryIntervalMs = jsonConfig.correlationIdRetryIntervalMs;
this.disableAllExtendedMetrics = jsonConfig.disableAllExtendedMetrics;
Expand Down Expand Up @@ -171,19 +178,6 @@ class Config implements IConfig {
this.enableAutoWebSnippetInjection = jsonConfig.enableAutoWebSnippetInjection;
}

private static _getInstrumentationKey(): string {
// check for both the documented env variable and the azure-prefixed variable
var iKey = process.env[Config.ENV_iKey]
|| process.env[Config.ENV_azurePrefix + Config.ENV_iKey]
|| process.env[Config.legacy_ENV_iKey]
|| process.env[Config.ENV_azurePrefix + Config.legacy_ENV_iKey];
if (!iKey || iKey == "") {
throw new Error("Instrumentation key not found, pass the key in the config to this method or set the key in the environment variable APPINSIGHTS_INSTRUMENTATIONKEY before starting the server");
}

return iKey;
}

/**
* Validate UUID Format
* Specs taken from breeze repo
Expand Down
12 changes: 12 additions & 0 deletions Library/JsonConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { IDisabledExtendedMetrics } from "../AutoCollection/NativePerformance";
const ENV_CONFIGURATION_FILE = "APPLICATIONINSIGHTS_CONFIGURATION_FILE";
// Azure Connection String
const ENV_connectionString = "APPLICATIONINSIGHTS_CONNECTION_STRING";
// Instrumentation Key
const ENV_azurePrefix = "APPSETTING_"; // Azure adds this prefix to all environment variables
const ENV_instrumentationKey = "APPINSIGHTS_INSTRUMENTATIONKEY";
const ENV_legacyInstrumentationKey = "APPINSIGHTS_INSTRUMENTATION_KEY"
// Native Metrics Opt Outs
const ENV_nativeMetricsDisablers = "APPLICATION_INSIGHTS_DISABLE_EXTENDED_METRIC";
const ENV_nativeMetricsDisableAll = "APPLICATION_INSIGHTS_DISABLE_ALL_EXTENDED_METRICS"
Expand Down Expand Up @@ -73,6 +77,14 @@ export class JsonConfig implements IJsonConfig {
constructor() {
// Load env variables first
this.connectionString = process.env[ENV_connectionString];
this.instrumentationKey = process.env[ENV_instrumentationKey]
|| process.env[ENV_azurePrefix + ENV_instrumentationKey]
|| process.env[ENV_legacyInstrumentationKey]
|| process.env[ENV_azurePrefix + ENV_legacyInstrumentationKey];

if (!this.connectionString && this.instrumentationKey) {
Logging.warn("APPINSIGHTS_INSTRUMENTATIONKEY is in path of deprecation, please use APPLICATIONINSIGHTS_CONNECTION_STRING env variable to setup the SDK.");
}
this.disableAllExtendedMetrics = !!process.env[ENV_nativeMetricsDisableAll];
this.extendedMetricDisablers = process.env[ENV_nativeMetricsDisablers];
this.proxyHttpUrl = process.env[ENV_http_proxy];
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ You can manually track more aspects of your app and system using the API describ

## Getting Started

> *Important:* On March 31st, 2025, support for instrumentation key ingestion will end. Instrumentation key ingestion will continue to work, but we’ll no longer provide updates or support for the feature. [Transition to connection strings](https://docs.microsoft.com/en-us/azure/azure-monitor/app/migrate-from-instrumentation-keys-to-connection-strings) to take advantage of [new capabilities](https://docs.microsoft.com/en-us/azure/azure-monitor/app/migrate-from-instrumentation-keys-to-connection-strings#new-capabilities).

1. Create an Application Insights resource in Azure by following [these instructions][].
2. Grab the _Connection String_ from the resource you created in
step 1. Later, you'll either add it to your app's environment variables or
Expand Down Expand Up @@ -76,7 +78,7 @@ let appInsights = require("applicationinsights");
appInsights.setup("YOUR_CONNECTION_STRING").start();
```

* If the instrumentation key is set in the environment variable
* If the connection string is set in the environment variable
APPLICATIONINSIGHTS\_CONNECTION\_STRING, `.setup()` can be called with no
arguments. This makes it easy to use different connection strings for different
environments.
Expand Down
72 changes: 29 additions & 43 deletions Tests/Bootstrap/Default.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { DiagnosticLogger } from "../../Bootstrap/DiagnosticLogger";
import * as DataModel from "../../Bootstrap/DataModel";
import * as Helpers from "../../Bootstrap/Helpers";
import * as DefaultTypes from "../../Bootstrap/Default";
import { JsonConfig } from "../../Library/JsonConfig";


const appInsights = require("../../applicationinsights");

Expand All @@ -20,27 +22,33 @@ class LoggerSpy implements DataModel.AgentLogger {
}

describe("#setupAndStart()", () => {
const startSpy = sinon.spy(appInsights, "start");
let startSpy: sinon.SinonSpy;
var sandbox: sinon.SinonSandbox;
let originalEnv: NodeJS.ProcessEnv;

before(() => {
startSpy.reset();
sandbox = sinon.sandbox.create();
});

afterEach(() => {
startSpy.reset();
delete require.cache[require.resolve("../../Bootstrap/Default")];
beforeEach(() => {
startSpy = sandbox.spy(appInsights, "start");
originalEnv = process.env;
JsonConfig["_instance"] = undefined;
});

after(() => {
startSpy.restore();
afterEach(() => {
process.env = originalEnv;
sandbox.restore();
delete require.cache[require.resolve("../../Bootstrap/Default")];
});

it("should return the client if started multiple times", () => {
const logger = new LoggerSpy();
const origEnv = process.env.ApplicationInsightsAgent_EXTENSION_VERSION;
process.env.ApplicationInsightsAgent_EXTENSION_VERSION = "~2";
const alreadyExistsStub = sinon.stub(Helpers, "sdkAlreadyExists", () => false);

const env = <{ [id: string]: string }>{};
env["ApplicationInsightsAgent_EXTENSION_VERSION"] = "~2";
env["APPLICATIONINSIGHTS_CONNECTION_STRING"] = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://centralus-0.in.applicationinsights.azure.com/";
process.env = env;
sandbox.stub(Helpers, "sdkAlreadyExists", () => false);
// Test
const Default = require("../../Bootstrap/Default") as typeof DefaultTypes;
Default.setLogger(new DiagnosticLogger(logger));
Expand All @@ -52,18 +60,18 @@ describe("#setupAndStart()", () => {
assert.deepEqual(instance2.defaultClient["_telemetryProcessors"].length, 2)

// Cleanup
alreadyExistsStub.restore();
instance1.dispose();
instance2.dispose();
process.env.ApplicationInsightsAgent_EXTENSION_VERSION = origEnv;
})

it("should setup and start the SDK", () => {
// Setup env vars before requiring loader
const logger = new LoggerSpy();
const origEnv = process.env.ApplicationInsightsAgent_EXTENSION_VERSION;
process.env.ApplicationInsightsAgent_EXTENSION_VERSION = "~2";
const alreadyExistsStub = sinon.stub(Helpers, "sdkAlreadyExists", () => false);
const env = <{ [id: string]: string }>{};
env["ApplicationInsightsAgent_EXTENSION_VERSION"] = "~2";
env["APPLICATIONINSIGHTS_CONNECTION_STRING"] = "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;IngestionEndpoint=https://centralus-0.in.applicationinsights.azure.com/";
process.env = env;
sandbox.stub(Helpers, "sdkAlreadyExists", () => false);

// Test
const Default = require("../../Bootstrap/Default") as typeof DefaultTypes;
Expand All @@ -72,9 +80,7 @@ describe("#setupAndStart()", () => {
assert.deepEqual(instance, appInsights);

// Cleanup
alreadyExistsStub.restore();
instance.dispose();
process.env.ApplicationInsightsAgent_EXTENSION_VERSION = origEnv;

// start was called once
assert.equal(startSpy.callCount, 1);
Expand All @@ -87,32 +93,12 @@ describe("#setupAndStart()", () => {
it("should not setup and start the SDK if no setupString is provided", () => {
// Setup
const logger = new LoggerSpy();
const origEnv = process.env.ApplicationInsightsAgent_EXTENSION_VERSION;
const origIkey = process.env.APPINSIGHTS_INSTRUMENTATIONKEY;
const origCs = process.env.APPLICATIONINSIGHTS_CONNECTION_STRING;
process.env.ApplicationInsightsAgent_EXTENSION_VERSION = "~2";
delete process.env.APPINSIGHTS_INSTRUMENTATIONKEY;
delete process.env.APPLICATIONINSIGHTS_CONNECTION_STRING;
const alreadyExistsStub = sinon.stub(Helpers, "sdkAlreadyExists", () => false);
const env = <{ [id: string]: string }>{};
env["ApplicationInsightsAgent_EXTENSION_VERSION"] = "~2";
process.env = env;

sinon.stub(Helpers, "sdkAlreadyExists", () => false);
// Test
const Default = require("../../Bootstrap/Default") as typeof DefaultTypes;
Default.setLogger(new DiagnosticLogger(logger));
const instance = Default.setupAndStart();
assert.equal(instance, null);

// Cleanup
alreadyExistsStub.restore();
process.env.ApplicationInsightsAgent_EXTENSION_VERSION = origEnv;

// start was never called
assert.equal(startSpy.callCount, 0);

// No logging was done
assert.equal(logger.logCount, 0);
assert.equal(logger.errorCount, 1, "Should log if attach is attempted");

process.env.APPINSIGHTS_INSTRUMENTATIONKEY = origIkey;
process.env.APPLICATIONINSIGHTS_CONNECTION_STRING = origCs;
assert.throws(function () { const Default = require("../../Bootstrap/Default") as typeof DefaultTypes; });
});
});
2 changes: 1 addition & 1 deletion Tests/Bootstrap/DiagnosticLogger.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe("DiagnosticLogger", () => {
language: "nodejs",
operation: "Startup",
siteName: undefined,
ikey: undefined,
ikey: "unknown",
extensionVersion: undefined,
sdkVersion: version,
subscriptionId: null,
Expand Down
4 changes: 2 additions & 2 deletions Tests/Library/AuthorizationHandler.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("Library/AuthorizationHandler", () => {

describe("#addAuthorizationHeader()", () => {
it("should add Authorization header to options", async () => {
var config = new Config("");
var config = new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
config.aadTokenCredential = new TestTokenCredential();
var handler = new AuthorizationHandler(config.aadTokenCredential);
var options = {
Expand All @@ -53,7 +53,7 @@ describe("Library/AuthorizationHandler", () => {
});

it("should refresh token if expired", async () => {
var config = new Config("");
var config = new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
var tokenCredential = new TestTokenCredential(new Date(new Date().getMilliseconds() - 500));
config.aadTokenCredential = tokenCredential;
var handler = new AuthorizationHandler(config.aadTokenCredential);
Expand Down
2 changes: 1 addition & 1 deletion applicationinsights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ let _performanceLiveMetrics: AutoCollectPerformance;
*
* @param setupString the Connection String or Instrumentation Key to use. Optional, if
* this is not specified, the value will be read from the environment
* variable APPLICATIONINSIGHTS_CONNECTION_STRING or APPINSIGHTS_INSTRUMENTATIONKEY.
* variable APPLICATIONINSIGHTS_CONNECTION_STRING.
* @returns {Configuration} the configuration class to initialize
* and start the SDK.
*/
Expand Down
Loading