From 53ed4d097a322147194de55ed9125aa8f320d0d2 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Fri, 18 Apr 2025 14:41:44 -0700 Subject: [PATCH 1/4] Release 3.7.0 --- package-lock.json | 48 +-- package.json | 6 +- src/main.ts | 15 - src/metrics/performanceCounters.ts | 291 ------------------ src/metrics/types.ts | 35 --- src/shim/shim-config.ts | 3 +- src/traces/spanProcessor.ts | 34 -- .../metrics/performanceCounters.tests.ts | 123 -------- 8 files changed, 29 insertions(+), 526 deletions(-) delete mode 100644 src/metrics/performanceCounters.ts delete mode 100644 src/traces/spanProcessor.ts delete mode 100644 test/unitTests/metrics/performanceCounters.tests.ts diff --git a/package-lock.json b/package-lock.json index dfe03cc8f..8e860e26a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "applicationinsights", - "version": "3.5.0", + "version": "3.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "applicationinsights", - "version": "3.5.0", + "version": "3.7.0", "license": "MIT", "dependencies": { "@azure/core-auth": "^1.3.0", @@ -15,22 +15,22 @@ "@azure/functions": "^4.6.0", "@azure/functions-old": "npm:@azure/functions@3.5.1", "@azure/identity": "^4.6.0", - "@azure/monitor-opentelemetry": "^1.9.0", - "@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.29", - "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.5", + "@azure/monitor-opentelemetry": "^1.11.0", + "@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.31", + "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.7", "@opentelemetry/api": "^1.9.0", - "@opentelemetry/api-logs": "^0.57.1", - "@opentelemetry/core": "^1.26.0", - "@opentelemetry/exporter-logs-otlp-http": "^0.57.1", - "@opentelemetry/exporter-metrics-otlp-http": "^0.57.1", - "@opentelemetry/exporter-trace-otlp-http": "^0.57.1", - "@opentelemetry/otlp-exporter-base": "^0.57.1", + "@opentelemetry/api-logs": "^0.57.2", + "@opentelemetry/core": "^1.30.1", + "@opentelemetry/exporter-logs-otlp-http": "^0.57.2", + "@opentelemetry/exporter-metrics-otlp-http": "^0.57.2", + "@opentelemetry/exporter-trace-otlp-http": "^0.57.2", + "@opentelemetry/otlp-exporter-base": "^0.57.2", "@opentelemetry/resources": "^1.30.1", - "@opentelemetry/sdk-logs": "^0.57.1", + "@opentelemetry/sdk-logs": "^0.57.2", "@opentelemetry/sdk-metrics": "^1.30.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/sdk-trace-node": "^1.30.1", - "@opentelemetry/semantic-conventions": "^1.28.0", + "@opentelemetry/semantic-conventions": "^1.30.0", "diagnostic-channel": "1.1.1", "diagnostic-channel-publishers": "1.0.8" }, @@ -222,16 +222,16 @@ } }, "node_modules/@azure/monitor-opentelemetry": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/monitor-opentelemetry/-/monitor-opentelemetry-1.9.0.tgz", - "integrity": "sha512-FVpOA2+6heTZqCQIHcaVFcSQB8Bqa8gtIqFqb77sxAjoPdtR1yI26X+YrBO+ZmWxZrJKgyEKbFQDefALPs33vQ==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/monitor-opentelemetry/-/monitor-opentelemetry-1.11.0.tgz", + "integrity": "sha512-cw2Vcgku1779mhrkbH7q4oO0jM0YwdEC1KDDk9Z1GSKhg3z63pHOVp8iKvs33Pftwd3YjlK/6ygcRTiZYOymzg==", "license": "MIT", "dependencies": { - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.0.0", - "@azure/core-rest-pipeline": "^1.1.0", - "@azure/logger": "^1.0.0", - "@azure/monitor-opentelemetry-exporter": "1.0.0-beta.29", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.18.2", + "@azure/logger": "^1.1.4", + "@azure/monitor-opentelemetry-exporter": "1.0.0-beta.31", "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.7", "@microsoft/applicationinsights-web-snippet": "^1.2.1", "@opentelemetry/api": "^1.9.0", @@ -262,9 +262,9 @@ } }, "node_modules/@azure/monitor-opentelemetry-exporter": { - "version": "1.0.0-beta.29", - "resolved": "https://registry.npmjs.org/@azure/monitor-opentelemetry-exporter/-/monitor-opentelemetry-exporter-1.0.0-beta.29.tgz", - "integrity": "sha512-AbcVwf1H/eM1eUHFHrcUrbeBAMbdzmtz+8lCMhMNxUctMngc4TRJbus+t3qlAKzrcSe/3WKQhSorViunbxqIpg==", + "version": "1.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@azure/monitor-opentelemetry-exporter/-/monitor-opentelemetry-exporter-1.0.0-beta.31.tgz", + "integrity": "sha512-fH/vFMWOHwN/qdJ1SxVtsJ9zWIGWJdy/tZiVVPsFbpbR4NT49J5Im72iCcTyvABRPfIkMz/zsD58Yilf0yiEZw==", "license": "MIT", "dependencies": { "@azure/core-auth": "^1.9.0", diff --git a/package.json b/package.json index 188efd01e..5e9819b05 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "author": "Microsoft Application Insights Team", "license": "MIT", "bugs": "https://github.com/microsoft/ApplicationInsights-node.js/issues", - "version": "3.6.0", + "version": "3.7.0", "description": "Microsoft Application Insights module for Node.js", "repository": { "type": "git", @@ -69,8 +69,8 @@ "@azure/functions": "^4.6.0", "@azure/functions-old": "npm:@azure/functions@3.5.1", "@azure/identity": "^4.6.0", - "@azure/monitor-opentelemetry": "^1.9.0", - "@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.29", + "@azure/monitor-opentelemetry": "^1.11.0", + "@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.31", "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.7", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.57.2", diff --git a/src/main.ts b/src/main.ts index 634713142..3fef3f90f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,13 +16,10 @@ import { AutoCollectExceptions } from "./logs/exceptions"; import { AZURE_MONITOR_STATSBEAT_FEATURES, AzureMonitorOpenTelemetryOptions } from "./types"; import { ApplicationInsightsConfig } from "./shared/configuration/config"; import { LogApi } from "./shim/logsApi"; -import { PerformanceCounterMetrics } from "./metrics/performanceCounters"; -import { AzureMonitorSpanProcessor } from "./traces/spanProcessor"; import { StatsbeatFeature, StatsbeatInstrumentation } from "./shim/types"; let autoCollectLogs: AutoCollectLogs; let exceptions: AutoCollectExceptions; -let perfCounters: PerformanceCounterMetrics; /** * Initialize Azure Monitor @@ -41,17 +38,6 @@ export function useAzureMonitor(options?: AzureMonitorOpenTelemetryOptions) { if (internalConfig.enableAutoCollectExceptions) { exceptions = new AutoCollectExceptions(logApi); } - if (internalConfig.enableAutoCollectPerformance) { - try { - perfCounters = new PerformanceCounterMetrics(internalConfig); - // Add SpanProcessor to calculate Request Metrics - if (typeof (trace.getTracerProvider() as BasicTracerProvider).addSpanProcessor === "function") { - (trace.getTracerProvider() as BasicTracerProvider).addSpanProcessor(new AzureMonitorSpanProcessor(perfCounters)); - } - } catch (err) { - diag.error("Failed to initialize PerformanceCounterMetrics: ", err); - } - } autoCollectLogs.enable(internalConfig.instrumentationOptions); _addOtlpExporters(internalConfig); } @@ -63,7 +49,6 @@ export async function shutdownAzureMonitor() { await distroShutdownAzureMonitor(); autoCollectLogs.shutdown(); exceptions?.shutdown(); - perfCounters?.shutdown(); } /** diff --git a/src/metrics/performanceCounters.ts b/src/metrics/performanceCounters.ts deleted file mode 100644 index 6525cbb15..000000000 --- a/src/metrics/performanceCounters.ts +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import * as os from "os"; -import { - Histogram, - Meter, - ObservableCallback, - ObservableGauge, - ObservableResult, - SpanKind, - ValueType, -} from "@opentelemetry/api"; -import { AzureMonitorMetricExporter } from "@azure/monitor-opentelemetry-exporter"; -import { - MeterProvider, - MeterProviderOptions, - PeriodicExportingMetricReader, - PeriodicExportingMetricReaderOptions, -} from "@opentelemetry/sdk-metrics"; -import { ReadableSpan } from "@opentelemetry/sdk-trace-base"; -import { PerformanceCounterMetricNames } from "./types"; -import { ApplicationInsightsConfig } from "../shared/configuration/config"; - -/** - * Azure Monitor PerformanceCounter Metrics - */ -export class PerformanceCounterMetrics { - private _internalConfig: ApplicationInsightsConfig; - private _collectionInterval = 60000; // 60 seconds - private _meterProvider: MeterProvider; - private _azureExporter: AzureMonitorMetricExporter; - private _metricReader: PeriodicExportingMetricReader; - private _meter: Meter; - private _requestDurationHistogram: Histogram; - private _requestRateGauge: ObservableGauge; - private _requestRateGaugeCallback: ObservableCallback; - private _memoryPrivateBytesGauge: ObservableGauge; - private _memoryPrivateBytesGaugeCallback: ObservableCallback; - private _memoryAvailableBytesGauge: ObservableGauge; - private _memoryAvailableBytesGaugeCallback: ObservableCallback; - private _processorTimeGauge: ObservableGauge; - private _processorTimeGaugeCallback: ObservableCallback; - private _processTimeGauge: ObservableGauge; - private _processTimeGaugeCallback: ObservableCallback; - private _totalCount = 0; - private _intervalExecutionTime = 0; - private _lastRequestRate: { count: number; time: number; executionInterval: number }; - private _lastAppCpuUsage: { user: number; system: number }; - private _lastHrtime: number[]; - private _lastCpus: { - model: string; - speed: number; - times: { user: number; nice: number; sys: number; idle: number; irq: number }; - }[]; - private _lastCpusProcess: { - model: string; - speed: number; - times: { user: number; nice: number; sys: number; idle: number; irq: number }; - }[]; - - /** - * Creates performance counter instruments. - * @param options - Distro configuration. - * @param config - Application Insights configuration. - */ - constructor(config: ApplicationInsightsConfig, options?: { collectionInterval: number }) { - this._internalConfig = config; - this._lastCpus = os.cpus(); - this._lastCpusProcess = os.cpus(); - this._lastAppCpuUsage = (process as any).cpuUsage(); - this._lastHrtime = process.hrtime(); - - this._lastRequestRate = { - count: this._totalCount, - time: +new Date(), - executionInterval: this._intervalExecutionTime, - }; - - const meterProviderConfig: MeterProviderOptions = { - resource: this._internalConfig.resource, - }; - this._meterProvider = new MeterProvider(meterProviderConfig); - this._azureExporter = new AzureMonitorMetricExporter(this._internalConfig.azureMonitorExporterOptions); - const metricReaderOptions: PeriodicExportingMetricReaderOptions = { - exporter: this._azureExporter as any, - exportIntervalMillis: options?.collectionInterval || this._collectionInterval, - }; - this._metricReader = new PeriodicExportingMetricReader(metricReaderOptions); - this._meterProvider.addMetricReader(this._metricReader); - this._meter = this._meterProvider.getMeter("AzureMonitorPerformanceCountersMeter"); - - this._lastRequestRate = { count: 0, time: 0, executionInterval: 0 }; - - // Create Instruments - this._requestDurationHistogram = this._meter.createHistogram( - PerformanceCounterMetricNames.REQUEST_DURATION, - { valueType: ValueType.DOUBLE } - ); - this._requestRateGauge = this._meter.createObservableGauge( - PerformanceCounterMetricNames.REQUEST_RATE, - { - description: "Incoming Requests Average Execution Time", - valueType: ValueType.DOUBLE, - } - ); - this._memoryPrivateBytesGauge = this._meter.createObservableGauge( - PerformanceCounterMetricNames.PRIVATE_BYTES, - { description: "Amount of memory process has used in bytes", valueType: ValueType.INT } - ); - this._memoryAvailableBytesGauge = this._meter.createObservableGauge( - PerformanceCounterMetricNames.AVAILABLE_BYTES, - { description: "Amount of available memory in bytes", valueType: ValueType.INT } - ); - this._processorTimeGauge = this._meter.createObservableGauge( - PerformanceCounterMetricNames.PROCESSOR_TIME, - { - description: "Processor time as a percentage", - valueType: ValueType.DOUBLE, - } - ); - this._processTimeGauge = this._meter.createObservableGauge( - PerformanceCounterMetricNames.PROCESS_TIME, - { - description: "Process CPU usage as a percentage", - valueType: ValueType.DOUBLE, - } - ); - - // Add callbacks - this._requestRateGaugeCallback = this._getRequestRate.bind(this); - this._memoryPrivateBytesGaugeCallback = this._getPrivateMemory.bind(this); - this._memoryAvailableBytesGaugeCallback = this._getAvailableMemory.bind(this); - this._processorTimeGaugeCallback = this._getProcessorTime.bind(this); - this._processTimeGaugeCallback = this._getProcessTime.bind(this); - this._memoryPrivateBytesGauge.addCallback(this._memoryPrivateBytesGaugeCallback); - this._memoryAvailableBytesGauge.addCallback(this._memoryAvailableBytesGaugeCallback); - this._processTimeGauge.addCallback(this._processTimeGaugeCallback); - this._processorTimeGauge.addCallback(this._processorTimeGaugeCallback); - this._requestRateGauge.addCallback(this._requestRateGaugeCallback); - } - - /** - * Shutdown Meter Provider it will return no-op Meters after being called. - */ - public async shutdown(): Promise { - return this._meterProvider.shutdown(); - } - - /** - * Force flush Meter Provider. - */ - public async flush(): Promise { - return this._meterProvider.forceFlush(); - } - - /** - *Get OpenTelemetry MeterProvider - */ - public getMeterProvider(): MeterProvider { - return this._meterProvider; - } - - /** - * Record Span metrics - */ - public recordSpan(span: ReadableSpan): void { - if (span.kind !== SpanKind.SERVER) { - return; - } - this._totalCount++; - const durationMs = span.duration[0]; - this._intervalExecutionTime += durationMs; - this._requestDurationHistogram.record(durationMs); - } - - private _getRequestRate(observableResult: ObservableResult) { - const currentTime = +new Date(); - const intervalRequests = this._totalCount - this._lastRequestRate.count || 0; - const elapsedMs = currentTime - this._lastRequestRate.time; - if (elapsedMs > 0) { - const elapsedSeconds = elapsedMs / 1000; - const requestsPerSec = intervalRequests / elapsedSeconds; - observableResult.observe(requestsPerSec); - } - this._lastRequestRate = { - count: this._totalCount, - time: currentTime, - executionInterval: this._lastRequestRate.executionInterval, - }; - } - - private _getPrivateMemory(observableResult: ObservableResult) { - observableResult.observe(process.memoryUsage().rss); - } - - private _getAvailableMemory(observableResult: ObservableResult) { - observableResult.observe(os.freemem()); - } - - private _getTotalCombinedCpu(cpus: os.CpuInfo[], lastCpus: os.CpuInfo[]) { - let totalUser = 0; - let totalSys = 0; - let totalNice = 0; - let totalIdle = 0; - let totalIrq = 0; - for (let i = 0; !!cpus && i < cpus.length; i++) { - const cpu = cpus[i]; - const lastCpu = lastCpus[i]; - const times = cpu.times; - const lastTimes = lastCpu.times; - // user cpu time (or) % CPU time spent in user space - let user = times.user - lastTimes.user; - user = user > 0 ? user : 0; // Avoid negative values - totalUser += user; - // system cpu time (or) % CPU time spent in kernel space - let sys = times.sys - lastTimes.sys; - sys = sys > 0 ? sys : 0; // Avoid negative values - totalSys += sys; - // user nice cpu time (or) % CPU time spent on low priority processes - let nice = times.nice - lastTimes.nice; - nice = nice > 0 ? nice : 0; // Avoid negative values - totalNice += nice; - // idle cpu time (or) % CPU time spent idle - let idle = times.idle - lastTimes.idle; - idle = idle > 0 ? idle : 0; // Avoid negative values - totalIdle += idle; - // irq (or) % CPU time spent servicing/handling hardware interrupts - let irq = times.irq - lastTimes.irq; - irq = irq > 0 ? irq : 0; // Avoid negative values - totalIrq += irq; - } - const combinedTotal = totalUser + totalSys + totalNice + totalIdle + totalIrq; - return { - combinedTotal: combinedTotal, - totalUser: totalUser, - totalIdle: totalIdle, - }; - } - - private _getProcessorTime(observableResult: ObservableResult) { - // this reports total ms spent in each category since the OS was booted, to calculate percent it is necessary - // to find the delta since the last measurement - const cpus = os.cpus(); - if (cpus && cpus.length && this._lastCpus && cpus.length === this._lastCpus.length) { - const cpuTotals = this._getTotalCombinedCpu(cpus, this._lastCpus); - - const value = - cpuTotals.combinedTotal > 0 - ? ((cpuTotals.combinedTotal - cpuTotals.totalIdle) / cpuTotals.combinedTotal) * 100 - : 0; - observableResult.observe(value); - } - this._lastCpus = cpus; - } - - private _getProcessTime(observableResult: ObservableResult) { - // this reports total ms spent in each category since the OS was booted, to calculate percent it is necessary - // to find the delta since the last measurement - const cpus = os.cpus(); - if ( - cpus && - cpus.length && - this._lastCpusProcess && - cpus.length === this._lastCpusProcess.length - ) { - // Calculate % of total cpu time (user + system) this App Process used (Only supported by node v6.1.0+) - let appCpuPercent: number | undefined = undefined; - const appCpuUsage = (process as any).cpuUsage(); - const hrtime = process.hrtime(); - const totalApp = - appCpuUsage.user - - this._lastAppCpuUsage.user + - (appCpuUsage.system - this._lastAppCpuUsage.system) || 0; - - if (typeof this._lastHrtime !== "undefined" && this._lastHrtime.length === 2) { - const elapsedTime = - (hrtime[0] - this._lastHrtime[0]) * 1e6 + (hrtime[1] - this._lastHrtime[1]) / 1e3 || 0; // convert to microseconds - - appCpuPercent = (100 * totalApp) / (elapsedTime * cpus.length); - } - // Set previous - this._lastAppCpuUsage = appCpuUsage; - this._lastHrtime = hrtime; - const cpuTotals = this._getTotalCombinedCpu(cpus, this._lastCpusProcess); - const value = appCpuPercent || (cpuTotals.totalUser / cpuTotals.combinedTotal) * 100; - observableResult.observe(value); - } - this._lastCpusProcess = cpus; - } -} diff --git a/src/metrics/types.ts b/src/metrics/types.ts index 697614543..1c391924b 100644 --- a/src/metrics/types.ts +++ b/src/metrics/types.ts @@ -5,38 +5,3 @@ * Disable Standard Metrics environment variable name. */ export const APPLICATION_INSIGHTS_NO_STANDARD_METRICS = "APPLICATION_INSIGHTS_NO_STANDARD_METRICS"; - -export interface StandardMetricBaseDimensions { - metricId?: string; - cloudRoleInstance?: string; - cloudRoleName?: string; - IsAutocollected?: string; -} - -export interface MetricRequestDimensions extends StandardMetricBaseDimensions { - requestSuccess?: string; - requestResultCode?: string; -} - -export interface MetricDependencyDimensions extends StandardMetricBaseDimensions { - dependencyType?: string; - dependencyTarget?: string; - dependencySuccess?: string; - dependencyResultCode?: string; -} - -export enum StandardMetricNames { - HTTP_REQUEST_DURATION = "azureMonitor.http.requestDuration", - HTTP_DEPENDENCY_DURATION = "azureMonitor.http.dependencyDuration", - EXCEPTION_COUNT = "azureMonitor.exceptionCount", - TRACE_COUNT = "azureMonitor.traceCount", -} - -export enum PerformanceCounterMetricNames { - PRIVATE_BYTES = "Private_Bytes", - AVAILABLE_BYTES = "Available_Bytes", - PROCESSOR_TIME = "Processor_Time", - PROCESS_TIME = "Process_Time", - REQUEST_RATE = "Request_Rate", - REQUEST_DURATION = "Request_Execution_Time", -} diff --git a/src/shim/shim-config.ts b/src/shim/shim-config.ts index 2f63082af..f099c164b 100644 --- a/src/shim/shim-config.ts +++ b/src/shim/shim-config.ts @@ -213,8 +213,9 @@ class Config implements IConfig { }; } } + // Performance counters if (typeof (this.enableAutoCollectPerformance) === "boolean") { - options.enableAutoCollectPerformance = this.enableAutoCollectPerformance; + options.enablePerformanceCounters = this.enableAutoCollectPerformance; } if (typeof (this.enableAutoCollectExternalLoggers) === "boolean") { (options.instrumentationOptions as InstrumentationOptions) = { diff --git a/src/traces/spanProcessor.ts b/src/traces/spanProcessor.ts deleted file mode 100644 index 4354e4b07..000000000 --- a/src/traces/spanProcessor.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { Context } from "@opentelemetry/api"; -import { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base"; -import { PerformanceCounterMetrics } from "../metrics/performanceCounters"; - -/** - * Azure Monitor Span Processor. - * @internal - */ -export class AzureMonitorSpanProcessor implements SpanProcessor { - private readonly _metricHandler: PerformanceCounterMetrics; - - constructor(metricHandler: PerformanceCounterMetrics) { - this._metricHandler = metricHandler; - } - - forceFlush(): Promise { - return Promise.resolve(); - } - - onStart(span: Span, _context: Context): void { - return; - } - - onEnd(span: ReadableSpan): void { - this._metricHandler.recordSpan(span); - } - - shutdown(): Promise { - return Promise.resolve(); - } -} diff --git a/test/unitTests/metrics/performanceCounters.tests.ts b/test/unitTests/metrics/performanceCounters.tests.ts deleted file mode 100644 index 2e99bf6e8..000000000 --- a/test/unitTests/metrics/performanceCounters.tests.ts +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import * as assert from "assert"; -import * as sinon from "sinon"; -import { SpanKind } from "@opentelemetry/api"; -import { ExportResultCode } from "@opentelemetry/core"; -import { PerformanceCounterMetrics } from "../../../src/metrics/performanceCounters"; -import { ApplicationInsightsConfig } from "../../../src/shared/configuration/config"; -import { - SEMRESATTRS_SERVICE_NAME, - SEMRESATTRS_SERVICE_INSTANCE_ID, - } from "@opentelemetry/semantic-conventions"; -import { Resource } from "@opentelemetry/resources"; -import { Histogram } from "@opentelemetry/sdk-metrics"; -import { NoopMeter } from "@opentelemetry/api/build/src/metrics/NoopMeter"; - - -describe("PerformanceCounterMetricsHandler", () => { - let autoCollect: PerformanceCounterMetrics; - let config: ApplicationInsightsConfig; - let exportStub: sinon.SinonStub; - - before(() => { - config = new ApplicationInsightsConfig(); - config.azureMonitorExporterOptions.connectionString = - "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;"; - autoCollect = new PerformanceCounterMetrics(config || config, { - collectionInterval: 100, - }); - exportStub = sinon.stub(autoCollect["_azureExporter"], "export").callsFake( - (spans: any, resultCallback: any) => - new Promise((resolve) => { - resultCallback({ - code: ExportResultCode.SUCCESS, - }); - resolve(spans); - }) - ); - }); - - afterEach(() => { - exportStub.resetHistory(); - }); - - after(async () => { - exportStub.restore(); - await autoCollect.shutdown(); - }); - - let resource = new Resource({}); - resource.attributes[SEMRESATTRS_SERVICE_NAME] = "testcloudRoleName"; - resource.attributes[SEMRESATTRS_SERVICE_INSTANCE_ID] = "testcloudRoleInstance"; - let serverSpan: any = { - kind: SpanKind.SERVER, - duration: [654321], - attributes: { - "http.status_code": 200, - }, - resource: resource, - }; - - describe("#Metrics", () => { - it("should observe instruments during collection", async () => { - for (let i = 0; i < 10; i++) { - autoCollect.recordSpan(serverSpan); - } - - await new Promise((resolve) => setTimeout(resolve, 120)); - assert.ok(exportStub.called); - const resourceMetrics = exportStub.args[0][0]; - const scopeMetrics = resourceMetrics.scopeMetrics; - assert.strictEqual(scopeMetrics.length, 1, "scopeMetrics count"); - let metrics = scopeMetrics[0].metrics; - assert.strictEqual(metrics.length, 6, "metrics count"); - - assert.deepStrictEqual( - metrics[0].descriptor.name, - "Request_Execution_Time" - ); - assert.strictEqual(metrics[0].dataPoints.length, 1, "dataPoints count"); - assert.strictEqual((metrics[0].dataPoints[0].value as Histogram).count, 10, "dataPoint count"); - assert.strictEqual((metrics[0].dataPoints[0].value as Histogram).min, 654321, "dataPoint min"); - assert.strictEqual((metrics[0].dataPoints[0].value as Histogram).max, 654321, "dataPoint max"); - assert.strictEqual((metrics[0].dataPoints[0].value as Histogram).sum, 6543210, "dataPoint sum"); - - assert.deepStrictEqual( - metrics[1].descriptor.name, - "Request_Rate" - ); - assert.ok(metrics[1].dataPoints[0].value> 0, "Wrong request rate value"); - - assert.deepStrictEqual( - metrics[2].descriptor.name, - "Private_Bytes" - ); - assert.ok(metrics[2].dataPoints[0].value > 0, "Wrong private bytes value"); - assert.deepStrictEqual(metrics[3].descriptor.name, "Available_Bytes"); - assert.ok(metrics[3].dataPoints[0].value > 0, "Wrong available bytes value"); - assert.deepStrictEqual(metrics[4].descriptor.name, "Processor_Time"); - assert.ok( - metrics[4].dataPoints[0].value >= 0 && metrics[4].dataPoints[0].value <= 100, - `Wrong Processor Time value: ${metrics[4].dataPoints[0].value}` - ); - assert.deepStrictEqual( - metrics[5].descriptor.name, - "Process_Time" - ); - assert.ok( - metrics[5].dataPoints[0].value >= 0 && metrics[5].dataPoints[0].value <= 100, - `Wrong Process Time value: ${metrics[5].dataPoints[0].value}` - ); - }); - - it("should not collect when disabled", async () => { - autoCollect.shutdown().then(async () => { - autoCollect.recordSpan(serverSpan); - await new Promise((resolve) => setTimeout(resolve, 120)); - assert.ok(exportStub.notCalled); - }); - }); - }); -}); From 4f1cc85ee2b4e3c0af300278ee00cfcca5292e31 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Mon, 21 Apr 2025 11:52:28 -0700 Subject: [PATCH 2/4] Fix test. --- test/unitTests/shim/applicationInsights.tests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unitTests/shim/applicationInsights.tests.ts b/test/unitTests/shim/applicationInsights.tests.ts index 03052496b..71557cc63 100644 --- a/test/unitTests/shim/applicationInsights.tests.ts +++ b/test/unitTests/shim/applicationInsights.tests.ts @@ -87,7 +87,7 @@ describe("ApplicationInsights", () => { .setAutoDependencyCorrelation(false); appInsights.start(); assert.equal(appInsights.defaultClient["_options"].enableAutoCollectExceptions, false); - assert.equal(appInsights.defaultClient["_options"].enableAutoCollectPerformance, false); + assert.equal(appInsights.defaultClient["_options"].enablePerformanceCounters, false); assert.equal(JSON.stringify(appInsights.defaultClient["_options"].instrumentationOptions.bunyan), JSON.stringify({ enabled: false })); assert.equal(JSON.stringify((appInsights.defaultClient["_options"].instrumentationOptions as InstrumentationOptions).console), JSON.stringify({ enabled: false })); assert.equal(JSON.stringify((appInsights.defaultClient["_options"].instrumentationOptions as InstrumentationOptions).winston), JSON.stringify({ enabled: false })); From d6b995216f203dc940ac86e767e8db5cd16731ed Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Mon, 21 Apr 2025 14:53:36 -0700 Subject: [PATCH 3/4] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8cb2f78ae..4cce62db5 100644 --- a/README.md +++ b/README.md @@ -417,3 +417,4 @@ This project may contain trademarks or logos for projects, products, or services ## License [MIT](LICENSE) + From 8584cbe763e7b9c9b305ce14965ad215a4bd9626 Mon Sep 17 00:00:00 2001 From: Jackson Weber Date: Mon, 21 Apr 2025 14:53:43 -0700 Subject: [PATCH 4/4] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4cce62db5..8cb2f78ae 100644 --- a/README.md +++ b/README.md @@ -417,4 +417,3 @@ This project may contain trademarks or logos for projects, products, or services ## License [MIT](LICENSE) -