@pagopa/azure-tracing 0.4.1-beta.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,8 @@ yarn add @pagopa/azure-tracing
15
15
 
16
16
  ### Instrumenting Azure Functions
17
17
 
18
+ To enable OpenTelemetry tracing and route telemetry to Azure Monitor in your Azure Functions (both v3 and v4 programming models), you primarily need to perform two steps: preload the instrumentation logic via `NODE_OPTIONS` and register lifecycle hooks.
19
+
18
20
  Currently, [ECMAScript Modules (ESM) support in OpenTelemetry is still experimental](https://github.com/open-telemetry/opentelemetry-js/blob/966ac176af249d86de6cb10feac2306062846768/doc/esm-support.md),
19
21
  which makes direct instrumentation of Azure Functions a bit tricky.
20
22
  So, if you have a Node.js project ESM based (`"type": "module"` in the `package.json`), to work around this, you have to preload the instrumentation logic at runtime using the `NODE_OPTIONS` environment variable.
@@ -70,15 +72,9 @@ registerAzureFunctionHooks(app);
70
72
 
71
73
  ### Instrumenting Azure Functions v3 Handlers
72
74
 
73
- For Azure Functions using the v3 programming model, the recommended way to enable OpenTelemetry tracing is to use the `NODE_OPTIONS` environment variable, just like for v4 functions:
75
+ For Azure Functions using the v3 programming model, if you need more granular control over OpenTelemetry context propagation within your function handlers, you can use the `withOtelContextFunctionV3` helper function to wrap your handlers. This function is designed to work with the v3 `Context` object structure.
74
76
 
75
- ```bash
76
- NODE_OPTIONS=--import @pagopa/azure-tracing
77
- ```
78
-
79
- This will automatically enable OpenTelemetry tracing and route telemetry to Azure Monitor.
80
-
81
- Then, wrap the execution of the Azure function in the OpenTelemetry context; take inspiration from the following code snippet:
77
+ To wrap the execution of your Azure Function in the OpenTelemetry context, use the `withOtelContextFunctionV3` helper as follows:
82
78
 
83
79
  ```ts
84
80
  import { AzureFunction, Context as FunctionContext } from "@azure/functions"; // "@azure/functions": "^3"
@@ -95,6 +91,9 @@ export const expressToAzureFunction =
95
91
 
96
92
  ### Enabling Azure Monitor Telemetry
97
93
 
94
+ > [!NOTE]
95
+ > For Azure Functions, it is necessary to use the `NODE_OPTIONS` environment variable and register lifecycle hooks as described in the "Instrumenting Azure Functions" section. Manual initialization with `initAzureMonitor` is typically not required for Azure Functions (due to the issue previously explained), but it is useful for other Node.js applications (e.g., Azure App Services) where direct SDK initialization is preferred or necessary.
96
+
98
97
  If you want to enable Azure Monitor telemetry in your application, and you don't have those issues previously described, you can do so in the following ways:
99
98
 
100
99
  ```ts
@@ -108,17 +107,6 @@ initAzureMonitor(instrumentations, config);
108
107
  ...
109
108
  ```
110
109
 
111
- > [!NOTE]
112
- > the use of `ExpressInstrumentation` is just for example, you can use any other OpenTelemetry instrumentation you want.
113
-
114
- or, if you want to use the default configuration:
115
-
116
- ```ts
117
- import { initAzureMonitor } from "@pagopa/azure-tracing/azure-monitor";
118
- ...
119
- initAzureMonitor();
120
- ```
121
-
122
110
  ### Logging Custom Events
123
111
 
124
112
  You can log custom events for additional observability using the `emitCustomEvent` function.
@@ -0,0 +1,22 @@
1
+ import { app } from '@azure/functions';
2
+
3
+ /**
4
+ * Registers Azure Function hooks to enable OpenTelemetry tracing.
5
+ * These hooks extract trace context from the Azure Function context
6
+ * and bind it to the function handler, ensuring that traces are
7
+ * properly propagated across function invocations.
8
+ *
9
+ * Once the issues that causes this workaround are resolved, it will be possible
10
+ * to add the [azure-functions-nodejs-opentelemetry](https://github.com/Azure/azure-functions-nodejs-opentelemetry/tree/main)
11
+ * to the instrumentation package and remove this workaround.
12
+ *
13
+ * @example
14
+ * In your application, where you add the Azure Functions hooks (like `app.http() and so on), you
15
+ * can add the following code:
16
+ *
17
+ * registerAzureFunctionHooks(app);
18
+ *
19
+ */
20
+ declare const registerAzureFunctionHooks: ({ hook }: typeof app) => void;
21
+
22
+ export { registerAzureFunctionHooks };
@@ -0,0 +1,20 @@
1
+ // src/azure/functions/hooks.ts
2
+ import { context as otelContext, propagation } from "@opentelemetry/api";
3
+ var registerAzureFunctionHooks = ({ hook }) => {
4
+ hook.preInvocation((context) => {
5
+ const traceContext = context.invocationContext.traceContext;
6
+ if (traceContext) {
7
+ context.functionHandler = otelContext.bind(
8
+ propagation.extract(otelContext.active(), {
9
+ traceparent: traceContext.traceParent,
10
+ tracestate: traceContext.traceState
11
+ }),
12
+ context.functionHandler
13
+ );
14
+ }
15
+ });
16
+ };
17
+ export {
18
+ registerAzureFunctionHooks
19
+ };
20
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/azure/functions/hooks.ts"],"sourcesContent":["import { app } from \"@azure/functions\";\nimport { context as otelContext, propagation } from \"@opentelemetry/api\";\n\n/**\n * Registers Azure Function hooks to enable OpenTelemetry tracing.\n * These hooks extract trace context from the Azure Function context\n * and bind it to the function handler, ensuring that traces are\n * properly propagated across function invocations.\n *\n * Once the issues that causes this workaround are resolved, it will be possible\n * to add the [azure-functions-nodejs-opentelemetry](https://github.com/Azure/azure-functions-nodejs-opentelemetry/tree/main)\n * to the instrumentation package and remove this workaround.\n *\n * @example\n * In your application, where you add the Azure Functions hooks (like `app.http() and so on), you\n * can add the following code:\n *\n * registerAzureFunctionHooks(app);\n *\n */\nexport const registerAzureFunctionHooks = ({ hook }: typeof app) => {\n hook.preInvocation((context) => {\n const traceContext = context.invocationContext.traceContext;\n if (traceContext) {\n context.functionHandler = otelContext.bind(\n propagation.extract(otelContext.active(), {\n traceparent: traceContext.traceParent,\n tracestate: traceContext.traceState,\n }),\n context.functionHandler,\n );\n }\n });\n};\n"],"mappings":";AACA,SAAS,WAAW,aAAa,mBAAmB;AAmB7C,IAAM,6BAA6B,CAAC,EAAE,KAAK,MAAkB;AAClE,OAAK,cAAc,CAAC,YAAY;AAC9B,UAAM,eAAe,QAAQ,kBAAkB;AAC/C,QAAI,cAAc;AAChB,cAAQ,kBAAkB,YAAY;AAAA,QACpC,YAAY,QAAQ,YAAY,OAAO,GAAG;AAAA,UACxC,aAAa,aAAa;AAAA,UAC1B,YAAY,aAAa;AAAA,QAC3B,CAAC;AAAA,QACD,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,75 @@
1
+ // src/azure/functions/index.mts
2
+ import { createAddHookMessageChannel } from "import-in-the-middle";
3
+ import { register } from "module";
4
+ import { metrics, trace } from "@opentelemetry/api";
5
+ import { registerInstrumentations } from "@opentelemetry/instrumentation";
6
+
7
+ // src/azure/monitor/start-from-env.ts
8
+ import { useAzureMonitor } from "@azure/monitor-opentelemetry";
9
+
10
+ // src/azure/monitor/env.ts
11
+ import { createEnv } from "@t3-oss/env-core";
12
+ import { z } from "zod";
13
+ var loadEnv = () => createEnv({
14
+ emptyStringAsUndefined: true,
15
+ onValidationError: (errors) => {
16
+ throw new Error(
17
+ errors.map(
18
+ (error) => `Environment variable ${error.path} - ${error.message}`
19
+ ).join(", ")
20
+ );
21
+ },
22
+ runtimeEnv: process.env,
23
+ server: {
24
+ APPINSIGHTS_SAMPLING_PERCENTAGE: z.optional(
25
+ z.coerce.number().min(0).max(100).default(5).describe(
26
+ "Application Insights sampling percentage between 0 and 100. If not set, defaults to 5."
27
+ )
28
+ ).transform((value) => {
29
+ const percentage = Number(value);
30
+ return isNaN(percentage) ? 5 : percentage;
31
+ }).transform((value) => value / 100),
32
+ APPLICATIONINSIGHTS_CONNECTION_STRING: z.string().describe("The connection string for Application Insights.")
33
+ }
34
+ });
35
+
36
+ // src/azure/monitor/start-from-env.ts
37
+ var initFromEnv = () => {
38
+ const env = loadEnv();
39
+ return useAzureMonitor({
40
+ azureMonitorExporterOptions: {
41
+ connectionString: env.APPLICATIONINSIGHTS_CONNECTION_STRING
42
+ },
43
+ enableLiveMetrics: true,
44
+ samplingRatio: env.APPINSIGHTS_SAMPLING_PERCENTAGE
45
+ });
46
+ };
47
+
48
+ // src/azure/opentelemetry/azure-undici-instrumentation.ts
49
+ import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
50
+ var registerUndiciInstrumentation = () => new UndiciInstrumentation({
51
+ requestHook: (span, requestInfo) => {
52
+ const { method, origin, path } = requestInfo;
53
+ span.setAttributes({
54
+ "http.host": origin,
55
+ "http.method": method,
56
+ "http.target": path,
57
+ "http.url": `${origin}${path}`
58
+ });
59
+ },
60
+ responseHook: (span, { response }) => {
61
+ span.setAttribute("http.status_code", response.statusCode);
62
+ }
63
+ });
64
+
65
+ // src/azure/functions/index.mts
66
+ var { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel();
67
+ register("import-in-the-middle/hook.mjs", import.meta.url, registerOptions);
68
+ initFromEnv();
69
+ registerInstrumentations({
70
+ instrumentations: [registerUndiciInstrumentation()],
71
+ meterProvider: metrics.getMeterProvider(),
72
+ tracerProvider: trace.getTracerProvider()
73
+ });
74
+ await waitForAllMessagesAcknowledged();
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/azure/functions/index.mts","../../src/azure/monitor/start-from-env.ts","../../src/azure/monitor/env.ts","../../src/azure/opentelemetry/azure-undici-instrumentation.ts"],"sourcesContent":["/*\nThis file is required to instrument ESM application to use OpenTelemetry.\nThis file must be pre-loaded through the `NODE_OPTIONS` environment variable to\nhave a fully instrumented application.\n */\n\nimport { createAddHookMessageChannel } from \"import-in-the-middle\";\nimport { register } from \"module\";\n\nconst { registerOptions, waitForAllMessagesAcknowledged } =\n createAddHookMessageChannel();\n\nregister(\"import-in-the-middle/hook.mjs\", import.meta.url, registerOptions);\n\nimport { metrics, trace } from \"@opentelemetry/api\";\nimport { registerInstrumentations } from \"@opentelemetry/instrumentation\";\n\nimport { initFromEnv } from \"../monitor/start-from-env\";\nimport { registerUndiciInstrumentation } from \"../opentelemetry/azure-undici-instrumentation\";\n\ninitFromEnv();\n\nregisterInstrumentations({\n instrumentations: [registerUndiciInstrumentation()],\n meterProvider: metrics.getMeterProvider(),\n tracerProvider: trace.getTracerProvider(),\n});\n\nawait waitForAllMessagesAcknowledged();\n","import { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\n\nimport { loadEnv } from \"./env\";\n\nexport const initFromEnv = () => {\n const env = loadEnv();\n\n return useAzureMonitor({\n azureMonitorExporterOptions: {\n connectionString: env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n },\n enableLiveMetrics: true,\n samplingRatio: env.APPINSIGHTS_SAMPLING_PERCENTAGE,\n });\n};\n","// Load and type check environment variables on runtime\nimport { createEnv } from \"@t3-oss/env-core\";\nimport { z } from \"zod\";\n\nexport const loadEnv = () =>\n createEnv({\n emptyStringAsUndefined: true,\n onValidationError: (errors) => {\n throw new Error(\n errors\n .map(\n (error) => `Environment variable ${error.path} - ${error.message}`,\n )\n .join(\", \"),\n );\n },\n runtimeEnv: process.env,\n server: {\n APPINSIGHTS_SAMPLING_PERCENTAGE: z\n .optional(\n z.coerce\n .number()\n .min(0)\n .max(100)\n .default(5)\n .describe(\n \"Application Insights sampling percentage between 0 and 100. If not set, defaults to 5.\",\n ),\n )\n .transform((value) => {\n const percentage = Number(value);\n return isNaN(percentage) ? 5 : percentage;\n })\n .transform((value) => value / 100),\n APPLICATIONINSIGHTS_CONNECTION_STRING: z\n .string()\n .describe(\"The connection string for Application Insights.\"),\n },\n });\n","import { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\n\n// instrument native node fetch\nexport const registerUndiciInstrumentation = () =>\n new UndiciInstrumentation({\n requestHook: (span, requestInfo) => {\n const { method, origin, path } = requestInfo;\n // Default instrumented attributes don't feed well into AppInsights,\n // so we set them manually.\n span.setAttributes({\n \"http.host\": origin,\n \"http.method\": method,\n \"http.target\": path,\n \"http.url\": `${origin}${path}`,\n });\n },\n responseHook: (span, { response }) => {\n // Same as above, set the status code manually.\n span.setAttribute(\"http.status_code\", response.statusCode);\n },\n });\n"],"mappings":";AAMA,SAAS,mCAAmC;AAC5C,SAAS,gBAAgB;AAOzB,SAAS,SAAS,aAAa;AAC/B,SAAS,gCAAgC;;;ACfzC,SAAS,uBAAuB;;;ACChC,SAAS,iBAAiB;AAC1B,SAAS,SAAS;AAEX,IAAM,UAAU,MACrB,UAAU;AAAA,EACR,wBAAwB;AAAA,EACxB,mBAAmB,CAAC,WAAW;AAC7B,UAAM,IAAI;AAAA,MACR,OACG;AAAA,QACC,CAAC,UAAU,wBAAwB,MAAM,IAAI,MAAM,MAAM,OAAO;AAAA,MAClE,EACC,KAAK,IAAI;AAAA,IACd;AAAA,EACF;AAAA,EACA,YAAY,QAAQ;AAAA,EACpB,QAAQ;AAAA,IACN,iCAAiC,EAC9B;AAAA,MACC,EAAE,OACC,OAAO,EACP,IAAI,CAAC,EACL,IAAI,GAAG,EACP,QAAQ,CAAC,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ,EACC,UAAU,CAAC,UAAU;AACpB,YAAM,aAAa,OAAO,KAAK;AAC/B,aAAO,MAAM,UAAU,IAAI,IAAI;AAAA,IACjC,CAAC,EACA,UAAU,CAAC,UAAU,QAAQ,GAAG;AAAA,IACnC,uCAAuC,EACpC,OAAO,EACP,SAAS,iDAAiD;AAAA,EAC/D;AACF,CAAC;;;ADlCI,IAAM,cAAc,MAAM;AAC/B,QAAM,MAAM,QAAQ;AAEpB,SAAO,gBAAgB;AAAA,IACrB,6BAA6B;AAAA,MAC3B,kBAAkB,IAAI;AAAA,IACxB;AAAA,IACA,mBAAmB;AAAA,IACnB,eAAe,IAAI;AAAA,EACrB,CAAC;AACH;;;AEdA,SAAS,6BAA6B;AAG/B,IAAM,gCAAgC,MAC3C,IAAI,sBAAsB;AAAA,EACxB,aAAa,CAAC,MAAM,gBAAgB;AAClC,UAAM,EAAE,QAAQ,QAAQ,KAAK,IAAI;AAGjC,SAAK,cAAc;AAAA,MACjB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,eAAe;AAAA,MACf,YAAY,GAAG,MAAM,GAAG,IAAI;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EACA,cAAc,CAAC,MAAM,EAAE,SAAS,MAAM;AAEpC,SAAK,aAAa,oBAAoB,SAAS,UAAU;AAAA,EAC3D;AACF,CAAC;;;AHXH,IAAM,EAAE,iBAAiB,+BAA+B,IACtD,4BAA4B;AAE9B,SAAS,iCAAiC,YAAY,KAAK,eAAe;AAQ1E,YAAY;AAEZ,yBAAyB;AAAA,EACvB,kBAAkB,CAAC,8BAA8B,CAAC;AAAA,EAClD,eAAe,QAAQ,iBAAiB;AAAA,EACxC,gBAAgB,MAAM,kBAAkB;AAC1C,CAAC;AAED,MAAM,+BAA+B;","names":[]}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Interface representing the necessary parts of the Azure Functions v3 Context
3
+ * for OpenTelemetry trace context propagation.
4
+ */
5
+ interface FunctionContextV3 {
6
+ traceContext?: {
7
+ traceparent?: null | string;
8
+ tracestate?: null | string;
9
+ };
10
+ }
11
+ /**
12
+ * Wraps an Azure Function v3 handler to propagate OpenTelemetry context.
13
+ *
14
+ * This function extracts trace context from a v3-like context object (simulated via `FunctionContextV3` interface)
15
+ * and runs the provided `v3Function` within that context, ensuring OpenTelemetry trace propagation.
16
+ *
17
+ * @param context The Azure Function v3 context object (or an object conforming to `FunctionContextV3`).
18
+ * @param v3Function The original Azure Function v3 handler function.
19
+ * @returns A new function that, when called with the v3 context, executes the original handler with OpenTelemetry context propagation.
20
+ */
21
+ declare const withOtelContextFunctionV3: <T extends FunctionContextV3>(context: T) => (v3Function: (context: T) => void) => void;
22
+
23
+ export { withOtelContextFunctionV3 };
@@ -0,0 +1,15 @@
1
+ // src/azure/functions/v3/index.ts
2
+ import { context as otelContext, propagation } from "@opentelemetry/api";
3
+ var withOtelContextFunctionV3 = (context) => (v3Function) => {
4
+ const traceContext = context.traceContext ?? {};
5
+ const headers = {
6
+ traceparent: traceContext.traceparent,
7
+ tracestate: traceContext.tracestate
8
+ };
9
+ const ctx = propagation.extract(otelContext.active(), headers);
10
+ return otelContext.with(ctx, () => v3Function(context));
11
+ };
12
+ export {
13
+ withOtelContextFunctionV3
14
+ };
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/azure/functions/v3/index.ts"],"sourcesContent":["import { context as otelContext, propagation } from \"@opentelemetry/api\";\n\n/**\n * Interface representing the necessary parts of the Azure Functions v3 Context\n * for OpenTelemetry trace context propagation.\n */\ninterface FunctionContextV3 {\n traceContext?: {\n traceparent?: null | string;\n tracestate?: null | string;\n };\n}\n\n/**\n * Wraps an Azure Function v3 handler to propagate OpenTelemetry context.\n *\n * This function extracts trace context from a v3-like context object (simulated via `FunctionContextV3` interface)\n * and runs the provided `v3Function` within that context, ensuring OpenTelemetry trace propagation.\n *\n * @param context The Azure Function v3 context object (or an object conforming to `FunctionContextV3`).\n * @param v3Function The original Azure Function v3 handler function.\n * @returns A new function that, when called with the v3 context, executes the original handler with OpenTelemetry context propagation.\n */\nexport const withOtelContextFunctionV3 =\n <T extends FunctionContextV3>(context: T) =>\n (v3Function: (context: T) => void) => {\n const traceContext = context.traceContext ?? {};\n const headers = {\n traceparent: traceContext.traceparent,\n tracestate: traceContext.tracestate,\n };\n\n const ctx = propagation.extract(otelContext.active(), headers);\n return otelContext.with(ctx, () => v3Function(context));\n };\n"],"mappings":";AAAA,SAAS,WAAW,aAAa,mBAAmB;AAuB7C,IAAM,4BACX,CAA8B,YAC9B,CAAC,eAAqC;AACpC,QAAM,eAAe,QAAQ,gBAAgB,CAAC;AAC9C,QAAM,UAAU;AAAA,IACd,aAAa,aAAa;AAAA,IAC1B,YAAY,aAAa;AAAA,EAC3B;AAEA,QAAM,MAAM,YAAY,QAAQ,YAAY,OAAO,GAAG,OAAO;AAC7D,SAAO,YAAY,KAAK,KAAK,MAAM,WAAW,OAAO,CAAC;AACxD;","names":[]}
@@ -0,0 +1,47 @@
1
+ import { AzureMonitorOpenTelemetryOptions } from '@azure/monitor-opentelemetry';
2
+ import { Instrumentation } from '@opentelemetry/instrumentation';
3
+
4
+ /**
5
+ * Initialize the Azure Monitor with the given instrumentations and options.
6
+ * This function sets up telemetry collection for your application by registering
7
+ * the provided instrumentations and configuring Azure Monitor OpenTelemetry.
8
+ *
9
+ * By default, the Undici instrumentation is included. You can extend the functionality
10
+ * by passing additional instrumentations as an array.
11
+ *
12
+ * @remarks
13
+ * - This function should be called at the start of your application to ensure
14
+ * telemetry is collected from the beginning.
15
+ * - If `azureMonitorOptions` is not provided, the configuration will be initialized
16
+ * using environment variables. @see README for more details.
17
+ *
18
+ * @example
19
+ * // Basic usage with default settings
20
+ * import { initAzureMonitor } from "@pagopa/azure-tracing/azure-monitor";
21
+ * initAzureMonitor();
22
+ *
23
+ * @example
24
+ * // Usage with custom instrumentations
25
+ * import { initAzureMonitor } from "@pagopa/azure-tracing/azure-monitor";
26
+ * import { MyCustomInstrumentation } from "my-custom-instrumentation";
27
+ *
28
+ * initAzureMonitor([new MyCustomInstrumentation()]);
29
+ *
30
+ * @example
31
+ * // Usage with custom Azure Monitor options
32
+ * import { initAzureMonitor } from "@pagopa/azure-tracing/azure-monitor";
33
+ *
34
+ * initAzureMonitor([], {
35
+ * azureMonitorExporterOptions: {
36
+ * connectionString: "theConnectionString",
37
+ * },
38
+ * // other options...
39
+ * });
40
+ *
41
+ * @param instrumentations - The list of instrumentations to register with the Azure Monitor.
42
+ * @param azureMonitorOptions - Custom configuration for Azure Monitor. If not provided,
43
+ * it will be initialized using environment variables.
44
+ */
45
+ declare const initAzureMonitor: (instrumentations?: readonly Instrumentation[], azureMonitorOptions?: AzureMonitorOpenTelemetryOptions) => void;
46
+
47
+ export { initAzureMonitor };
@@ -0,0 +1,84 @@
1
+ // src/azure/monitor/index.ts
2
+ import {
3
+ useAzureMonitor as useAzureMonitor2
4
+ } from "@azure/monitor-opentelemetry";
5
+ import { metrics, trace } from "@opentelemetry/api";
6
+ import {
7
+ registerInstrumentations
8
+ } from "@opentelemetry/instrumentation";
9
+
10
+ // src/azure/opentelemetry/azure-undici-instrumentation.ts
11
+ import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
12
+ var registerUndiciInstrumentation = () => new UndiciInstrumentation({
13
+ requestHook: (span, requestInfo) => {
14
+ const { method, origin, path } = requestInfo;
15
+ span.setAttributes({
16
+ "http.host": origin,
17
+ "http.method": method,
18
+ "http.target": path,
19
+ "http.url": `${origin}${path}`
20
+ });
21
+ },
22
+ responseHook: (span, { response }) => {
23
+ span.setAttribute("http.status_code", response.statusCode);
24
+ }
25
+ });
26
+
27
+ // src/azure/monitor/start-from-env.ts
28
+ import { useAzureMonitor } from "@azure/monitor-opentelemetry";
29
+
30
+ // src/azure/monitor/env.ts
31
+ import { createEnv } from "@t3-oss/env-core";
32
+ import { z } from "zod";
33
+ var loadEnv = () => createEnv({
34
+ emptyStringAsUndefined: true,
35
+ onValidationError: (errors) => {
36
+ throw new Error(
37
+ errors.map(
38
+ (error) => `Environment variable ${error.path} - ${error.message}`
39
+ ).join(", ")
40
+ );
41
+ },
42
+ runtimeEnv: process.env,
43
+ server: {
44
+ APPINSIGHTS_SAMPLING_PERCENTAGE: z.optional(
45
+ z.coerce.number().min(0).max(100).default(5).describe(
46
+ "Application Insights sampling percentage between 0 and 100. If not set, defaults to 5."
47
+ )
48
+ ).transform((value) => {
49
+ const percentage = Number(value);
50
+ return isNaN(percentage) ? 5 : percentage;
51
+ }).transform((value) => value / 100),
52
+ APPLICATIONINSIGHTS_CONNECTION_STRING: z.string().describe("The connection string for Application Insights.")
53
+ }
54
+ });
55
+
56
+ // src/azure/monitor/start-from-env.ts
57
+ var initFromEnv = () => {
58
+ const env = loadEnv();
59
+ return useAzureMonitor({
60
+ azureMonitorExporterOptions: {
61
+ connectionString: env.APPLICATIONINSIGHTS_CONNECTION_STRING
62
+ },
63
+ enableLiveMetrics: true,
64
+ samplingRatio: env.APPINSIGHTS_SAMPLING_PERCENTAGE
65
+ });
66
+ };
67
+
68
+ // src/azure/monitor/index.ts
69
+ var initAzureMonitor = (instrumentations = [], azureMonitorOptions) => {
70
+ if (azureMonitorOptions) {
71
+ useAzureMonitor2(azureMonitorOptions);
72
+ } else {
73
+ initFromEnv();
74
+ }
75
+ registerInstrumentations({
76
+ instrumentations: [registerUndiciInstrumentation(), ...instrumentations],
77
+ meterProvider: metrics.getMeterProvider(),
78
+ tracerProvider: trace.getTracerProvider()
79
+ });
80
+ };
81
+ export {
82
+ initAzureMonitor
83
+ };
84
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/azure/monitor/index.ts","../../src/azure/opentelemetry/azure-undici-instrumentation.ts","../../src/azure/monitor/start-from-env.ts","../../src/azure/monitor/env.ts"],"sourcesContent":["import {\n AzureMonitorOpenTelemetryOptions,\n useAzureMonitor,\n} from \"@azure/monitor-opentelemetry\";\nimport { metrics, trace } from \"@opentelemetry/api\";\nimport {\n Instrumentation,\n registerInstrumentations,\n} from \"@opentelemetry/instrumentation\";\n\nimport { registerUndiciInstrumentation } from \"../opentelemetry/azure-undici-instrumentation\";\nimport { initFromEnv } from \"./start-from-env\";\n\n/**\n * Initialize the Azure Monitor with the given instrumentations and options.\n * This function sets up telemetry collection for your application by registering\n * the provided instrumentations and configuring Azure Monitor OpenTelemetry.\n *\n * By default, the Undici instrumentation is included. You can extend the functionality\n * by passing additional instrumentations as an array.\n *\n * @remarks\n * - This function should be called at the start of your application to ensure\n * telemetry is collected from the beginning.\n * - If `azureMonitorOptions` is not provided, the configuration will be initialized\n * using environment variables. @see README for more details.\n *\n * @example\n * // Basic usage with default settings\n * import { initAzureMonitor } from \"@pagopa/azure-tracing/azure-monitor\";\n * initAzureMonitor();\n *\n * @example\n * // Usage with custom instrumentations\n * import { initAzureMonitor } from \"@pagopa/azure-tracing/azure-monitor\";\n * import { MyCustomInstrumentation } from \"my-custom-instrumentation\";\n *\n * initAzureMonitor([new MyCustomInstrumentation()]);\n *\n * @example\n * // Usage with custom Azure Monitor options\n * import { initAzureMonitor } from \"@pagopa/azure-tracing/azure-monitor\";\n *\n * initAzureMonitor([], {\n * azureMonitorExporterOptions: {\n * connectionString: \"theConnectionString\",\n * },\n * // other options...\n * });\n *\n * @param instrumentations - The list of instrumentations to register with the Azure Monitor.\n * @param azureMonitorOptions - Custom configuration for Azure Monitor. If not provided,\n * it will be initialized using environment variables.\n */\nexport const initAzureMonitor = (\n instrumentations: readonly Instrumentation[] = [],\n azureMonitorOptions?: AzureMonitorOpenTelemetryOptions,\n) => {\n if (azureMonitorOptions) {\n useAzureMonitor(azureMonitorOptions);\n } else {\n initFromEnv();\n }\n\n registerInstrumentations({\n instrumentations: [registerUndiciInstrumentation(), ...instrumentations],\n meterProvider: metrics.getMeterProvider(),\n tracerProvider: trace.getTracerProvider(),\n });\n};\n","import { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\n\n// instrument native node fetch\nexport const registerUndiciInstrumentation = () =>\n new UndiciInstrumentation({\n requestHook: (span, requestInfo) => {\n const { method, origin, path } = requestInfo;\n // Default instrumented attributes don't feed well into AppInsights,\n // so we set them manually.\n span.setAttributes({\n \"http.host\": origin,\n \"http.method\": method,\n \"http.target\": path,\n \"http.url\": `${origin}${path}`,\n });\n },\n responseHook: (span, { response }) => {\n // Same as above, set the status code manually.\n span.setAttribute(\"http.status_code\", response.statusCode);\n },\n });\n","import { useAzureMonitor } from \"@azure/monitor-opentelemetry\";\n\nimport { loadEnv } from \"./env\";\n\nexport const initFromEnv = () => {\n const env = loadEnv();\n\n return useAzureMonitor({\n azureMonitorExporterOptions: {\n connectionString: env.APPLICATIONINSIGHTS_CONNECTION_STRING,\n },\n enableLiveMetrics: true,\n samplingRatio: env.APPINSIGHTS_SAMPLING_PERCENTAGE,\n });\n};\n","// Load and type check environment variables on runtime\nimport { createEnv } from \"@t3-oss/env-core\";\nimport { z } from \"zod\";\n\nexport const loadEnv = () =>\n createEnv({\n emptyStringAsUndefined: true,\n onValidationError: (errors) => {\n throw new Error(\n errors\n .map(\n (error) => `Environment variable ${error.path} - ${error.message}`,\n )\n .join(\", \"),\n );\n },\n runtimeEnv: process.env,\n server: {\n APPINSIGHTS_SAMPLING_PERCENTAGE: z\n .optional(\n z.coerce\n .number()\n .min(0)\n .max(100)\n .default(5)\n .describe(\n \"Application Insights sampling percentage between 0 and 100. If not set, defaults to 5.\",\n ),\n )\n .transform((value) => {\n const percentage = Number(value);\n return isNaN(percentage) ? 5 : percentage;\n })\n .transform((value) => value / 100),\n APPLICATIONINSIGHTS_CONNECTION_STRING: z\n .string()\n .describe(\"The connection string for Application Insights.\"),\n },\n });\n"],"mappings":";AAAA;AAAA,EAEE,mBAAAA;AAAA,OACK;AACP,SAAS,SAAS,aAAa;AAC/B;AAAA,EAEE;AAAA,OACK;;;ACRP,SAAS,6BAA6B;AAG/B,IAAM,gCAAgC,MAC3C,IAAI,sBAAsB;AAAA,EACxB,aAAa,CAAC,MAAM,gBAAgB;AAClC,UAAM,EAAE,QAAQ,QAAQ,KAAK,IAAI;AAGjC,SAAK,cAAc;AAAA,MACjB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,eAAe;AAAA,MACf,YAAY,GAAG,MAAM,GAAG,IAAI;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EACA,cAAc,CAAC,MAAM,EAAE,SAAS,MAAM;AAEpC,SAAK,aAAa,oBAAoB,SAAS,UAAU;AAAA,EAC3D;AACF,CAAC;;;ACpBH,SAAS,uBAAuB;;;ACChC,SAAS,iBAAiB;AAC1B,SAAS,SAAS;AAEX,IAAM,UAAU,MACrB,UAAU;AAAA,EACR,wBAAwB;AAAA,EACxB,mBAAmB,CAAC,WAAW;AAC7B,UAAM,IAAI;AAAA,MACR,OACG;AAAA,QACC,CAAC,UAAU,wBAAwB,MAAM,IAAI,MAAM,MAAM,OAAO;AAAA,MAClE,EACC,KAAK,IAAI;AAAA,IACd;AAAA,EACF;AAAA,EACA,YAAY,QAAQ;AAAA,EACpB,QAAQ;AAAA,IACN,iCAAiC,EAC9B;AAAA,MACC,EAAE,OACC,OAAO,EACP,IAAI,CAAC,EACL,IAAI,GAAG,EACP,QAAQ,CAAC,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ,EACC,UAAU,CAAC,UAAU;AACpB,YAAM,aAAa,OAAO,KAAK;AAC/B,aAAO,MAAM,UAAU,IAAI,IAAI;AAAA,IACjC,CAAC,EACA,UAAU,CAAC,UAAU,QAAQ,GAAG;AAAA,IACnC,uCAAuC,EACpC,OAAO,EACP,SAAS,iDAAiD;AAAA,EAC/D;AACF,CAAC;;;ADlCI,IAAM,cAAc,MAAM;AAC/B,QAAM,MAAM,QAAQ;AAEpB,SAAO,gBAAgB;AAAA,IACrB,6BAA6B;AAAA,MAC3B,kBAAkB,IAAI;AAAA,IACxB;AAAA,IACA,mBAAmB;AAAA,IACnB,eAAe,IAAI;AAAA,EACrB,CAAC;AACH;;;AFwCO,IAAM,mBAAmB,CAC9B,mBAA+C,CAAC,GAChD,wBACG;AACH,MAAI,qBAAqB;AACvB,IAAAC,iBAAgB,mBAAmB;AAAA,EACrC,OAAO;AACL,gBAAY;AAAA,EACd;AAEA,2BAAyB;AAAA,IACvB,kBAAkB,CAAC,8BAA8B,GAAG,GAAG,gBAAgB;AAAA,IACvE,eAAe,QAAQ,iBAAiB;AAAA,IACxC,gBAAgB,MAAM,kBAAkB;AAAA,EAC1C,CAAC;AACH;","names":["useAzureMonitor","useAzureMonitor"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Emit a custom event to the Azure Monitor.
3
+ * This function is used to emit custom events to the Azure Monitor.
4
+ *
5
+ * @param eventName the name of the event to emit
6
+ * @param attributes the attributes to include with the event
7
+ */
8
+ declare const emitCustomEvent: (eventName: string, attributes?: Record<string, string>) => (loggerName?: string) => void;
9
+
10
+ export { emitCustomEvent };
@@ -0,0 +1,14 @@
1
+ // src/azure/opentelemetry/logger.ts
2
+ import { logs } from "@opentelemetry/api-logs";
3
+ var emitCustomEvent = (eventName, attributes = {}) => (loggerName = "ApplicationInsightsLogger") => {
4
+ logs.getLogger(loggerName).emit({
5
+ attributes: {
6
+ "microsoft.custom_event.name": eventName,
7
+ ...attributes
8
+ }
9
+ });
10
+ };
11
+ export {
12
+ emitCustomEvent
13
+ };
14
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/azure/opentelemetry/logger.ts"],"sourcesContent":["import { logs } from \"@opentelemetry/api-logs\";\n\n/**\n * Emit a custom event to the Azure Monitor.\n * This function is used to emit custom events to the Azure Monitor.\n *\n * @param eventName the name of the event to emit\n * @param attributes the attributes to include with the event\n */\nexport const emitCustomEvent =\n (eventName: string, attributes: Record<string, string> = {}) =>\n (loggerName = \"ApplicationInsightsLogger\") => {\n logs.getLogger(loggerName).emit({\n attributes: {\n \"microsoft.custom_event.name\": eventName,\n ...attributes,\n },\n });\n };\n"],"mappings":";AAAA,SAAS,YAAY;AASd,IAAM,kBACX,CAAC,WAAmB,aAAqC,CAAC,MAC1D,CAAC,aAAa,gCAAgC;AAC5C,OAAK,UAAU,UAAU,EAAE,KAAK;AAAA,IAC9B,YAAY;AAAA,MACV,+BAA+B;AAAA,MAC/B,GAAG;AAAA,IACL;AAAA,EACF,CAAC;AACH;","names":[]}
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@pagopa/azure-tracing",
3
- "version": "0.4.1-beta.0",
3
+ "version": "0.4.2",
4
4
  "type": "module",
