Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions .changeset/expose-fluid-runner-helpers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@fluidframework/fluid-runner": minor
"__section": other
---
Expose `createFluidRunnerContainerAndExecute` and `createFluidRunnerLogger` as `@legacy @beta`

The lower-level helpers `createFluidRunnerContainerAndExecute` and `createFluidRunnerLogger` from `@fluidframework/fluid-runner` are now part of the legacy/beta public API surface. Use `createFluidRunnerContainerAndExecute` to load a container from an ODSP snapshot and run caller-provided code against it. Use `createFluidRunnerLogger` to obtain a file-backed telemetry logger that can be passed to `createFluidRunnerContainerAndExecute`.

Check warning on line 7 in .changeset/expose-fluid-runner-helpers.md

View workflow job for this annotation

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Microsoft.Acronyms] 'ODSP' has no definition. Raw Output: {"message": "[Microsoft.Acronyms] 'ODSP' has no definition.", "location": {"path": ".changeset/expose-fluid-runner-helpers.md", "range": {"start": {"line": 7, "column": 253}}}, "severity": "INFO"}

The `IFileLogger` and `IFileLoggerTelemetryOptions` types — already exported from the package — have likewise been promoted from `@internal` to `@legacy @beta` so they can be referenced by consumers of these APIs. The signatures of `createFluidRunnerLogger` and `createFluidRunnerContainerAndExecute` use the public `ITelemetryBaseLogger` type from `@fluidframework/core-interfaces`.

Check failure on line 9 in .changeset/expose-fluid-runner-helpers.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/expose-fluid-runner-helpers.md", "range": {"start": {"line": 9, "column": 94}}}, "severity": "ERROR"}

Check failure on line 9 in .changeset/expose-fluid-runner-helpers.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/expose-fluid-runner-helpers.md", "range": {"start": {"line": 9, "column": 58}}}, "severity": "ERROR"}

For back-compatibility, the previous `@internal` names are retained as `@deprecated` aliases:

- `createContainerAndExecute` → use `createFluidRunnerContainerAndExecute`
- `createLogger` → use `createFluidRunnerLogger`
- `ITelemetryOptions` → use `IFileLoggerTelemetryOptions`

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

