Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
39098a7
feat: added new info and essential values to LogLevel
MarioJGMsoft Apr 6, 2026
6b94dcf
Merge remote-tracking branch 'origin/main' into marioja/LogLevelBaseU…
MarioJGMsoft Apr 6, 2026
ece7c02
feat: updated api.md's
MarioJGMsoft Apr 6, 2026
23ebb02
docs: fixed unnecesarry comment
MarioJGMsoft Apr 6, 2026
d94c06f
Merge branch 'main' into marioja/LogLevelBaseUpdate
MarioJGMsoft Apr 7, 2026
cc3386f
feat: added new logLevel values
MarioJGMsoft Apr 7, 2026
01f622e
fix: fixed failing build
MarioJGMsoft Apr 8, 2026
118fd64
fix: removed unnecessary call to LogLevel
MarioJGMsoft Apr 8, 2026
836a899
docs: reverted default comment
MarioJGMsoft Apr 8, 2026
c52caa9
Merge branch 'main' into marioja/LogLevelBaseUpdate
MarioJGMsoft Apr 8, 2026
404e8dd
fix: change minLogLevel from essential to info for compat reasons
MarioJGMsoft Apr 8, 2026
59d4bb7
fix: updated default to .info for compatibility purposes
MarioJGMsoft Apr 8, 2026
7324872
test: updated test
MarioJGMsoft Apr 8, 2026
13d82d6
Merge branch 'main' into marioja/LogLevelBaseUpdate
MarioJGMsoft Apr 9, 2026
48d6b82
feat: turned PR into naming only PR
MarioJGMsoft Apr 9, 2026
9d79c1e
docs: updated comments based on feedback
MarioJGMsoft Apr 9, 2026
d2fafda
Merge branch 'main' into marioja/LogLevelBaseUpdate
MarioJGMsoft Apr 9, 2026
e53642d
Merge branch 'main' into marioja/LogLevelBaseUpdate
MarioJGMsoft Apr 9, 2026
43b1680
feat: updated comments, changeset and LogLevel.default call places
MarioJGMsoft Apr 9, 2026
4aa890f
feat: removed logLevel from new places and added changeset
MarioJGMsoft Apr 9, 2026
06d316c
docs: updated comments
MarioJGMsoft Apr 9, 2026
aa5af96
docs: updated comments for future plans
MarioJGMsoft Apr 9, 2026
ca62e2a
docs: updated comments
MarioJGMsoft Apr 9, 2026
c6ae5e7
docs: updated comments
MarioJGMsoft Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/tender-poems-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@fluidframework/core-interfaces": minor
"@fluidframework/telemetry-utils": minor
"__section": deprecation
---
Deprecated default and error in LogLevel

Two new `LogLevel` members have been added to `@fluidframework/core-interfaces` to better express intent:

- `LogLevel.info` — replaces `LogLevel.default` (same numeric value). Use this for informational session logs that could be omitted at high telemetry volumes.

Check failure on line 10 in .changeset/tender-poems-float.md

View workflow job for this annotation

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Microsoft.Dashes] Remove the spaces around ' — '. Raw Output: {"message": "[Microsoft.Dashes] Remove the spaces around ' — '.", "location": {"path": ".changeset/tender-poems-float.md", "range": {"start": {"line": 10, "column": 18}}}, "severity": "ERROR"}
- `LogLevel.essential` — replaces `LogLevel.error` (same numeric value). Use this for critical operational events that should always be collected.

Check failure on line 11 in .changeset/tender-poems-float.md

View workflow job for this annotation

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Microsoft.Dashes] Remove the spaces around ' — '. Raw Output: {"message": "[Microsoft.Dashes] Remove the spaces around ' — '.", "location": {"path": ".changeset/tender-poems-float.md", "range": {"start": {"line": 11, "column": 23}}}, "severity": "ERROR"}