5
5
  "description": "A package that contains some utilities to enable Azure tracing on Node.js applications.",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/pagopa/dx.git",
9
+ "directory": "packages/azure-tracing"
10
+ },
6
11
  "keywords": [
7
12
  "azure",
8
13
  "azuremonitor",
@@ -34,12 +39,12 @@
34
39
  "@azure/monitor-opentelemetry": "^1.11.0",
35
40
  "@azure/monitor-opentelemetry-exporter": "^1.0.0-beta.31",
36
41
  "@opentelemetry/api": "^1.9.0",
37
- "@opentelemetry/api-logs": "^0.202.0",
38
- "@opentelemetry/instrumentation": "^0.202.0",
39
- "@opentelemetry/instrumentation-undici": "^0.13.0",
40
- "@t3-oss/env-core": "^0.13.6",
41
- "import-in-the-middle": "^1.14.0",
42
- "zod": "^3.25.49"
42
+ "@opentelemetry/api-logs": "^0.201.1",
43
+ "@opentelemetry/instrumentation": "^0.201.1",
44
+ "@opentelemetry/instrumentation-undici": "^0.12.0",
45
+ "@t3-oss/env-core": "^0.13.4",
46
+ "import-in-the-middle": "^1.13.2",
47
+ "zod": "^3.25.28"
43
48
  },
44
49
  "devDependencies": {
45
50
  "@pagopa/eslint-config": "workspace:^",