Repository: microsoft/ApplicationInsights-node.js
Pull request #1076 (2023-02-09 18:42:04)

[Beta] Add default ignoreOutgoingRequestHook for HTTP instrumentation


Patch:
diff --git a/src/metrics/collection/azureHttpMetricsInstrumentation.ts b/src/metrics/collection/azureHttpMetricsInstrumentation.ts
index cc15f06..fd495ed 100644
--- a/src/metrics/collection/azureHttpMetricsInstrumentation.ts
+++ b/src/metrics/collection/azureHttpMetricsInstrumentation.ts
@@ -11,12 +11,12 @@ import {
     isWrapped,
     safeExecuteInTheMiddle,
 } from "@opentelemetry/instrumentation";
-import { getRequestInfo } from "@opentelemetry/instrumentation-http";
+import { getRequestInfo, HttpInstrumentationConfig } from "@opentelemetry/instrumentation-http";
 import { SpanKind, TracerProvider, Histogram, MeterProvider, ValueType } from "@opentelemetry/api";
 import { SemanticAttributes } from "@opentelemetry/semantic-conventions";
 
 import { APPLICATION_INSIGHTS_SDK_VERSION } from "../../declarations/constants";
-import { HttpMetricsInstrumentationConfig, IHttpStandardMetric, MetricName } from "../types";
+import { IHttpStandardMetric, MetricName } from "../types";
 import { Logger } from "../../shared/logging";
 
 