`LogLevel.default` and `LogLevel.error` are now `@deprecated` and will be removed in a future release (see [issue #26969](https://github.com/microsoft/FluidFramework/issues/26969) for the removal timeline).

If an event does not have a log level specified, it should be treated as if it were `LogLevel.essential`.

**Migration:**

| Deprecated | Replacement |
|---|---|
| `LogLevel.default` | `LogLevel.info` |
| `LogLevel.error` | `LogLevel.essential` |
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ export type Listeners<T extends object> = {
// @public
export const LogLevel: {
readonly verbose: 10;
readonly info: 20;
readonly essential: 30;
readonly default: 20;
readonly error: 30;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,8 @@ export type Listeners<T extends object> = {
// @public
export const LogLevel: {
readonly verbose: 10;
readonly info: 20;
readonly essential: 30;
readonly default: 20;
readonly error: 30;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ export type Listeners<T extends object> = {
// @public
export const LogLevel: {
readonly verbose: 10;
readonly info: 20;
readonly essential: 30;
readonly default: 20;
readonly error: 30;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ export type Listeners<T extends object> = {
// @public
export const LogLevel: {
readonly verbose: 10;
readonly info: 20;
readonly essential: 30;
readonly default: 20;
readonly error: 30;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ export type Listeners<T extends object> = {
// @public
export const LogLevel: {
readonly verbose: 10;
readonly info: 20;
readonly essential: 30;
readonly default: 20;
readonly error: 30;
};
Expand Down
30 changes: 29 additions & 1 deletion packages/common/core-interfaces/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,36 @@ export interface ITelemetryBaseEvent extends ITelemetryBaseProperties {
* @public
*/
export const LogLevel = {
verbose: 10, // To log any verbose event for example when you are debugging something.
/**
* Chatty logs useful for debugging.
* @remarks They need not be collected in production.
*/
verbose: 10,

/**
* Information about the session.
* @remarks These logs could be omitted in some sessions if needed (e.g. to reduce overall telemetry volume).
* If any are collected from a particular session, all should be.
*/
info: 20,

/**
* Essential information about the operation of Fluid.
* @remarks It is recommended that these should always be collected, even in production, for diagnostic purposes.
* If an event does not have a log level specified, it should be treated as if it were LogLevel.essential.
*/
essential: 30,

/**
* @deprecated Use {@link (LogLevel:variable).info}. If an event does not have a log level specified, it should be treated as if it were LogLevel.essential.
* See {@link https://github.com/microsoft/FluidFramework/issues/26969} for removal timeline.
*/
default: 20, // Default log level

/**
* @deprecated Use {@link (LogLevel:variable).essential}.
* See {@link https://github.com/microsoft/FluidFramework/issues/26969} for removal timeline.
*/
error: 30, // To log errors.
} as const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import {
} from "@fluidframework/azure-client";
import { AttachState } from "@fluidframework/container-definitions";
import { ConnectionState } from "@fluidframework/container-loader";
import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
import { LogLevel } from "@fluidframework/core-interfaces";
import type { ITelemetryBaseLogger, LogLevel } from "@fluidframework/core-interfaces";
import type { ScopeType } from "@fluidframework/driver-definitions/legacy";
import type { ContainerSchema, IFluidContainer } from "@fluidframework/fluid-static";
import {
Expand Down Expand Up @@ -74,7 +73,10 @@ function telemetryEventInterestLevel(eventName: string): "none" | "basic" | "det
return "none";
}

function selectiveVerboseLog(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {
function selectiveVerboseLog(
event: ITelemetryBaseEvent,
logLevel: LogLevel | undefined,
): void {
const interest = telemetryEventInterestLevel(event.eventName);
if (interest === "none") {
return;
Expand All @@ -86,7 +88,7 @@ function selectiveVerboseLog(event: ITelemetryBaseEvent, logLevel?: LogLevel): v
if (interest === "details") {
content.details = event.details;
}
log(`[${logLevel ?? LogLevel.default}]`, content);
log(`[${logLevel ?? "unspecified"}]`, content);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change necessary? What's the intent?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was something that was brought up in the previous PR, where Jason pointed out that this change could be done: Original comment. I'll make it's own PR for it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this change needs to go in this PR because it's using LogLevel.default

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {
// @beta @legacy
export interface ITelemetryLoggerExt extends ITelemetryBaseLogger {
sendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;
sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.default): void;
sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.default): void;
sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.info): void;
sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.info): void;
}

// @beta @legacy (undocumented)
Expand Down
23 changes: 14 additions & 9 deletions packages/utils/telemetry-utils/src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,18 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
* @param error - optional error object to log
* @param logLevel - optional level of the log. It category of event is set as error,
* then the logLevel will be upgraded to be an error.
*
* @remarks The default value for logLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential}.
*/
public sendTelemetryEvent(
event: ITelemetryGenericEventExt,
error?: unknown,
logLevel: typeof LogLevel.verbose | typeof LogLevel.default = LogLevel.default,
logLevel: typeof LogLevel.verbose | typeof LogLevel.info = LogLevel.info,
): void {
this.sendTelemetryEventCore(
{ ...event, category: event.category ?? "generic" },
error,
event.category === "error" ? LogLevel.error : logLevel,
event.category === "error" ? LogLevel.essential : logLevel,
);
}

Expand Down Expand Up @@ -237,7 +239,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
category: "error",
},
error,
LogLevel.error,
LogLevel.essential,
);
}

Expand All @@ -248,11 +250,13 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
* @param error - optional error object to log
* @param logLevel - optional level of the log. It category of event is set as error,
* then the logLevel will be upgraded to be an error.
*
* @remarks The default value for logLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential}.
*/
public sendPerformanceEvent(
event: ITelemetryPerformanceEventExt,
error?: unknown,
logLevel: typeof LogLevel.verbose | typeof LogLevel.default = LogLevel.default,
logLevel: typeof LogLevel.verbose | typeof LogLevel.info = LogLevel.info,
): void {
const perfEvent = {
...event,
Expand All @@ -262,7 +266,7 @@ export abstract class TelemetryLogger implements ITelemetryLoggerExt {
this.sendTelemetryEventCore(
perfEvent,
error,
perfEvent.category === "error" ? LogLevel.error : logLevel,
perfEvent.category === "error" ? LogLevel.essential : logLevel,
);
}

Expand Down Expand Up @@ -459,8 +463,9 @@ export class ChildLogger extends TelemetryLogger {
}

private shouldFilterOutEvent(event: ITelemetryBaseEvent, logLevel?: LogLevel): boolean {
const eventLogLevel = logLevel ?? LogLevel.default;
const configLogLevel = this.baseLogger.minLogLevel ?? LogLevel.default;
// The default value for eventLogLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential} once issue #26910 is resolved.
const eventLogLevel = logLevel ?? LogLevel.info;
const configLogLevel = this.baseLogger.minLogLevel ?? LogLevel.info;
// Filter out in case event log level is below what is wanted in config.
return eventLogLevel < configLogLevel;
}
Expand Down Expand Up @@ -559,7 +564,7 @@ export class MultiSinkLogger extends TelemetryLogger {

super(namespace, realProperties);
this.loggers = loggers;
this._minLogLevelOfAllLoggers = LogLevel.default;
this._minLogLevelOfAllLoggers = LogLevel.info;
this.calculateMinLogLevel();
}

Expand All @@ -571,7 +576,7 @@ export class MultiSinkLogger extends TelemetryLogger {
if (this.loggers.length > 0) {
const logLevels: LogLevel[] = [];
for (const logger of this.loggers) {
logLevels.push(logger.minLogLevel ?? LogLevel.default);
logLevels.push(logger.minLogLevel ?? LogLevel.info);
}
this._minLogLevelOfAllLoggers = Math.min(...logLevels) as LogLevel;
}
Expand Down
6 changes: 4 additions & 2 deletions packages/utils/telemetry-utils/src/mockLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export class MockLogger implements ITelemetryBaseLogger {
public readonly minLogLevel: LogLevel;

public constructor(minLogLevel?: LogLevel) {
this.minLogLevel = minLogLevel ?? LogLevel.default;
// The default value for logLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential} once issue #26910 is resolved.
this.minLogLevel = minLogLevel ?? LogLevel.info;
}

/**
Expand All @@ -59,7 +60,8 @@ export class MockLogger implements ITelemetryBaseLogger {
* {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}
*/
public send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {
if ((logLevel ?? LogLevel.default) >= this.minLogLevel) {
// The default value for logLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential} once issue #26910 is resolved.
if ((logLevel ?? LogLevel.info) >= this.minLogLevel) {
this._events.push(event);
}
}
Expand Down
12 changes: 8 additions & 4 deletions packages/utils/telemetry-utils/src/telemetryTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,14 @@ export interface ITelemetryLoggerExt extends ITelemetryBaseLogger {
* Send an information telemetry event.
* @param event - Event to send.
* @param error - Optional error object to log.
* @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.default}.
* @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.info}.
*
* @remarks The default value for logLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential} once issue #26910 is resolved.
*/
sendTelemetryEvent(
event: ITelemetryGenericEventExt,
error?: unknown,
logLevel?: typeof LogLevel.verbose | typeof LogLevel.default,
logLevel?: typeof LogLevel.verbose | typeof LogLevel.info,
): void;

/**
Expand All @@ -136,11 +138,13 @@ export interface ITelemetryLoggerExt extends ITelemetryBaseLogger {
* Send a performance telemetry event.
* @param event - Event to send
* @param error - Optional error object to log.
* @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.default}.
* @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.info}.
*
* @remarks The default value for logLevel will be updated to {@link @fluidframework/core-interfaces#LogLevel.essential} once issue #26910 is resolved.
*/
sendPerformanceEvent(
event: ITelemetryPerformanceEventExt,
error?: unknown,
logLevel?: typeof LogLevel.verbose | typeof LogLevel.default,
logLevel?: typeof LogLevel.verbose | typeof LogLevel.info,
): void;
}
17 changes: 10 additions & 7 deletions packages/utils/telemetry-utils/src/test/childLogger.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,15 @@ describe("ChildLogger", () => {
sent = true;
},

minLogLevel: LogLevel.error,
minLogLevel: LogLevel.essential,
};
const childLogger1 = createChildLogger({ logger });

childLogger1.send({ category: "error", eventName: "testEvent" }, LogLevel.error);
childLogger1.send({ category: "error", eventName: "testEvent" }, LogLevel.essential);
assert(sent, "event should be sent");

sent = false;
childLogger1.send({ category: "generic", eventName: "testEvent" }, LogLevel.default);
childLogger1.send({ category: "generic", eventName: "testEvent" }, LogLevel.info);
assert(!sent, "event should not be sent");
});

Expand Down Expand Up @@ -257,10 +257,10 @@ describe("ChildLogger", () => {
}
sent = true;
},
minLogLevel: LogLevel.default,
minLogLevel: LogLevel.info,
};
const multiSinkLogger = createMultiSinkLogger({
loggers: [logger1, new MockLogger(LogLevel.error)],
loggers: [logger1, new MockLogger(LogLevel.info)],
});
const childLogger1 = createChildLogger({
logger: multiSinkLogger,
Expand All @@ -269,7 +269,10 @@ describe("ChildLogger", () => {
childLogger1.send({ category: "generic", eventName: "testEvent" }, LogLevel.verbose);
assert(!sent, "verbose event should not be sent");

childLogger1.send({ category: "generic", eventName: "testEvent" }, LogLevel.default);
assert(sent, "verbose event should be sent");
childLogger1.send({ category: "generic", eventName: "testEvent" }, LogLevel.info);
assert(sent, "info event should be sent");

childLogger1.send({ category: "generic", eventName: "testEvent" }, LogLevel.essential);
assert(sent, "essential event should be sent");
});
});
22 changes: 11 additions & 11 deletions packages/utils/telemetry-utils/src/test/multiSinkLogger.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ describe("MultiSinkLogger", () => {
});

it("MultiSink logger set the logLevel to min logLevel of all loggers", () => {
const logger1 = new MockLogger(LogLevel.error);
const logger2 = new MockLogger(LogLevel.default);
const logger1 = new MockLogger(LogLevel.essential);
const logger2 = new MockLogger(LogLevel.info);
const multiSink = createMultiSinkLogger({
loggers: [createChildLogger({ logger: logger1 }), logger2],
});
assert.strictEqual(
multiSink.minLogLevel,
LogLevel.default,
LogLevel.info,
"Min loglevel should be set correctly",
);

Expand All @@ -86,16 +86,16 @@ describe("MultiSinkLogger", () => {
);
});

it("MultiSink logger set the logLevel to default if not supplied with a log level", () => {
it("MultiSink logger set the logLevel to info if not supplied with a log level", () => {
const logger1 = new MockLogger();
const logger2 = new MockLogger();
const multiSink = createMultiSinkLogger({
loggers: [createChildLogger({ logger: logger1 }), logger2],
});
assert.strictEqual(
multiSink.minLogLevel,
LogLevel.default,
"Min loglevel should be set correctly to default",
LogLevel.info,
"Min loglevel should be set correctly to info",
);
});

Expand All @@ -107,15 +107,15 @@ describe("MultiSinkLogger", () => {
(multiSink as MultiSinkLogger).addLogger(new MockLogger());
assert.strictEqual(
multiSink.minLogLevel,
LogLevel.default,
"Min loglevel should be set correctly to default",
LogLevel.info,
"Min loglevel should be set correctly to info",
);

(multiSink as MultiSinkLogger).addLogger(new MockLogger(LogLevel.default));
(multiSink as MultiSinkLogger).addLogger(new MockLogger(LogLevel.info));
assert.strictEqual(
multiSink.minLogLevel,
LogLevel.default,
"Min loglevel should be set correctly to default",
LogLevel.info,
"Min loglevel should be set correctly to info",
);

(multiSink as MultiSinkLogger).addLogger(new MockLogger(LogLevel.verbose));
Expand Down
Loading