diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c5bf801a13e..ed238cb2c420 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -803,7 +803,7 @@ importers: version: link:../../monitor/monitor-opentelemetry '@azure/monitor-opentelemetry-exporter': specifier: 1.0.0-beta.39 - version: link:../../monitor/monitor-opentelemetry-exporter + version: 1.0.0-beta.39 '@azure/opentelemetry-instrumentation-azure-sdk': specifier: ^1.0.0-beta.7 version: link:../../instrumentation/opentelemetry-instrumentation-azure-sdk @@ -906,7 +906,7 @@ importers: version: 4.13.0 '@azure/monitor-opentelemetry-exporter': specifier: 1.0.0-beta.39 - version: link:../../monitor/monitor-opentelemetry-exporter + version: 1.0.0-beta.39 '@azure/opentelemetry-instrumentation-azure-sdk': specifier: 1.0.0-beta.7 version: 1.0.0-beta.7 @@ -20263,12 +20263,15 @@ importers: '@azure/core-rest-pipeline': specifier: ^1.22.2 version: link:../../core/core-rest-pipeline + '@azure/functions-opentelemetry-instrumentation': + specifier: ^0.3.0 + version: 0.3.0(@opentelemetry/api@1.9.0) '@azure/logger': specifier: ^1.3.0 version: link:../../core/logger '@azure/monitor-opentelemetry-exporter': specifier: 1.0.0-beta.39 - version: link:../monitor-opentelemetry-exporter + version: 1.0.0-beta.39 '@azure/opentelemetry-instrumentation-azure-sdk': specifier: ^1.0.0-beta.9 version: link:../../instrumentation/opentelemetry-instrumentation-azure-sdk @@ -20590,7 +20593,7 @@ importers: version: 4.13.0 '@azure/monitor-opentelemetry-exporter': specifier: 1.0.0-beta.39 - version: link:../monitor-opentelemetry-exporter + version: 1.0.0-beta.39 '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -20678,7 +20681,7 @@ importers: version: 4.13.0 '@azure/monitor-opentelemetry-exporter': specifier: 1.0.0-beta.39 - version: link:../monitor-opentelemetry-exporter + version: 1.0.0-beta.39 '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -32248,6 +32251,12 @@ packages: resolution: {integrity: sha1-M79pG6baQlmig0OZKCXDrzwO0G4=} engines: {node: '>=18.0'} + '@azure/functions-opentelemetry-instrumentation@0.3.0': + resolution: {integrity: sha1-HucaUrbhq71ltyIdCQEWK1hhnh4=} + engines: {node: '>=18.0'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@azure/functions@3.5.1': resolution: {integrity: sha1-mKxcGPhINf1YId5ATFKrvUWIcfY=} @@ -32279,6 +32288,10 @@ packages: resolution: {integrity: sha1-Cey+hAiSgQAjgn7y2DjyGaUcHDU=} engines: {node: '>=14.0.0'} + '@azure/monitor-opentelemetry-exporter@1.0.0-beta.39': + resolution: {integrity: sha1-s7A+yKgRlkxXsxdEIsmHqsfouOA=} + engines: {node: '>=20.0.0'} + '@azure/msal-browser@4.29.0': resolution: {integrity: sha1-bXEazTtGO0a9rgVEW4NUeBb7j1w=} engines: {node: '>=0.8.0'} @@ -33155,10 +33168,18 @@ packages: resolution: {integrity: sha1-VtOJEBCh+hz2ALqIme1htDrOURw=} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.209.0': + resolution: {integrity: sha1-XzIs39n97T+wBuXWhaN4d8rvhGQ=} + engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.211.0': resolution: {integrity: sha1-MtntmJOZVqhNTi/14BWYy50o10Q=} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.52.1': + resolution: {integrity: sha1-UpBjddpNZMIGsMTLj/ogkhRlTsw=} + engines: {node: '>=14'} + '@opentelemetry/api-logs@0.53.0': resolution: {integrity: sha1-xHjL2BIOwlR7ZO36A6VSz+QhcL4=} engines: {node: '>=14'} @@ -33367,6 +33388,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.52.1': + resolution: {integrity: sha1-Ln5Go4vXr78Dz2iMhisLQ0GLf0g=} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.53.0': resolution: {integrity: sha1-5jaeQBXrURJGik1F043K2n2tiS0=} engines: {node: '>=14'} @@ -37262,6 +37289,14 @@ snapshots: '@azure/functions-extensions-base@0.2.0': {} + '@azure/functions-opentelemetry-instrumentation@0.3.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.209.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + transitivePeerDependencies: + - supports-color + '@azure/functions@3.5.1': dependencies: iconv-lite: 0.6.3 @@ -37355,6 +37390,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@azure/monitor-opentelemetry-exporter@1.0.0-beta.39': + dependencies: + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.205.0 + '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.205.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.40.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@azure/msal-browser@4.29.0': dependencies: '@azure/msal-common': 15.15.0 @@ -38412,10 +38464,18 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.209.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.211.0': dependencies: '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.52.1': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs@0.53.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -38692,6 +38752,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.52.1 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.15.0 + require-in-the-middle: 7.5.2 + semver: 7.7.4 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 diff --git a/sdk/monitor/monitor-opentelemetry/CHANGELOG.md b/sdk/monitor/monitor-opentelemetry/CHANGELOG.md index 1ef653979ed3..2c6a8ac406db 100644 --- a/sdk/monitor/monitor-opentelemetry/CHANGELOG.md +++ b/sdk/monitor/monitor-opentelemetry/CHANGELOG.md @@ -1,11 +1,12 @@ # Release History -## 1.17.0 () +## 1.17.0 (Unreleaseed) ### Features Added - Added support for the AKS resource detector from `@opentelemetry/resource-detector-azure`. - Added `AKS_RESOURCE_DETECTOR_POPULATION` statsbeat feature signal to track when the AKS resource detector successfully populates resource attributes. +- Replaced custom `AzureFunctionsHook` with `@azure/functions-opentelemetry-instrumentation` for Azure Functions context propagation. The new package is maintained by the Azure Functions team and provides additional capabilities including log forwarding and `WorkerOpenTelemetryEnabled` host capability. Added `azureFunctions` to `instrumentationOptions`, allowing the Azure Functions instrumentation to be configured (enabled/disabled) like all other instrumentations. It is enabled by default. ### Bugs Fixed diff --git a/sdk/monitor/monitor-opentelemetry/README.md b/sdk/monitor/monitor-opentelemetry/README.md index fbfb52fb346b..e3bcfa1e0122 100644 --- a/sdk/monitor/monitor-opentelemetry/README.md +++ b/sdk/monitor/monitor-opentelemetry/README.md @@ -102,6 +102,7 @@ const options: AzureMonitorOpenTelemetryOptions = { instrumentationOptions: { // Instrumentations generating traces azureSdk: { enabled: true }, + azureFunctions: { enabled: true }, http: { enabled: true }, mongoDb: { enabled: true }, mySql: { enabled: true }, @@ -155,6 +156,7 @@ useAzureMonitor(options); { http: { enabled: true }, azureSdk: { enabled: true }, + azureFunctions: { enabled: true }, mongoDb: { enabled: true }, mySql: { enabled: true }, postgreSql: { enabled: true }, @@ -248,7 +250,7 @@ process.env["APPLICATIONINSIGHTS_CONFIGURATION_FILE"] = "path/to/customConfig.js The following OpenTelemetry Instrumentation libraries are included as part of Azure Monitor OpenTelemetry. -**Note:** The Azure SDK, MongoDB, MySQL, PostgreSQL, Redis, and Redis-4 instrumentations are enabled by default for distributed tracing. The HTTP/HTTPS instrumentation is also enabled by default. All other instrumentations are disabled by default and can be enabled by setting `enabled: true` in the instrumentation options. +**Note:** The Azure SDK, Azure Functions, MongoDB, MySQL, PostgreSQL, Redis, and Redis-4 instrumentations are enabled by default for distributed tracing. The HTTP/HTTPS instrumentation is also enabled by default. All other instrumentations are disabled by default and can be enabled by setting `enabled: true` in the instrumentation options. > _Warning:_ Instrumentation libraries are based on experimental OpenTelemetry specifications. Microsoft's _preview_ support commitment is to ensure that the following libraries emit data to Azure Monitor Application Insights, but it's possible that breaking changes or experimental mapping will block some data elements. @@ -261,6 +263,7 @@ The following OpenTelemetry Instrumentation libraries are included as part of Az - [Redis](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-redis) - [Redis-4](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-redis-4) - [Azure SDK](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/instrumentation/opentelemetry-instrumentation-azure-sdk) +- [Azure Functions](https://github.com/Azure/azure-functions-nodejs-opentelemetry) ### Metrics diff --git a/sdk/monitor/monitor-opentelemetry/package.json b/sdk/monitor/monitor-opentelemetry/package.json index 55882f8ed1ac..49d00680bb57 100644 --- a/sdk/monitor/monitor-opentelemetry/package.json +++ b/sdk/monitor/monitor-opentelemetry/package.json @@ -2,7 +2,7 @@ "name": "@azure/monitor-opentelemetry", "author": "Microsoft Corporation", "sdk-type": "client", - "version": "1.16.0", + "version": "1.17.0", "description": "Azure Monitor OpenTelemetry (Node.js)", "main": "./dist/commonjs/index.js", "module": "./dist/esm/index.js", @@ -73,6 +73,7 @@ "@azure/core-auth": "^1.10.1", "@azure/core-rest-pipeline": "^1.22.2", "@azure/logger": "^1.3.0", + "@azure/functions-opentelemetry-instrumentation": "^0.3.0", "@azure/monitor-opentelemetry-exporter": "1.0.0-beta.39", "@azure/opentelemetry-instrumentation-azure-sdk": "^1.0.0-beta.9", "@microsoft/applicationinsights-web-snippet": "^1.2.3", diff --git a/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md b/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md index 2fa9d64d9116..4fc1fa0bdd4d 100644 --- a/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md +++ b/sdk/monitor/monitor-opentelemetry/review/monitor-opentelemetry-node.api.md @@ -42,6 +42,7 @@ export function _getSdkInstance(): NodeSDK | undefined; // @public export interface InstrumentationOptions { + azureFunctions?: InstrumentationConfig; azureSdk?: InstrumentationConfig; bunyan?: InstrumentationConfig; http?: InstrumentationConfig; diff --git a/sdk/monitor/monitor-opentelemetry/src/metrics/quickpulse/export/sender.ts b/sdk/monitor/monitor-opentelemetry/src/metrics/quickpulse/export/sender.ts index 27cab01a9188..ce89e1221d89 100644 --- a/sdk/monitor/monitor-opentelemetry/src/metrics/quickpulse/export/sender.ts +++ b/sdk/monitor/monitor-opentelemetry/src/metrics/quickpulse/export/sender.ts @@ -40,7 +40,7 @@ export class QuickpulseSender { private endpointUrl: string; private credential: TokenCredential; private credentialScopes: string[]; - // @ts-expect-error - accessed by tests via bracket notation + // @ts-expect-error - assigned in constructor, accessed by tests via bracket notation private quickpulseClientOptions: { credential?: TokenCredential; credentialScopes?: string[]; diff --git a/sdk/monitor/monitor-opentelemetry/src/shared/config.ts b/sdk/monitor/monitor-opentelemetry/src/shared/config.ts index 143e3bd70670..e34f5cc44e21 100644 --- a/sdk/monitor/monitor-opentelemetry/src/shared/config.ts +++ b/sdk/monitor/monitor-opentelemetry/src/shared/config.ts @@ -83,6 +83,7 @@ export class InternalConfig implements AzureMonitorOpenTelemetryOptions { this.instrumentationOptions = { http: { enabled: true }, azureSdk: { enabled: true }, + azureFunctions: { enabled: true }, mongoDb: { enabled: true }, mySql: { enabled: true }, postgreSql: { enabled: true }, diff --git a/sdk/monitor/monitor-opentelemetry/src/shared/module-cjs.cts b/sdk/monitor/monitor-opentelemetry/src/shared/module-cjs.cts index aa435af3ffbf..95bf5f00defd 100644 --- a/sdk/monitor/monitor-opentelemetry/src/shared/module-cjs.cts +++ b/sdk/monitor/monitor-opentelemetry/src/shared/module-cjs.cts @@ -5,19 +5,6 @@ // As per https://github.com/isaacs/tshy?tab=readme-ov-file#commonjs-dialect-polyfills // Encapsulating the ESM / CommonJS specific implementation as needed. -/** - * A CommonJS module loader for Azure Function Core. - */ -export function loadAzureFunctionCore(): ReturnType { - try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - return require("@azure/functions-core"); - } catch (e) { - // Module not found, this is expected in non-Azure Functions environments - return undefined; - } -} - /** * A polyfill for __dirname in CommonJS * @returns The directory name of the current module. diff --git a/sdk/monitor/monitor-opentelemetry/src/shared/module.ts b/sdk/monitor/monitor-opentelemetry/src/shared/module.ts index 426e70154257..88f98eab8276 100644 --- a/sdk/monitor/monitor-opentelemetry/src/shared/module.ts +++ b/sdk/monitor/monitor-opentelemetry/src/shared/module.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { createRequire } from "node:module"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; @@ -9,21 +8,6 @@ import { fileURLToPath } from "node:url"; // As per https://github.com/isaacs/tshy?tab=readme-ov-file#commonjs-dialect-polyfills // Encapsulating the ESM / CommonJS specific implementation as needed. -/** - * An ESM module loader for Azure Function Core. - * @returns The Azure Functions Core module if it exists, otherwise undefined - */ -export function loadAzureFunctionCore(): ReturnType { - try { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore ESM only output - return createRequire(import.meta.url)("@azure/functions-core"); - } catch (e) { - // Module not found, this is expected in non-Azure Functions environments - return undefined; - } -} - /** * A polyfill for __dirname in ESM. * diff --git a/sdk/monitor/monitor-opentelemetry/src/traces/azureFnHook.ts b/sdk/monitor/monitor-opentelemetry/src/traces/azureFnHook.ts deleted file mode 100644 index af19a72229ba..000000000000 --- a/sdk/monitor/monitor-opentelemetry/src/traces/azureFnHook.ts +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import type { Context as AzureFnV3Context } from "@azure/functions-old"; -import type { InvocationContext as AzureFnV4Context } from "@azure/functions"; -import type { Context as OpenTelemetryContext } from "@opentelemetry/api"; -import { context, propagation } from "@opentelemetry/api"; -import { Logger } from "../shared/logging/index.js"; -import { loadAzureFunctionCore } from "../shared/module.js"; - -type AzureFnContext = AzureFnV3Context & AzureFnV4Context; - -type FunctionCallback = (context: unknown, ...inputs: unknown[]) => unknown; - -/** - * Context on a function that is about to be executed - * This object will be passed to all pre invocation hooks - */ -export interface PreInvocationContext { - /** - * The context object passed to the function - * This object is readonly. You may modify it, but attempting to overwrite it will throw an error - */ - readonly invocationContext: unknown; - - /** - * The input values for this specific invocation. Changes to this array _will_ affect the inputs passed to your function - */ - inputs: any[]; - - /** - * The function callback for this specific invocation. Changes to this value _will_ affect the function itself - */ - functionCallback: FunctionCallback; -} - -export class AzureFunctionsHook { - private _functionsCoreModule: any; - private _preInvocationHook: any; - - constructor() { - try { - this._functionsCoreModule = loadAzureFunctionCore(); - if (this._functionsCoreModule) { - this._addPreInvocationHook(); - } else { - Logger.getInstance().debug( - "@azure/functions-core failed to load, not running in Azure Functions", - ); - } - } catch (error) { - Logger.getInstance().debug( - "@azure/functions-core failed to load, not running in Azure Functions", - ); - } - } - - public shutdown(): void { - if (this._preInvocationHook) { - this._preInvocationHook.dispose(); - this._preInvocationHook = undefined; - } - this._functionsCoreModule = undefined; - } - - private _addPreInvocationHook(): void { - if (!this._preInvocationHook) { - this._preInvocationHook = this._functionsCoreModule.registerHook( - "preInvocation", - // eslint-disable-next-line @typescript-eslint/require-await - async (preInvocationContext: PreInvocationContext) => { - const sharedContext = preInvocationContext.invocationContext; - const traceContext = sharedContext.traceContext; - // Update context to use Azure Functions one - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents - let extractedContext: OpenTelemetryContext | any = null; - try { - if (traceContext) { - extractedContext = propagation.extract(context.active(), { - traceparent: traceContext.traceparent || traceContext.traceParent, - tracestate: traceContext.tracestate || traceContext.traceState, - }); - } - const currentContext = extractedContext || context.active(); - preInvocationContext.functionCallback = context.bind( - currentContext, - preInvocationContext.functionCallback, - ); - } catch (err) { - Logger.getInstance().error("Failed to propagate context in Azure Functions", err); - } - }, - ); - } - } -} diff --git a/sdk/monitor/monitor-opentelemetry/src/traces/handler.ts b/sdk/monitor/monitor-opentelemetry/src/traces/handler.ts index ff15feb477c3..99a9021e6c6c 100644 --- a/sdk/monitor/monitor-opentelemetry/src/traces/handler.ts +++ b/sdk/monitor/monitor-opentelemetry/src/traces/handler.ts @@ -23,7 +23,7 @@ import type { InternalConfig } from "../shared/config.js"; import type { MetricHandler } from "../metrics/handler.js"; import { ignoreOutgoingRequestHook } from "../utils/common.js"; import { AzureMonitorSpanProcessor } from "./spanProcessor.js"; -import { AzureFunctionsHook } from "./azureFnHook.js"; +import { AzureFunctionsInstrumentation } from "@azure/functions-opentelemetry-instrumentation"; import type { Instrumentation } from "@opentelemetry/instrumentation"; import { ApplicationInsightsSampler } from "./sampler.js"; @@ -37,7 +37,6 @@ export class TraceHandler { private _instrumentations: Instrumentation[]; private _config: InternalConfig; private _metricHandler: MetricHandler; - private _azureFunctionsHook: AzureFunctionsHook; private _sampler: Sampler; /** @@ -68,7 +67,6 @@ export class TraceHandler { }; this._batchSpanProcessor = new BatchSpanProcessor(this._azureExporter, bufferConfig); this._azureSpanProcessor = new AzureMonitorSpanProcessor(this._metricHandler); - this._azureFunctionsHook = new AzureFunctionsHook(); this._initializeInstrumentations(); } @@ -92,7 +90,6 @@ export class TraceHandler { * Shutdown handler */ public async shutdown(): Promise { - this._azureFunctionsHook.shutdown(); await this._batchSpanProcessor.shutdown(); await this._azureSpanProcessor.shutdown(); await this._azureExporter.shutdown(); @@ -153,5 +150,10 @@ export class TraceHandler { new RedisInstrumentation(this._config.instrumentationOptions.redis), ); } + if (this._config.instrumentationOptions.azureFunctions?.enabled) { + this._instrumentations.push( + new AzureFunctionsInstrumentation(this._config.instrumentationOptions.azureFunctions), + ); + } } } diff --git a/sdk/monitor/monitor-opentelemetry/src/types.ts b/sdk/monitor/monitor-opentelemetry/src/types.ts index 7b04e2f506d4..3f271d9b1ca8 100644 --- a/sdk/monitor/monitor-opentelemetry/src/types.ts +++ b/sdk/monitor/monitor-opentelemetry/src/types.ts @@ -27,7 +27,7 @@ export interface AzureMonitorOpenTelemetryOptions { enableTraceBasedSamplingForLogs?: boolean; /** Enable Performance Counter feature */ enablePerformanceCounters?: boolean; - /** OpenTelemetry Instrumentations options included as part of Azure Monitor (azureSdk, http, mongoDb, mySql, postgreSql, redis, redis4) */ + /** OpenTelemetry Instrumentations options included as part of Azure Monitor (azureSdk, azureFunctions, http, mongoDb, mySql, postgreSql, redis, redis4) */ instrumentationOptions?: InstrumentationOptions; /** Application Insights Web Instrumentation options (enabled, connectionString, src, config)*/ browserSdkLoaderOptions?: BrowserSdkLoaderOptions; @@ -47,6 +47,8 @@ export interface AzureMonitorOpenTelemetryOptions { export interface InstrumentationOptions { /** Azure SDK Instrumentation Config */ azureSdk?: InstrumentationConfig; + /** Azure Functions Instrumentation Config */ + azureFunctions?: InstrumentationConfig; /** HTTP Instrumentation Config */ http?: InstrumentationConfig; /** MongoDB Instrumentation Config */ diff --git a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/azureFnHook.test.ts b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/azureFnHook.test.ts deleted file mode 100644 index fc601854d555..000000000000 --- a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/azureFnHook.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/* eslint-disable @typescript-eslint/no-require-imports */ - -import type { Context as AzureFnV3Context } from "@azure/functions-old"; -import type { InvocationContext as AzureFnV4Context } from "@azure/functions"; -import type { PreInvocationContext } from "../../../../src/traces/azureFnHook.js"; -import { AzureFunctionsHook } from "../../../../src/traces/azureFnHook.js"; -import { TraceHandler } from "../../../../src/traces/index.js"; -import { Logger } from "../../../../src/shared/logging/index.js"; -import { InternalConfig } from "../../../../src/shared/index.js"; -import { MetricHandler } from "../../../../src/metrics/index.js"; -import { metrics, trace } from "@opentelemetry/api"; -import { vi, describe, it, beforeEach, afterEach, expect, assert, beforeAll } from "vitest"; -import { shutdownAzureMonitor, useAzureMonitor } from "../../../../src/index.js"; - -describe("Library/AzureFunctionsHook", () => { - let metricHandler: MetricHandler; - let handler: TraceHandler; - - afterEach(async () => { - if (metricHandler) { - metricHandler.shutdown(); - } - if (handler) { - handler.shutdown(); - } - metrics.disable(); - trace.disable(); - vi.restoreAllMocks(); - await shutdownAzureMonitor(); - }); - - beforeEach(() => { - useAzureMonitor({ - azureMonitorExporterOptions: { - connectionString: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;", - }, - }); - }); - - it("Hook not added if not running in Azure Functions", () => { - const spy = vi.spyOn(Logger.getInstance(), "debug"); - const hook = new AzureFunctionsHook(); - assert.equal(hook["_functionsCoreModule"], undefined); - expect(spy).toHaveBeenCalledTimes(1); - assert.equal( - spy.mock.calls[0][0], - "@azure/functions-core failed to load, not running in Azure Functions", - ); - }); - - describe("AutoCollection/AzureFunctionsHook load fake Azure Functions Core", () => { - let originalRequire: any; - - const v3Context: Partial = { - invocationId: "testinvocationId", - traceContext: { - traceparent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01", - tracestate: "", - attributes: {}, - }, - }; - - const v4Context: Partial = { - invocationId: "testinvocationId", - traceContext: { - traceParent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01", - traceState: "", - attributes: {}, - }, - }; - - beforeAll(() => { - const Module = require("module"); - originalRequire = Module.prototype.require; - }); - - afterEach(() => { - const Module = require("module"); - Module.prototype.require = originalRequire; - }); - - type PreInvocationCallback = (context: PreInvocationContext) => void | Promise; - - for (const [testModelVersion, testInvocationContext] of [ - ["3.x", v3Context], - ["4.x", v4Context], - ]) { - it(// eslint-disable-next-line @typescript-eslint/no-base-to-string - `[${testModelVersion}] Pre Invokation Hook added if running in Azure Functions and context is propagated`, async () => { - let preInvocationCallback: any; - let preInvocationCalled = false; - - const Module = require("module"); - Module.prototype.require = function () { - // eslint-disable-next-line prefer-rest-params - if (arguments[0] === "@azure/functions-core") { - return { - registerHook(name: string, callback: PreInvocationCallback) { - if (name === "preInvocation") { - preInvocationCalled = true; - preInvocationCallback = callback; - } - }, - }; - } - // eslint-disable-next-line prefer-rest-params, @typescript-eslint/no-unsafe-return - return originalRequire.apply(this, arguments); - }; - - const config = new InternalConfig({}); - config.azureMonitorExporterOptions.connectionString = - "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;"; - metricHandler = new MetricHandler(config); - handler = new TraceHandler(config, metricHandler); - const azureFnHook = new AzureFunctionsHook(); - assert.isDefined(preInvocationCalled, "preInvocationCalled"); - assert.isDefined(azureFnHook, "azureFnHook"); - - // Azure Functions should call preinvocation callback - const preInvocationContext: PreInvocationContext = { - inputs: [], - functionCallback: () => { - const span = trace.getTracer("testTracer").startSpan("test"); - // Context should be propagated here - assert.equal( - (span as any)["_spanContext"]["traceId"], - "0af7651916cd43dd8448eb211c80319c", - ); - assert.isDefined((span as any)["_spanContext"]["spanId"]); - }, - invocationContext: testInvocationContext, - }; - - await preInvocationCallback(preInvocationContext); - preInvocationContext.functionCallback(testInvocationContext); - }); - } - }); -}); diff --git a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/azureFnInstrumentation.test.ts b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/azureFnInstrumentation.test.ts new file mode 100644 index 000000000000..e60efc2b62d3 --- /dev/null +++ b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/azureFnInstrumentation.test.ts @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { AzureFunctionsInstrumentation } from "@azure/functions-opentelemetry-instrumentation"; +import { TraceHandler } from "../../../../src/traces/index.js"; +import { InternalConfig } from "../../../../src/shared/index.js"; +import { MetricHandler } from "../../../../src/metrics/index.js"; +import { metrics, trace } from "@opentelemetry/api"; +import { describe, it, beforeEach, afterEach, assert } from "vitest"; +import { shutdownAzureMonitor, useAzureMonitor } from "../../../../src/index.js"; + +describe("Library/AzureFunctionsInstrumentation", () => { + let metricHandler: MetricHandler; + let handler: TraceHandler; + + afterEach(async () => { + if (metricHandler) { + await metricHandler.shutdown(); + } + if (handler) { + await handler.shutdown(); + } + metrics.disable(); + trace.disable(); + await shutdownAzureMonitor(); + }); + + beforeEach(() => { + useAzureMonitor({ + azureMonitorExporterOptions: { + connectionString: "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;", + }, + }); + }); + + it("AzureFunctionsInstrumentation is included by default", () => { + const config = new InternalConfig({}); + config.azureMonitorExporterOptions.connectionString = + "InstrumentationKey=1aa11111-bbbb-1ccc-8ddd-eeeeffff3333;"; + metricHandler = new MetricHandler(config); + handler = new TraceHandler(config, metricHandler); + const instrumentations = handler.getInstrumentations(); + const azureFnInstrumentation = instrumentations.find( + (i) => i instanceof AzureFunctionsInstrumentation, + ); + assert.isDefined(azureFnInstrumentation, "AzureFunctionsInstrumentation should be registered"); + }); +}); diff --git a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts index 7f743340ccea..5eadb17fc0e8 100644 --- a/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts +++ b/sdk/monitor/monitor-opentelemetry/test/internal/unit/traces/traceHandler.test.ts @@ -360,6 +360,7 @@ describe("Library/TraceHandler", () => { _config.instrumentationOptions = { http: { enabled: false }, azureSdk: { enabled: false }, + azureFunctions: { enabled: false }, mongoDb: { enabled: false }, mySql: { enabled: false }, postgreSql: { enabled: false }, @@ -368,8 +369,9 @@ describe("Library/TraceHandler", () => { }; metricHandler = new MetricHandler(_config); handler = new TraceHandler(_config, metricHandler); - // No instrumentations should be created - expect(handler.getInstrumentations()).toHaveLength(0); + const instrumentations = handler.getInstrumentations(); + expect(instrumentations).toHaveLength(0); + expect(instrumentations[0]).not.toBeInstanceOf(HttpInstrumentation); }); }); }); diff --git a/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts b/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts index cba637b9e2dd..81a9a41cc800 100644 --- a/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts +++ b/sdk/monitor/monitor-opentelemetry/test/snippets.spec.ts @@ -58,6 +58,7 @@ describe("snippets", () => { instrumentationOptions: { // Instrumentations generating traces azureSdk: { enabled: true }, + azureFunctions: { enabled: true }, http: { enabled: true }, mongoDb: { enabled: true }, mySql: { enabled: true },