@@ -32,7 +32,7 @@ export class AzureHttpMetricsInstrumentation extends InstrumentationBase<Http> {
     private _httpServerDurationHistogram!: Histogram;
     private _httpClientDurationHistogram!: Histogram;
 
-    constructor(config: HttpMetricsInstrumentationConfig = {}) {
+    constructor(config: HttpInstrumentationConfig = {}) {
         super("AzureHttpMetricsInstrumentation", APPLICATION_INSIGHTS_SDK_VERSION, config);
         this._nodeVersion = process.versions.node;
         this._updateMetricInstruments();
@@ -58,7 +58,7 @@ export class AzureHttpMetricsInstrumentation extends InstrumentationBase<Http> {
         );
     }
 
-    public _getConfig(): HttpMetricsInstrumentationConfig {
+    public _getConfig(): HttpInstrumentationConfig {
         return this._config;
     }
 
diff --git a/src/metrics/handlers/performanceCounterMetricsHandler.ts b/src/metrics/handlers/performanceCounterMetricsHandler.ts
index 570c3de..cce5d1d 100644
--- a/src/metrics/handlers/performanceCounterMetricsHandler.ts
+++ b/src/metrics/handlers/performanceCounterMetricsHandler.ts
@@ -1,6 +1,5 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT license.
-import { RequestOptions } from "https";
 import {
     AzureMonitorExporterOptions,
     AzureMonitorMetricExporter,
@@ -15,7 +14,6 @@ import {
     View,
 } from "@opentelemetry/sdk-metrics";
 import {
-    HttpMetricsInstrumentationConfig,
     MetricName,
     NativeMetricsCounter,
     PerformanceCounter,
@@ -25,6 +23,7 @@ import { ProcessMetrics } from "../collection/processMetrics";
 import { RequestMetrics } from "../collection/requestMetrics";
 import { ApplicationInsightsConfig, ResourceManager } from "../../shared";
 import { NativePerformanceMetrics } from "../collection/nativePerformanceMetrics";
+import { Util } from "../../shared/util";
 
 export class PerformanceCounterMetricsHandler {
     private _config: ApplicationInsightsConfig;
@@ -59,23 +58,9 @@ export class PerformanceCounterMetricsHandler {
         this._metricReader = new PeriodicExportingMetricReader(metricReaderOptions);
         this._meterProvider.addMetricReader(this._metricReader);
         this._meter = this._meterProvider.getMeter("ApplicationInsightsPerfMetricsMeter");
-
-        const httpMetricsConfig: HttpMetricsInstrumentationConfig = {
-            ignoreOutgoingRequestHook: (request: RequestOptions) => {
-                // Iterate headers
-                for (const key in request?.headers) {
-                    if (key.toLowerCase() === "user-agent") {
-                        return (
-                            request?.headers[key]
-                                .toString()
-                                .indexOf("azsdk-js-monitor-opentelemetry-exporter") > -1
-                        );
-                    }
-                }
-                return false;
-            },
-        };
-        this._httpMetrics = new AzureHttpMetricsInstrumentation(httpMetricsConfig);
+        this._httpMetrics = new AzureHttpMetricsInstrumentation({
+            ignoreOutgoingRequestHook: Util.getInstance().ignoreOutgoingRequestHook
+        });
         this._processMetrics = new ProcessMetrics(this._meter);
         this._requestMetrics = new RequestMetrics(this._meter, this._httpMetrics);
         this._nativeMetrics = new NativePerformanceMetrics(this._meter);
diff --git a/src/metrics/types.ts b/src/metrics/types.ts
index ce04a86..57e4667 100644
--- a/src/metrics/types.ts
+++ b/src/metrics/types.ts
@@ -151,20 +151,3 @@ export const PreAggregatedMetricPropertyNames: { [key in MetricDimensionTypeKeys
     dependencyResultCode: "dependency/resultCode",
     traceSeverityLevel: "trace/severityLevel",
 };
-
-export type IgnoreMatcher = string | RegExp | ((url: string) => boolean);
-
-export interface IgnoreIncomingRequestFunction {
-    (request: IncomingMessage): boolean;
-}
-
-export interface IgnoreOutgoingRequestFunction {
-    (request: RequestOptions): boolean;
-}
-
-export interface HttpMetricsInstrumentationConfig extends InstrumentationConfig {
-    /** Not trace all incoming requests that matched with custom function */
-    ignoreIncomingRequestHook?: IgnoreIncomingRequestFunction;
-    /** Not trace all outgoing requests that matched with custom function */
-    ignoreOutgoingRequestHook?: IgnoreOutgoingRequestFunction;
-}
diff --git a/src/shared/util/util.ts b/src/shared/util/util.ts
index 1396955..a98cf0b 100644
--- a/src/shared/util/util.ts
+++ b/src/shared/util/util.ts
@@ -9,6 +9,7 @@ import { IdGenerator, RandomIdGenerator } from "@opentelemetry/sdk-trace-base";
 
 import { Logger } from "../logging";
 import { ApplicationInsightsConfig } from "../configuration";
+import { IgnoreOutgoingRequestFunction } from "@opentelemetry/instrumentation-http";
 
 export class Util {
     private static _instance: Util;
@@ -121,6 +122,21 @@ export class Util {
         return `${daysText + hour}:${min}:${sec}`;
     }
 
+    public ignoreOutgoingRequestHook: IgnoreOutgoingRequestFunction =
+        (request: http.RequestOptions) => {
+            // Iterate headers and ignore if call is from Azure Monitor Exporter
+            for (const key in request?.headers) {
+                if (key.toLowerCase() === "user-agent") {
+                    return (
+                        request?.headers[key]
+                            .toString()
+                            .indexOf("azsdk-js-monitor-opentelemetry-exporter") > -1
+                    );
+                }
+            }
+            return false;
+        };
+
     /**
      * Using JSON.stringify, by default Errors do not serialize to something useful:
      * Simplify a generic Node Error into a simpler map for customDimensions
diff --git a/src/traces/traceHandler.ts b/src/traces/traceHandler.ts
index fd8e22e..8e7fb31 100644
--- a/src/traces/traceHandler.ts
+++ b/src/traces/traceHandler.ts
@@ -1,5 +1,6 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT license.
+import { RequestOptions } from "http";
 import {
     ApplicationInsightsSampler,
     AzureMonitorExporterOptions,
@@ -14,7 +15,7 @@ import { RedisInstrumentation } from "@opentelemetry/instrumentation-redis";
 import { RedisInstrumentation as Redis4Instrumentation } from "@opentelemetry/instrumentation-redis-4";
 import { NodeTracerProvider, NodeTracerConfig } from "@opentelemetry/sdk-trace-node";
 import { BatchSpanProcessor, BufferConfig, Tracer } from "@opentelemetry/sdk-trace-base";
-import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
+import { HttpInstrumentation, HttpInstrumentationConfig, IgnoreOutgoingRequestFunction } from "@opentelemetry/instrumentation-http";
 
 import { ApplicationInsightsConfig, ResourceManager } from "../shared";
 import { TracerProvider } from "@opentelemetry/api";
@@ -22,6 +23,7 @@ import { MetricHandler } from "../metrics/metricHandler";
 import { AzureSpanProcessor } from "./azureSpanProcessor";
 import { AzureHttpMetricsInstrumentation } from "../metrics/collection/azureHttpMetricsInstrumentation";
 import { AzureFunctionsHook } from "./azureFunctionsHook";
+import { Util } from "../shared/util";
 
 export class TraceHandler {
     private _exporter: AzureMonitorTraceExporter;
@@ -100,6 +102,18 @@ export class TraceHandler {
             }
         }
         if (!this._httpInstrumentation) {
+            let httpInstrumentationConfig = (this._config.instrumentations.http as HttpInstrumentationConfig);
+            let providedgnoreOutgoingRequestHook = httpInstrumentationConfig.ignoreOutgoingRequestHook;
+            let mergedIgnoreOutgoingRequestHook: IgnoreOutgoingRequestFunction = (request: RequestOptions) => {
+                let result = Util.getInstance().ignoreOutgoingRequestHook(request);
+                if (!result) { // Not internal call
+                    if (providedgnoreOutgoingRequestHook) { // Provided hook in config
+                        return providedgnoreOutgoingRequestHook(request);
+                    }
+                }
+                return result;
+            };
+            httpInstrumentationConfig.ignoreOutgoingRequestHook = mergedIgnoreOutgoingRequestHook;
             this._httpInstrumentation = new HttpInstrumentation(this._config.instrumentations.http);
             if (this._metricHandler && this._metricHandler.getStandardMetricsHandler()) {
                 this._httpInstrumentation.setMeterProvider(


Test patch:
diff --git a/test/unitTests/metrics/azureHttpMetricsInstrumentation.tests.ts b/test/unitTests/metrics/azureHttpMetricsInstrumentation.tests.ts
index b2c01a4..61b7b64 100644
--- a/test/unitTests/metrics/azureHttpMetricsInstrumentation.tests.ts
+++ b/test/unitTests/metrics/azureHttpMetricsInstrumentation.tests.ts
@@ -7,37 +7,22 @@ import {
     MeterProvider,
     PeriodicExportingMetricReader,
 } from "@opentelemetry/sdk-metrics";
-
-import { AzureHttpMetricsInstrumentation } from "../../../src/metrics/collection/azureHttpMetricsInstrumentation";
 import { SemanticAttributes } from "@opentelemetry/semantic-conventions";
+import { AzureHttpMetricsInstrumentation } from "../../../src/metrics/collection/azureHttpMetricsInstrumentation";
+import { Util } from "../../../src/shared/util";
 
 nock("https://centralus-0.in.applicationinsights.azure.com")
     .post("/v2.1/track", (body: string) => true)
     .reply(200, {})
     .persist();
 
-const httpMetricsConfig: HttpMetricsInstrumentationConfig = {
-    ignoreOutgoingRequestHook: (request: RequestOptions) => {
-        // Iterate headers
-        for (const key in request?.headers) {
-            if (key.toLowerCase() === "user-agent") {
-                return (
-                    request?.headers[key]
-                        .toString()
-                        .indexOf("azsdk-js-monitor-opentelemetry-exporter") > -1
-                );
-            }
-        }
-        return false;
-    },
-};
-const instrumentation = new AzureHttpMetricsInstrumentation(httpMetricsConfig);
+const instrumentation = new AzureHttpMetricsInstrumentation({
+    ignoreOutgoingRequestHook: Util.getInstance().ignoreOutgoingRequestHook
+});
 instrumentation.enable();
 instrumentation.disable();
 
 import * as http from "http";
-import { HttpMetricsInstrumentationConfig } from "../../../src/metrics/types";
-import { RequestOptions } from "https";
 
 const meterProvider = new MeterProvider();
 const exporter = new AzureMonitorMetricExporter({