```ts

// @beta @legacy
export function createFluidRunnerContainerAndExecute(localOdspSnapshot: string | Uint8Array, fluidFileConverter: IFluidFileConverter, baseLogger: ITelemetryBaseLogger, options?: string, timeout?: number, disableNetworkFetch?: boolean): Promise<string>;

// @beta @legacy
export function createFluidRunnerLogger(filePath: string, options?: IFileLoggerTelemetryOptions): {
logger: ITelemetryBaseLogger;
fileLogger: IFileLogger;
};

// @beta @legacy (undocumented)
export type IExportFileResponse = IExportFileResponseSuccess | IExportFileResponseFailure;

Expand All @@ -25,6 +34,18 @@ export interface IExportFileResponseSuccess {
success: true;
}

// @beta @legacy
export interface IFileLogger extends ITelemetryBaseLogger {
close(): Promise<void>;
}

// @beta @legacy
export interface IFileLoggerTelemetryOptions {
defaultProps?: Record<string, string | number>;
eventsPerFlush?: number;
outputFormat?: OutputFormat;
}

// @beta @legacy
export interface IFluidFileConverter {
execute(container: IContainer, options?: string): Promise<string>;
Expand Down
60 changes: 56 additions & 4 deletions packages/tools/fluid-runner/src/exportFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,23 @@ import {
waitContainerToCatchUp,
type ILoaderProps,
} from "@fluidframework/container-loader/internal";
import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
import { createLocalOdspDocumentServiceFactory } from "@fluidframework/odsp-driver/internal";
import {
type TelemetryLoggerExt,
PerformanceEvent,
createChildLogger,
} from "@fluidframework/telemetry-utils/internal";

import type { IFluidFileConverter } from "./codeLoaderBundle.js";
import { FakeUrlResolver } from "./fakeUrlResolver.js";
/* eslint-disable import-x/no-internal-modules */
import type { ITelemetryOptions } from "./logger/fileLogger.js";
import { createLogger, getTelemetryFileValidationError } from "./logger/loggerUtils.js";
import type { IFileLoggerTelemetryOptions } from "./logger/fileLogger.js";
import {
// eslint-disable-next-line import-x/no-deprecated
createLogger,
getTelemetryFileValidationError,
} from "./logger/loggerUtils.js";
import { getArgsValidationError, getSnapshotFileContent, timeoutPromise } from "./utils.js";
/* eslint-enable import-x/no-internal-modules */

Expand Down Expand Up @@ -50,7 +56,8 @@ export interface IExportFileResponseFailure {
const clientArgsValidationError = "Client_ArgsValidationError";

/**
* Execute code on Container based on ODSP snapshot and write result to file
* Execute code on a Fluid {@link @fluidframework/container-definitions#IContainer} loaded from an ODSP snapshot
* file and write the resulting string to disk.
* @internal
*/
export async function exportFile(
Expand All @@ -59,7 +66,7 @@ export async function exportFile(
outputFile: string,
telemetryFile: string,
options?: string,
telemetryOptions?: ITelemetryOptions,
telemetryOptions?: IFileLoggerTelemetryOptions,
timeout?: number,
disableNetworkFetch?: boolean,
): Promise<IExportFileResponse> {
Expand All @@ -68,6 +75,7 @@ export async function exportFile(
const eventName = clientArgsValidationError;
return { success: false, eventName, errorMessage: telemetryArgError };
}
// eslint-disable-next-line import-x/no-deprecated
const { fileLogger, logger } = createLogger(telemetryFile, telemetryOptions);

try {
Expand Down Expand Up @@ -106,9 +114,53 @@ export async function exportFile(
}
}

/**
* Create a Fluid {@link @fluidframework/container-definitions#IContainer} from an ODSP snapshot and run
* caller-provided code against it.
*
* @remarks
* The container is loaded with `opsBeforeReturn: "cached"` and {@link @fluidframework/container-loader#waitContainerToCatchUp}
* is invoked before {@link IFluidFileConverter.execute} runs. The container is disposed once `execute` resolves
* (or rejects).
*
* @param localOdspSnapshot - The ODSP snapshot to load the container from. May be either the JSON snapshot
* as a string or the binary snapshot as a `Uint8Array`.
* @param fluidFileConverter - Caller-provided code loader and execution logic. See {@link IFluidFileConverter}.
* @param baseLogger - Telemetry logger that will receive events emitted during load and execution. Typically
* obtained from {@link createFluidRunnerLogger}.
* @param options - Opaque, caller-defined string passed through to {@link IFluidFileConverter.execute}.
* @param timeout - Optional timeout in milliseconds. If the operation does not complete within this period
* the returned promise rejects. When omitted, no timeout is applied.
* @param disableNetworkFetch - When `true`, replaces `global.fetch` with an implementation that throws,
* ensuring the container load is fully serviced from the provided snapshot. Defaults to `false`.
* @returns The string result returned by {@link IFluidFileConverter.execute}.
*
* @legacy
* @beta
*/
export async function createFluidRunnerContainerAndExecute(
localOdspSnapshot: string | Uint8Array,
fluidFileConverter: IFluidFileConverter,
baseLogger: ITelemetryBaseLogger,
options?: string,
timeout?: number,
disableNetworkFetch?: boolean,
): Promise<string> {
const logger = createChildLogger({ logger: baseLogger });
return createContainerAndExecute(
localOdspSnapshot,
fluidFileConverter,
logger,
options,
timeout,
disableNetworkFetch,
);
}

/**
* Create the container based on an ODSP snapshot and execute code on it
* @returns result of execution
* @deprecated Use {@link createFluidRunnerContainerAndExecute}.
* @internal
*/
export async function createContainerAndExecute(
Expand Down
5 changes: 4 additions & 1 deletion packages/tools/fluid-runner/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
export type { ICodeLoaderBundle, IFluidFileConverter } from "./codeLoaderBundle.js";
export {
createContainerAndExecute,
createFluidRunnerContainerAndExecute,
Comment thread
kian-thompson marked this conversation as resolved.
exportFile,
type IExportFileResponse,
type IExportFileResponseSuccess,
Expand All @@ -15,10 +16,12 @@ export {
export { fluidRunner } from "./fluidRunner.js";
export {
OutputFormat,
type ITelemetryOptions,
type IFileLoggerTelemetryOptions,
type IFileLogger,
type ITelemetryOptions,
} from "./logger/fileLogger.js";
export {
createFluidRunnerLogger,
Comment thread
kian-thompson marked this conversation as resolved.
createLogger,
getTelemetryFileValidationError,
validateAndParseTelemetryOptions,
Expand Down
15 changes: 12 additions & 3 deletions packages/tools/fluid-runner/src/logger/fileLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";

/**
* Contract for logger that writes telemetry to a file
* @internal
* @legacy
* @beta
*/
export interface IFileLogger extends ITelemetryBaseLogger {
/**
Expand All @@ -27,9 +28,10 @@ export enum OutputFormat {

/**
* Options to provide upon creation of IFileLogger
* @internal
* @legacy
* @beta
*/
export interface ITelemetryOptions {
export interface IFileLoggerTelemetryOptions {
/** Desired output format used to create a specific IFileLogger implementation */
outputFormat?: OutputFormat;

Expand All @@ -47,3 +49,10 @@ export interface ITelemetryOptions {
/** Number of telemetry events per flush to telemetry file */
eventsPerFlush?: number;
}

/**
* Options to provide upon creation of IFileLogger
* @deprecated Use {@link IFileLoggerTelemetryOptions}.
* @internal
*/
export type ITelemetryOptions = IFileLoggerTelemetryOptions;
43 changes: 41 additions & 2 deletions packages/tools/fluid-runner/src/logger/loggerUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,49 @@

import * as fs from "fs";

import type { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
import {
type TelemetryLoggerExt,
createChildLogger,
} from "@fluidframework/telemetry-utils/internal";

import { CSVFileLogger } from "./csvFileLogger.js";
import { type IFileLogger, type ITelemetryOptions, OutputFormat } from "./fileLogger.js";
import {
type IFileLogger,
type IFileLoggerTelemetryOptions,
// eslint-disable-next-line import-x/no-deprecated
type ITelemetryOptions,
OutputFormat,
} from "./fileLogger.js";
import { JSONFileLogger } from "./jsonFileLogger.js";

/**
* Create a telemetry logger wrapped around an {@link IFileLogger} that writes to the given file path.
*
* @remarks
* All telemetry events should be sent through the returned `logger`. The returned `fileLogger` is the
* underlying sink — its `close()` method must be called at the end of execution to flush any buffered
* events to disk.
*
* If `options.outputFormat` is not supplied, telemetry is written as JSON. Use {@link OutputFormat.CSV}
* to write CSV instead. See {@link IFileLoggerTelemetryOptions} for supported options including default
* properties applied to every event and flush batching.
*
* @param filePath - Path to the file telemetry will be written to. Must not already exist.
* @param options - Optional telemetry configuration. See {@link IFileLoggerTelemetryOptions}.
* @returns The wrapped telemetry logger to send events through, and the underlying `IFileLogger`
* which must be closed when telemetry collection is finished.
*
* @legacy
* @beta
*/
export function createFluidRunnerLogger(
filePath: string,
options?: IFileLoggerTelemetryOptions,
): { logger: ITelemetryBaseLogger; fileLogger: IFileLogger } {
return createLogger(filePath, options);
}

/**
* Create an {@link @fluidframework/telemetry-utils#TelemetryLoggerExt} wrapped around provided {@link IFileLogger}.
*
Expand All @@ -26,10 +60,13 @@ import { JSONFileLogger } from "./jsonFileLogger.js";
* Note: if an output format is not supplied, default is JSON.
*
* @returns Both the `IFileLogger` implementation and `TelemetryLoggerExt` wrapper to be called.
*
* @deprecated Use {@link createFluidRunnerLogger}.
* @internal
*/
export function createLogger(
filePath: string,
// eslint-disable-next-line import-x/no-deprecated
options?: ITelemetryOptions,
): { logger: TelemetryLoggerExt; fileLogger: IFileLogger } {
const fileLogger =
Expand Down Expand Up @@ -73,7 +110,9 @@ export function validateAndParseTelemetryOptions(
format?: string,
props?: (string | number)[],
eventsPerFlush?: number,
): { success: false; error: string } | { success: true; telemetryOptions: ITelemetryOptions } {
):
| { success: false; error: string }
| { success: true; telemetryOptions: IFileLoggerTelemetryOptions } {
let outputFormat: OutputFormat | undefined;
const defaultProps: Record<string, string | number> = {};

Expand Down
18 changes: 14 additions & 4 deletions packages/tools/fluid-runner/src/parseBundleAndExportFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@ import * as path from "node:path";
import { PerformanceEvent } from "@fluidframework/telemetry-utils/internal";

import { isCodeLoaderBundle, isFluidFileConverter } from "./codeLoaderBundle.js";
import { type IExportFileResponse, createContainerAndExecute } from "./exportFile.js";
import {
type IExportFileResponse,
// eslint-disable-next-line import-x/no-deprecated
createContainerAndExecute,
} from "./exportFile.js";
/* eslint-disable import-x/no-internal-modules */
import type { ITelemetryOptions } from "./logger/fileLogger.js";
import { createLogger, getTelemetryFileValidationError } from "./logger/loggerUtils.js";
import type { IFileLoggerTelemetryOptions } from "./logger/fileLogger.js";
import {
// eslint-disable-next-line import-x/no-deprecated
createLogger,
getTelemetryFileValidationError,
} from "./logger/loggerUtils.js";
/* eslint-enable import-x/no-internal-modules */
import { getArgsValidationError, getSnapshotFileContent } from "./utils.js";

Expand All @@ -29,7 +37,7 @@ export async function parseBundleAndExportFile(
outputFile: string,
telemetryFile: string,
options?: string,
telemetryOptions?: ITelemetryOptions,
telemetryOptions?: IFileLoggerTelemetryOptions,
timeout?: number,
disableNetworkFetch?: boolean,
): Promise<IExportFileResponse> {
Expand All @@ -38,6 +46,7 @@ export async function parseBundleAndExportFile(
const eventName = clientArgsValidationError;
return { success: false, eventName, errorMessage: telemetryArgError };
}
// eslint-disable-next-line import-x/no-deprecated
const { fileLogger, logger } = createLogger(telemetryFile, telemetryOptions);

try {
Expand Down Expand Up @@ -76,6 +85,7 @@ export async function parseBundleAndExportFile(

fs.writeFileSync(
outputFile,
// eslint-disable-next-line import-x/no-deprecated
await createContainerAndExecute(
getSnapshotFileContent(inputFile),
fluidExport,
Expand Down
4 changes: 2 additions & 2 deletions packages/tools/fluid-runner/src/test/exportFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import path from "path";
import { MockLogger } from "@fluidframework/telemetry-utils/internal";

/* eslint-disable import-x/no-internal-modules */
import { createContainerAndExecute, exportFile } from "../exportFile.js";
import { createFluidRunnerContainerAndExecute, exportFile } from "../exportFile.js";
import { getSnapshotFileContent } from "../utils.js";

import { _dirname } from "./dirname.cjs";
Expand Down Expand Up @@ -56,7 +56,7 @@ describe("exportFile", () => {
});

it("Execution result is correct", async () => {
const result = await createContainerAndExecute(
const result = await createFluidRunnerContainerAndExecute(
getSnapshotFileContent(path.join(snapshotFolder, snapshotFileName)),
fluidExport,
new MockLogger().toTelemetryLogger(),
Expand Down
6 changes: 3 additions & 3 deletions packages/tools/fluid-runner/src/test/loggerUtils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import path from "path";
/* eslint-disable import-x/no-internal-modules */
import { OutputFormat } from "../logger/fileLogger.js";
import {
createLogger,
createFluidRunnerLogger,
getTelemetryFileValidationError,
validateAndParseTelemetryOptions,
} from "../logger/loggerUtils.js";
Expand Down Expand Up @@ -173,10 +173,10 @@ describe("logger utils", () => {
});
});

describe("createLogger", () => {
describe("createFluidRunnerLogger", () => {
[-1, 0, 1, 25].forEach((eventsPerFlush) => {
it(`sets eventsPerFlush [${eventsPerFlush}] properly`, () => {
const { fileLogger } = createLogger("fake/path", {
const { fileLogger } = createFluidRunnerLogger("fake/path", {
outputFormat: OutputFormat.CSV,
eventsPerFlush,
});
Expand Down
Loading