Skip to content

Commit

Permalink
Ensure that undefined client/statsbeat will not error out.
Browse files Browse the repository at this point in the history
  • Loading branch information
JacksonWeber committed Dec 7, 2023
1 parent f9a11e7 commit e904748
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 24 deletions.
12 changes: 8 additions & 4 deletions AutoCollection/NativePerformance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class AutoCollectNativePerformance {
private _handle: NodeJS.Timer;
private _client: TelemetryClient;
private _disabledMetrics: IDisabledExtendedMetrics = {};
private _statsbeat: Statsbeat;
private _statsbeat: Statsbeat | undefined;

constructor(client: TelemetryClient) {
// Note: Only 1 instance of this can exist. So when we reconstruct this object,
Expand All @@ -37,7 +37,7 @@ export class AutoCollectNativePerformance {
}
AutoCollectNativePerformance.INSTANCE = this;
this._client = client;
this._statsbeat = this._client.getStatsbeat();
this._statsbeat = this._client?.getStatsbeat();
}

/**
Expand Down Expand Up @@ -70,15 +70,19 @@ export class AutoCollectNativePerformance {

// Enable the emitter if we were able to construct one
if (this._isEnabled && AutoCollectNativePerformance._emitter) {
this._statsbeat.addFeature(Constants.StatsbeatFeature.NATIVE_METRICS);
if (this._statsbeat) {
this._statsbeat.addFeature(Constants.StatsbeatFeature.NATIVE_METRICS);
}
// enable self
AutoCollectNativePerformance._emitter.enable(true, collectionInterval);
if (!this._handle) {
this._handle = setInterval(() => this._trackNativeMetrics(), collectionInterval);
this._handle.unref();
}
} else if (AutoCollectNativePerformance._emitter) {
this._statsbeat.removeFeature(Constants.StatsbeatFeature.NATIVE_METRICS);
if (this._statsbeat) {
this._statsbeat.removeFeature(Constants.StatsbeatFeature.NATIVE_METRICS);
}
// disable self
AutoCollectNativePerformance._emitter.enable(false);
if (this._handle) {
Expand Down
4 changes: 2 additions & 2 deletions AutoCollection/WebSnippet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class WebSnippet {
private _isEnabled: boolean;
private _isInitialized: boolean;
private _isIkeyValid: boolean = true;
private _statsbeat: Statsbeat;
private _statsbeat: Statsbeat | undefined;
private _webInstrumentationIkey: string;
private _clientWebInstrumentationConfig: IWebInstrumentationConfig[];
private _clientWebInstrumentationSrc: string;
Expand All @@ -43,7 +43,7 @@ class WebSnippet {
this._clientWebInstrumentationConfig = client.config.webInstrumentationConfig;
this._clientWebInstrumentationSrc = client.config.webInstrumentationSrc;

this._statsbeat = client.getStatsbeat();
this._statsbeat = client?.getStatsbeat();
}

public enable(isEnabled: boolean, webInstrumentationConnectionString?: string ) {
Expand Down
12 changes: 7 additions & 5 deletions Library/QuickPulseStateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ class QuickPulseStateManager {
private _collectors: { enable: (enable: boolean) => void }[] = [];
private _redirectedHost: string = null;
private _pollingIntervalHint: number = -1;
private _statsbeat: Statsbeat;
private _statsbeat: Statsbeat | undefined;

constructor(client: TelemetryClient, context?: Context, getAuthorizationHandler?: (config: Config) => AuthorizationHandler) {
this.config = client.config;
constructor(config: Config, context?: Context, getAuthorizationHandler?: (config: Config) => AuthorizationHandler, client?: TelemetryClient) {
this.config = config;
this.context = context || new Context();
this._sender = new QuickPulseSender(this.config, getAuthorizationHandler);
this._isEnabled = false;
this._statsbeat = client.getStatsbeat();
this._statsbeat = client?.getStatsbeat();
}

/**
Expand Down Expand Up @@ -82,7 +82,9 @@ class QuickPulseStateManager {
if (isEnabled && !this._isEnabled) {
this._isEnabled = true;
this._goQuickPulse();
this._statsbeat.addFeature(Constants.StatsbeatFeature.LIVE_METRICS);
if (this._statsbeat) {
this._statsbeat.addFeature(Constants.StatsbeatFeature.LIVE_METRICS);
}
} else if (!isEnabled && this._isEnabled) {
this._isEnabled = false;
clearTimeout(this._handle);
Expand Down
2 changes: 1 addition & 1 deletion Library/TelemetryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Tags } from "../Declarations/Contracts";
class TelemetryClient {
private static TAG = "TelemetryClient";
private _telemetryProcessors: { (envelope: Contracts.EnvelopeTelemetry, contextObjects: { [name: string]: any; }): boolean; }[] = [];
private _statsbeat: Statsbeat;
private _statsbeat: Statsbeat | undefined;

public config: Config;
public context: Context;
Expand Down
26 changes: 17 additions & 9 deletions Tests/Library/QuickPulseStateManager.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("Library/QuickPulseStateManager", () => {
});

it("should create a config with ikey", () => {
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));

assert.ok(qps.config);
assert.equal(qps.config.instrumentationKey, "1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
Expand All @@ -34,7 +34,15 @@ describe("Library/QuickPulseStateManager", () => {
assert.ok(qps["_collectors"].length === 0);
});

it("should not error if statsbeat is undefined", () => {
const client: TelemetryClient = new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
client["_statsbeat"] = undefined;
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, client);
assert.ok(qps);
});

it("should reuse authorization handler if provided", () => {
const config = new Config("InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;");
var client = new TelemetryClient("InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;");
var handler = new AuthorizationHandler({
async getToken(scopes: string | string[], options?: any): Promise<any> {
Expand All @@ -44,7 +52,7 @@ describe("Library/QuickPulseStateManager", () => {
var getAuthorizationHandler = () => {
return handler;
};
qps = new QuickPulseClient(client, null, getAuthorizationHandler);
qps = new QuickPulseClient(config, null, getAuthorizationHandler);
assert.equal(qps["_sender"]["_getAuthorizationHandler"](client.config), handler);
});
});
Expand All @@ -53,7 +61,7 @@ describe("Library/QuickPulseStateManager", () => {
let qps: QuickPulseClient;

beforeEach(() => {
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
})
afterEach(() => {
qps = null;
Expand Down Expand Up @@ -104,7 +112,7 @@ describe("Library/QuickPulseStateManager", () => {

describe("#reset", () => {
it("should reset metric and document buffers", () => {
let qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
let qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
(<any>qps["_metrics"]) = { foo: "bar" };
(<any>qps["_documents"]) = [{ foo: "bar" }];

Expand All @@ -124,7 +132,7 @@ describe("Library/QuickPulseStateManager", () => {
let pingStub: sinon.SinonStub;

beforeEach(() => {
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
postStub = sinon.stub(qps, "_post");
pingStub = sinon.stub(qps, "_ping");
})
Expand Down Expand Up @@ -165,7 +173,7 @@ describe("Library/QuickPulseStateManager", () => {

beforeEach(() => {
clock = sinon.useFakeTimers();
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
postStub = sinon.stub(qps, "_post");
pingStub = sinon.stub(qps, "_ping");
})
Expand Down Expand Up @@ -204,7 +212,7 @@ describe("Library/QuickPulseStateManager", () => {

beforeEach(() => {
clock = sinon.useFakeTimers();
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
submitDataStub = sinon.stub(qps['_sender'], "_submitData");
})
afterEach(() => {
Expand Down Expand Up @@ -255,7 +263,7 @@ describe("Library/QuickPulseStateManager", () => {
let qps: QuickPulseClient;

beforeEach(() => {
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));

})
afterEach(() => {
Expand Down Expand Up @@ -293,7 +301,7 @@ describe("Library/QuickPulseStateManager", () => {

beforeEach(() => {
sandbox = sinon.sandbox.create();
qps = new QuickPulseClient(new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
qps = new QuickPulseClient(new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"), undefined, undefined, new TelemetryClient("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333"));
});

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe("TelemetryProcessors/PerformanceMetricsTelemetryProcessor", () => {

it("should add document to the provided client", () => {
var qpSpy = sinon.spy(QuickPulse, "performanceMetricsTelemetryProcessor");
var client: QuickPulseStateManager = new QuickPulseStateManager(new TelemetryClient(ikey));
var client: QuickPulseStateManager = new QuickPulseStateManager(new Config(ikey), undefined, undefined, new TelemetryClient(ikey));
var addDocumentStub = sinon.stub(client, "addDocument");

// Act
Expand All @@ -50,5 +50,19 @@ describe("TelemetryProcessors/PerformanceMetricsTelemetryProcessor", () => {
qpSpy.restore();
addDocumentStub.restore();
});

it("should not error on undefined statsbeat", () => {
const qpSpy = sinon.spy(QuickPulse, "performanceMetricsTelemetryProcessor");
const telemetryClient = new TelemetryClient(ikey);
telemetryClient["_statsbeat"] = undefined;

const client: QuickPulseStateManager = new QuickPulseStateManager(new Config(ikey), undefined, undefined, telemetryClient);

const res = QuickPulse.performanceMetricsTelemetryProcessor(envelope, client);

assert.ok(qpSpy.calledOnce);
assert.equal(res, true);
qpSpy.restore();
})
});
});
4 changes: 2 additions & 2 deletions applicationinsights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export function start() {
// Initialize Live metrics in case config was provided in telemetryClient config, double initialization check is part of liveMetrics client
if (!liveMetricsClient) {
// No qps client exists. Create one and prepare it to be enabled at .start()
liveMetricsClient = new QuickPulseClient(defaultClient, defaultClient.context, defaultClient.getAuthorizationHandler);
liveMetricsClient = new QuickPulseClient(defaultClient.config, defaultClient.context, defaultClient.getAuthorizationHandler, defaultClient);
_performanceLiveMetrics = new AutoCollectPerformance(liveMetricsClient as any, 1000, true);
liveMetricsClient.addCollector(_performanceLiveMetrics);
defaultClient.quickPulseClient = liveMetricsClient; // Need this so we can forward all manual tracks to live metrics via PerformanceMetricsTelemetryProcessor
Expand Down Expand Up @@ -483,7 +483,7 @@ export class Configuration {

if (!liveMetricsClient && enable) {
// No qps client exists. Create one and prepare it to be enabled at .start()
liveMetricsClient = new QuickPulseClient(defaultClient, defaultClient.context, defaultClient.getAuthorizationHandler);
liveMetricsClient = new QuickPulseClient(defaultClient.config, defaultClient.context, defaultClient.getAuthorizationHandler, defaultClient);
_performanceLiveMetrics = new AutoCollectPerformance(liveMetricsClient as any, 1000, true);
liveMetricsClient.addCollector(_performanceLiveMetrics);
defaultClient.quickPulseClient = liveMetricsClient; // Need this so we can forward all manual tracks to live metrics via PerformanceMetricsTelemetryProcessor
Expand Down

0 comments on commit e904748

Please sign in to comment.