Skip to content

Commit 95d6fec

Browse files
hectorhdzgCopilot
andauthored
OTel Web SDK Phase 1 (#2715)
* OTel Web SDK Phase 1 * Update shared/otel-core/src/utils/DataCacheHelper.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update shared/otel-core/src/otel/sdk/OTelWebSdk.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Address comments * Update * Addresing comments --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 93ebf41 commit 95d6fec

16 files changed

Lines changed: 1739 additions & 366 deletions

File tree

shared/otel-core/CONTEXT.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,6 @@ export interface IOTelWebSdkConfig {
404404
/** REQUIRED: Logger for SDK internal diagnostics */
405405
logger: IOTelLogger;
406406

407-
/** REQUIRED: Performance timing function (injected for testability) */
408-
performanceNow: () => number;
409-
410407
/** REQUIRED: Span processors for trace pipeline */
411408
spanProcessors: IOTelSpanProcessor[];
412409

shared/otel-core/Tests/Unit/src/index.tests.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { OTelMultiLogRecordProcessorTests } from "./sdk/OTelMultiLogRecordProces
77
import { CommonUtilsTests } from "./sdk/commonUtils.Tests";
88
import { OpenTelemetryErrorsTests } from "./ai/errors.Tests";
99
import { OTelTraceApiTests } from "./trace/traceState.Tests";
10+
import { OTelWebSdkTests } from "./sdk/OTelWebSdk.Tests";
1011

1112
// AppInsightsCommon tests
1213
import { ApplicationInsightsTests } from "./ai/AppInsightsCommon.tests";
@@ -56,6 +57,7 @@ export function runTests() {
5657
new CommonUtilsTests().registerTests();
5758
new OpenTelemetryErrorsTests().registerTests();
5859
new OTelTraceApiTests().registerTests();
60+
new OTelWebSdkTests().registerTests();
5961

6062
new GlobalTestHooks().registerTests();
6163
new DynamicTests().registerTests();

shared/otel-core/Tests/Unit/src/sdk/OTelLoggerProvider.Tests.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export class OTelLoggerProviderTests extends AITestClass {
3939
});
4040

4141
this.testCase({
42-
name: "LoggerProvider: constructor without options should use noop processor by default",
42+
name: "LoggerProvider: constructor without options should use default processor",
4343
test: (): IPromise<void> => {
4444
const provider = createLoggerProvider();
4545
const sharedState = this._getSharedState(provider);
@@ -296,21 +296,14 @@ export class OTelLoggerProviderTests extends AITestClass {
296296
});
297297

298298
this.testCase({
299-
name: "LoggerProvider: shutdown should return noop logger for new requests",
299+
name: "LoggerProvider: shutdown should return null for new requests",
300300
test: (): IPromise<void> => {
301301
const provider = createLoggerProvider();
302302
return createPromise((resolve, reject) => {
303303
provider.shutdown().then(() => {
304304
try {
305305
const logger = provider.getLogger("default", "1.0.0");
306-
Assert.equal(typeof logger.emit, "function", "Logger should expose emit function after shutdown");
307-
let threw = false;
308-
try {
309-
logger.emit({} as IOTelLogRecord);
310-
} catch (e) {
311-
threw = true;
312-
}
313-
Assert.ok(!threw, "Logger emit should not throw after shutdown");
306+
Assert.equal(logger, null, "Logger should be null after shutdown");
314307
resolve();
315308
} catch (e) {
316309
reject(e);
@@ -394,7 +387,7 @@ export class OTelLoggerProviderTests extends AITestClass {
394387

395388
/**
396389
* Creates a mock log record processor for testing purposes.
397-
* This avoids dependency on the noop package.
390+
* This avoids dependency on a separate mock package.
398391
*/
399392
private _createMockProcessor(): IOTelLogRecordProcessor {
400393
return {

shared/otel-core/Tests/Unit/src/sdk/OTelWebSdk.Tests.ts

Lines changed: 1051 additions & 0 deletions
Large diffs are not rendered by default.

shared/otel-core/src/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,6 @@ export { IOTelAttributes, OTelAttributeValue, ExtendedOTelAttributeValue } from
171171
export { OTelException, IOTelExceptionWithCode, IOTelExceptionWithMessage, IOTelExceptionWithName } from "./interfaces/IException";
172172
export { IOTelHrTime, OTelTimeInput } from "./interfaces/IOTelHrTime";
173173
export { createOTelApi } from "./otel/api/OTelApi";
174-
export { OTelSdk } from "./otel/sdk/OTelSdk";
175174

176175
// OpenTelemetry Trace Interfaces
177176
export { ITraceApi } from "./interfaces/otel/trace/IOTelTraceApi";
@@ -194,8 +193,8 @@ export { IOTelErrorHandlers } from "./interfaces/otel/config/IOTelErrorHandlers"
194193
export { ITraceCfg } from "./interfaces/otel/config/IOTelTraceCfg";
195194

196195
// OpenTelemetry SDK Interfaces
197-
export { IOTelSdk } from "./interfaces/otel/IOTelSdk";
198-
export { IOTelSdkCtx } from "./interfaces/otel/IOTelSdkCtx";
196+
export { IOTelWebSdk } from "./interfaces/otel/IOTelWebSdk";
197+
export { IOTelWebSdkConfig } from "./interfaces/otel/config/IOTelWebSdkConfig";
199198

200199
// OpenTelemetry Context
201200
export { createContextManager } from "./otel/api/context/contextManager";
@@ -262,6 +261,9 @@ export { createLogger } from "./otel/sdk/OTelLogger";
262261
export { createMultiLogRecordProcessor } from "./otel/sdk/OTelMultiLogRecordProcessor";
263262
export { loadDefaultConfig, reconfigureLimits } from "./otel/sdk/config";
264263

264+
// SDK Entry Point
265+
export { createOTelWebSdk } from "./otel/sdk/OTelWebSdk";
266+
265267
// ========================================
266268
// Application Insights Common Exports
267269
// ========================================

shared/otel-core/src/interfaces/otel/IOTelSdk.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

shared/otel-core/src/interfaces/otel/IOTelSdkCtx.ts

Lines changed: 0 additions & 57 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { IPromise } from "@nevware21/ts-async";
5+
import { IOTelWebSdkConfig } from "./config/IOTelWebSdkConfig";
6+
import { IOTelLogger } from "./logs/IOTelLogger";
7+
import { IOTelLoggerOptions } from "./logs/IOTelLoggerOptions";
8+
import { IOTelTracer } from "./trace/IOTelTracer";
9+
import { IOTelTracerOptions } from "./trace/IOTelTracerOptions";
10+
11+
/**
12+
* Main interface for the OpenTelemetry Web SDK.
13+
* Provides access to tracer and logger providers, configuration management,
14+
* and complete lifecycle control including unload/cleanup.
15+
*
16+
* @remarks
17+
* - Supports multiple isolated instances without global state
18+
* - All dependencies injected through {@link IOTelWebSdkConfig}
19+
* - Complete unload support — every instance must fully clean up on unload
20+
*
21+
* @example
22+
* ```typescript
23+
* const sdk = createOTelWebSdk({
24+
* resource: myResource,
25+
* errorHandlers: myHandlers,
26+
* contextManager: myContextManager,
27+
* idGenerator: myIdGenerator,
28+
* sampler: myAlwaysOnSampler
29+
* });
30+
*
31+
* // Get a tracer and create spans
32+
* const tracer = sdk.getTracer("my-service");
33+
* const span = tracer.startSpan("operation");
34+
* span.end();
35+
*
36+
* // Get a logger and emit log records
37+
* const logger = sdk.getLogger("my-service");
38+
* logger.emit({ body: "Hello, World!" });
39+
*
40+
* // Cleanup when done
41+
* sdk.shutdown();
42+
* ```
43+
*
44+
* @since 4.0.0
45+
*/
46+
export interface IOTelWebSdk {
47+
/**
48+
* Returns a Tracer for creating spans.
49+
* Tracers are cached by name + version combination — requesting the same
50+
* name and version returns the same Tracer instance.
51+
*
52+
* @param name - The name of the tracer or instrumentation library
53+
* @param version - The version of the tracer or instrumentation library
54+
* @param options - Additional tracer options (e.g., schemaUrl)
55+
* @returns A Tracer with the given name and version, or null if the SDK is shutdown or
56+
* required dependencies are not configured
57+
*
58+
* @example
59+
* ```typescript
60+
* const tracer = sdk.getTracer("my-component", "1.0.0");
61+
* const span = tracer.startSpan("my-operation");
62+
* ```
63+
*/
64+
getTracer(name: string, version?: string, options?: IOTelTracerOptions): IOTelTracer | null;
65+
66+
/**
67+
* Returns a Logger for emitting log records.
68+
* Loggers are cached by name + version + schemaUrl combination —
69+
* requesting the same combination returns the same Logger instance.
70+
*
71+
* @param name - The name of the logger or instrumentation library
72+
* @param version - The version of the logger or instrumentation library
73+
* @param options - Additional logger options (e.g., schemaUrl, scopeAttributes)
74+
* @returns A Logger with the given name and version, or null if the SDK is shutdown
75+
*
76+
* @example
77+
* ```typescript
78+
* const logger = sdk.getLogger("my-component", "1.0.0");
79+
* logger.emit({ body: "Operation completed", severityText: "INFO" });
80+
* ```
81+
*/
82+
getLogger(name: string, version?: string, options?: IOTelLoggerOptions): IOTelLogger | null;
83+
84+
// TODO: Phase 5 - Uncomment when metrics are implemented
85+
// /**
86+
// * Returns a Meter for recording metrics.
87+
// * @param name - The name of the meter or instrumentation library
88+
// * @param version - The version of the meter or instrumentation library
89+
// * @param options - Additional meter options
90+
// * @returns A Meter with the given name and version
91+
// */
92+
// getMeter(name: string, version?: string, options?: IOTelMeterOptions): IOTelMeter;
93+
94+
/**
95+
* Forces all providers to flush any buffered data.
96+
* This is useful before application shutdown to ensure all telemetry
97+
* is exported.
98+
*
99+
* @returns A promise that resolves when the flush is complete
100+
*/
101+
forceFlush(): IPromise<void>;
102+
103+
/**
104+
* Shuts down the SDK and releases all resources.
105+
* After shutdown, the SDK instance is no longer usable — all
106+
* subsequent calls to `getTracer` or `getLogger` will return null.
107+
*
108+
* @remarks
109+
* Shutdown performs the following:
110+
* - Flushes all pending telemetry
111+
* - Shuts down all providers (trace, log)
112+
* - Removes all config change listeners (calls `IUnloadHook.rm()`)
113+
* - Clears all cached instances
114+
*
115+
* @returns A promise that resolves when shutdown is complete
116+
*/
117+
shutdown(): IPromise<void>;
118+
119+
/**
120+
* Gets the current SDK configuration as a live reference.
121+
* Callers should treat the returned configuration as read-only.
122+
*
123+
* @returns The current SDK configuration
124+
*/
125+
getConfig(): Readonly<IOTelWebSdkConfig>;
126+
}

0 commit comments

Comments
 (0)