Repository: microsoft/ApplicationInsights-node.js
Pull request #1105 (2023-03-10 20:50:03)

[Beta] Add spanProccesor in TraceHandler


Patch:
diff --git a/README.md b/README.md
index 8482059..2d7235e 100644
--- a/README.md
+++ b/README.md
@@ -274,8 +274,7 @@ class SpanEnrichingProcessor implements SpanProcessor{
     }
 }
 
-const tracerProvider = appInsights.getTraceHandler().getTracerProvider();
-tracerProvider.addSpanProcessor(new SpanEnrichingProcessor());
+appInsights.getTraceHandler().addSpanProcessor(new SpanEnrichingProcessor());
 appInsights.start();
 ```
 
diff --git a/src/traces/traceHandler.ts b/src/traces/traceHandler.ts
index 489d4b5..69759c1 100644
--- a/src/traces/traceHandler.ts
+++ b/src/traces/traceHandler.ts
@@ -13,7 +13,7 @@ import { PgInstrumentation } from "@opentelemetry/instrumentation-pg";
 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 { BatchSpanProcessor, BufferConfig, SpanProcessor, Tracer } from "@opentelemetry/sdk-trace-base";
 import { HttpInstrumentation, HttpInstrumentationConfig, IgnoreOutgoingRequestFunction } from "@opentelemetry/instrumentation-http";
 import { ApplicationInsightsSampler } from "./applicationInsightsSampler";
 import { ApplicationInsightsConfig } from "../shared";
@@ -149,6 +149,10 @@ export class TraceHandler {
         });
     }
 
+    public addSpanProcessor(spanProcessor: SpanProcessor) {
+        this._tracerProvider.addSpanProcessor(spanProcessor);
+    }
+
     public addInstrumentation(instrumentation: Instrumentation) {
         this._instrumentations.push(instrumentation);
     }


Test patch:
diff --git a/test/unitTests/traces/traceHandler.tests.ts b/test/unitTests/traces/traceHandler.tests.ts
index 574512a..053b0c8 100644
--- a/test/unitTests/traces/traceHandler.tests.ts
+++ b/test/unitTests/traces/traceHandler.tests.ts
@@ -7,8 +7,9 @@ import { ExportResultCode } from "@opentelemetry/core";
 import { TraceHandler } from "../../../src/traces";
 import { MetricHandler } from "../../../src/metrics";
 import { ApplicationInsightsConfig } from "../../../src/shared";
-import { Instrumentation } from "@opentelemetry/instrumentation";
 import { HttpInstrumentationConfig } from "@opentelemetry/instrumentation-http";
+import { ReadableSpan, SpanProcessor } from "@opentelemetry/sdk-trace-base";
+import { Context, Span } from "@opentelemetry/api";
 
 describe("Library/TraceHandler", () => {
     let http: any = null;
@@ -148,7 +149,7 @@ describe("Library/TraceHandler", () => {
             if (isHttps) {
                 return new Promise((resolve, reject) => {
                     const req = https.request(options, (res: any) => {
-                        res.on("data", function () {});
+                        res.on("data", function () { });
                         res.on("end", () => {
                             resolve();
                         });
@@ -161,7 +162,7 @@ describe("Library/TraceHandler", () => {
             }
             return new Promise((resolve, reject) => {
                 const req = http.request(options, (res: any) => {
-                    res.on("data", function () {});
+                    res.on("data", function () { });
                     res.on("end", () => {
                         resolve();
                     });
@@ -329,6 +330,61 @@ describe("Library/TraceHandler", () => {
                 });
         });
 
+        it("Custom Span processors", (done) => {
+            handler.start();
+            let customSpanProcessor: SpanProcessor = {
+                forceFlush: () => {
+                    return Promise.resolve();
+                },
+                onStart: (span: Span, context: Context) => {
+                    span.setAttribute("startAttribute", "SomeValue");
+                },
+                onEnd: (span: ReadableSpan) => {
+                    span.attributes["endAttribute"] = "SomeValue2";
+                },
+                shutdown: () => {
+                    return Promise.resolve();
+                }
+            };
+            handler.addSpanProcessor(customSpanProcessor);
+            makeHttpRequest(false)
+                .then(() => {
+                    handler
+                        .flush()
+                        .then(() => {
+                            assert.ok(exportStub.calledOnce, "Export called");
+                            const spans = exportStub.args[0][0];
+                            assert.equal(spans.length, 2);
+                            // Incoming request
+                            assert.equal(
+                                spans[0].attributes["startAttribute"],
+                                "SomeValue"
+                            );
+                            assert.equal(
+                                spans[0].attributes["endAttribute"],
+                                "SomeValue2"
+                            );
+                            // Outgoing request
+                            assert.equal(
+                                spans[1].attributes["startAttribute"],
+                                "SomeValue"
+                            );
+                            assert.equal(
+                                spans[1].attributes["endAttribute"],
+                                "SomeValue2"
+                            );
+                            done();
+                        })
+                        .catch((error) => {
+                            done(error);
+                        });
+                })
+                .catch((error) => {
+                    done(error);
+                });
+        });
+
+
         it("Span processing for pre aggregated metrics", (done) => {
             handler.start();
             metricHandler.getConfig().enableAutoCollectStandardMetrics = true;