Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rush] Replay logs for warnings and errors as well #4668

Merged
merged 28 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
fc79a18
fix: replay logs for warnings and errors as well
aramissennyeydd Apr 29, 2024
3da7a34
remove console.log
aramissennyeydd Apr 29, 2024
64be994
add changeset
aramissennyeydd Apr 29, 2024
b8a8d3c
small rework
aramissennyeydd Apr 29, 2024
a6619b2
fix linting issues
aramissennyeydd Apr 29, 2024
f200c55
create a new terminal writer that outputs to a json files that stores…
aramissennyeydd Apr 29, 2024
c2c4ee1
fix linting errors
aramissennyeydd Apr 29, 2024
4f822fe
add comment
aramissennyeydd Apr 30, 2024
8452cfe
Update common/changes/@microsoft/rush/sennyeya-log-replays_2024-04-29…
aramissennyeydd May 1, 2024
d65408d
remove schema check and extract log file name forming
aramissennyeydd May 1, 2024
e1ad58b
update how we're saving the file
aramissennyeydd May 1, 2024
eb83a8d
remove top level gitignore
aramissennyeydd May 1, 2024
f785673
remove unnecessary gitignore changes
aramissennyeydd May 1, 2024
11a29ee
update to a jsonl format
aramissennyeydd May 2, 2024
e20d7af
rework to use async stream pipeline
aramissennyeydd May 2, 2024
8333906
Update build-tests/rush-redis-cobuild-plugin-integration-test/sandbox…
aramissennyeydd May 6, 2024
e481c31
address PR feedback
aramissennyeydd May 6, 2024
2bd0393
remove external dep
aramissennyeydd May 7, 2024
ad2a9c0
fix linting and remove debug log
aramissennyeydd May 7, 2024
58b43ac
fix repo state
aramissennyeydd May 10, 2024
a8a6f93
Update libraries/rush-lib/src/logic/operations/OperationMetadataManag…
aramissennyeydd May 10, 2024
cf60b6b
address PR feedback; move chunk writing to project log writable.
aramissennyeydd May 14, 2024
69bf9c2
fix comment
aramissennyeydd May 14, 2024
7bbc670
remove optional comment
aramissennyeydd May 14, 2024
fbdc6e7
don't log cache output
aramissennyeydd May 14, 2024
bee686c
adjust to .rush folder
aramissennyeydd May 14, 2024
e531b9c
pr adjustments
aramissennyeydd May 23, 2024
970601b
fix linting
aramissennyeydd May 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ common/temp/
common/autoinstallers/*/.npmrc
projects/*/dist/
*.log
node_modules/
node_modules/

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "Fix an issue where warnings and errors were not shown in the build summary for all cobuild agents.",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
10 changes: 6 additions & 4 deletions common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { CommandLineParameterKind } from '@rushstack/ts-command-line';
import { HookMap } from 'tapable';
import { IPackageJson } from '@rushstack/node-core-library';
import { ITerminal } from '@rushstack/terminal';
import type { ITerminalProvider } from '@rushstack/terminal';
import { ITerminalProvider } from '@rushstack/terminal';
import { JsonObject } from '@rushstack/node-core-library';
import { PackageNameParser } from '@rushstack/node-core-library';
import type { StdioSummarizer } from '@rushstack/terminal';
Expand Down Expand Up @@ -567,6 +567,8 @@ export interface _IOperationMetadata {
// (undocumented)
errorLogPath: string;
// (undocumented)
logChunksPath: string;
// (undocumented)
logPath: string;
}

Expand Down Expand Up @@ -912,13 +914,13 @@ export class _OperationMetadataManager {
constructor(options: _IOperationMetadataManagerOptions);
get relativeFilepaths(): string[];
// (undocumented)
saveAsync({ durationInSeconds, cobuildContextId, cobuildRunnerId, logPath, errorLogPath }: _IOperationMetadata): Promise<void>;
saveAsync({ durationInSeconds, cobuildContextId, cobuildRunnerId, logPath, errorLogPath, logChunksPath }: _IOperationMetadata): Promise<void>;
iclanton marked this conversation as resolved.
Show resolved Hide resolved
// (undocumented)
readonly stateFile: _OperationStateFile;
// (undocumented)
tryRestoreAsync({ terminal, logPath, errorLogPath }: {
tryRestoreAsync({ terminal, terminalProvider, errorLogPath }: {
terminalProvider: ITerminalProvider;
terminal: ITerminal;
logPath: string;
errorLogPath: string;
}): Promise<void>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
// has changed happens inside the hashing logic.
//

const { logPath, errorLogPath } = ProjectLogWritable.getLogFilePaths({
const { errorLogPath } = ProjectLogWritable.getLogFilePaths({
project,
logFilenameIdentifier: phase.logFilenameIdentifier
});
Expand All @@ -340,12 +340,17 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
);
if (restoreFromCacheSuccess) {
buildCacheContext.cacheRestored = true;
// Restore the original state of the operation without cache
await operationMetadataManager?.tryRestoreAsync({
terminal: buildCacheTerminal,
logPath,
errorLogPath
});
await runnerContext.runWithTerminalAsync(
async (taskTerminal, terminalProvider) => {
// Restore the original state of the operation without cache
await operationMetadataManager?.tryRestoreAsync({
terminalProvider,
terminal: buildCacheTerminal,
errorLogPath
});
},
{ createLogFile: false }
);
}
return !!restoreFromCacheSuccess;
};
Expand Down Expand Up @@ -448,7 +453,7 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
// Save the metadata to disk
const { logFilenameIdentifier } = phase;
const { duration: durationInSeconds } = stopwatch;
const { logPath, errorLogPath } = ProjectLogWritable.getLogFilePaths({
const { logPath, errorLogPath, logChunksPath } = ProjectLogWritable.getLogFilePaths({
aramissennyeydd marked this conversation as resolved.
Show resolved Hide resolved
project,
logFilenameIdentifier
});
Expand All @@ -457,7 +462,8 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin {
cobuildContextId: cobuildLock?.cobuildConfiguration.cobuildContextId,
cobuildRunnerId: cobuildLock?.cobuildConfiguration.cobuildRunnerId,
logPath,
errorLogPath
errorLogPath,
logChunksPath
});
}

Expand Down
107 changes: 107 additions & 0 deletions libraries/rush-lib/src/logic/operations/LogChunksWritable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import { TerminalWritable, type ITerminalChunk } from '@rushstack/terminal';
import { FileWriter } from '@rushstack/node-core-library';
import type { CollatedTerminal } from '@rushstack/stream-collator';

import type { RushConfigurationProject } from '../../api/RushConfigurationProject';
import { RushConstants } from '../RushConstants';
import { getRelativeLogFilePathBase } from './ProjectLogWritable';

/**
* A new terminal stream that writes all log chunks to a JSON format so they can be faithfully reconstructed
* during build cache restores. This is used for adding warning + error messages in cobuilds where the original
* logs cannot be completely restored from the existing `all.log` and `error.log` files.
*
* Example output:
* libraries/rush-lib/.rush/temp/operations/rush-lib._phase_build.chunks.jsonl
* ```
* {"kind":"O","text":"Invoking: heft run --only build -- --clean \n"}
* {"kind":"O","text":" ---- build started ---- \n"}
* {"kind":"O","text":"[build:clean] Deleted 0 files and 5 folders\n"}
* {"kind":"O","text":"[build:typescript] Using TypeScript version 5.4.2\n"}
* {"kind":"O","text":"[build:lint] Using ESLint version 8.57.0\n"}
* {"kind":"E","text":"[build:lint] Warning: libraries/rush-lib/src/logic/operations/LogChunksWritable.ts:15:7 - (@typescript-eslint/typedef) Expected test to have a type annotation.\n"}
* {"kind":"E","text":"[build:lint] Warning: libraries/rush-lib/src/logic/operations/LogChunksWritable.ts:15:7 - (@typescript-eslint/no-unused-vars) 'test' is assigned a value but never used.\n"}
* {"kind":"O","text":"[build:typescript] Copied 1138 folders or files and linked 0 files\n"}
* {"kind":"O","text":"[build:webpack] Using Webpack version 5.82.1\n"}
* {"kind":"O","text":"[build:webpack] Running Webpack compilation\n"}
* {"kind":"O","text":"[build:api-extractor] Using API Extractor version 7.43.1\n"}
* {"kind":"O","text":"[build:api-extractor] Analysis will use the bundled TypeScript version 5.4.2\n"}
* {"kind":"O","text":"[build:copy-mock-flush-telemetry-plugin] Copied 1260 folders or files and linked 5 files\n"}
* {"kind":"O","text":" ---- build finished (6.856s) ---- \n"}
* {"kind":"O","text":"-------------------- Finished (6.858s) --------------------\n"}
* ```
*
*/
export class LogChunksWritable extends TerminalWritable {
public readonly logChunksPath: string;
public readonly relativeLogChunksPath: string;

private _chunkWriter: FileWriter;
private readonly _terminal: CollatedTerminal;

public constructor(
project: RushConfigurationProject,
terminal: CollatedTerminal,
/**
* A unique identifier for the log file. This is used to generate the prefix for the log file name.
*/
logFilenameIdentifier: string
) {
super();

const { logChunksPath, relativeLogChunksPath } = LogChunksWritable.getLogFilePaths({
project,
logFilenameIdentifier
});
this.logChunksPath = logChunksPath;
this.relativeLogChunksPath = relativeLogChunksPath;

this._terminal = terminal;

this._chunkWriter = FileWriter.open(this.logChunksPath);
}

public static getLogFilePaths({
aramissennyeydd marked this conversation as resolved.
Show resolved Hide resolved
project,
logFilenameIdentifier,
isLegacyLog = false
}: {
project: RushConfigurationProject;
logFilenameIdentifier: string;
isLegacyLog?: boolean;
}): {
logChunksPath: string;
relativeLogChunksPath: string;
} {
const { projectFolder } = project;

const logFileBaseName: string = getRelativeLogFilePathBase(
project,
logFilenameIdentifier,
isLegacyLog,
`.rush/${RushConstants.rushTempFolderName}/operations`
);
const relativeLogChunksPath: string = `${logFileBaseName}.chunks.jsonl`;
aramissennyeydd marked this conversation as resolved.
Show resolved Hide resolved
const logChunksPath: string = `${projectFolder}/${relativeLogChunksPath}`;

return {
logChunksPath,
relativeLogChunksPath
};
}

protected onWriteChunk(chunk: ITerminalChunk): void {
this._chunkWriter.write(JSON.stringify(chunk) + '\n');
}

protected onClose(): void {
try {
this._chunkWriter?.close();
} catch (error) {
this._terminal.writeStderrLine('Failed to close file handle for ' + this._chunkWriter?.filePath);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type { IPhase } from '../../api/CommandLineConfiguration';
import type { RushConfigurationProject } from '../../api/RushConfigurationProject';
import { CollatedTerminalProvider } from '../../utilities/CollatedTerminalProvider';
import { ProjectLogWritable } from './ProjectLogWritable';
import { LogChunksWritable } from './LogChunksWritable';

export interface IOperationExecutionRecordContext {
streamCollator: StreamCollator;
Expand Down Expand Up @@ -199,28 +200,44 @@ export class OperationExecutionRecord implements IOperationRunnerContext {
`${associatedPhase.logFilenameIdentifier}${logFileSuffix}`
)
: undefined;
const logChunksWritable: LogChunksWritable | undefined =
associatedPhase && associatedProject
iclanton marked this conversation as resolved.
Show resolved Hide resolved
? new LogChunksWritable(
associatedProject,
this.collatedWriter.terminal,
`${associatedPhase.logFilenameIdentifier}${logFileSuffix}`
)
: undefined;

const fileWritables: TerminalWritable[] = [projectLogWritable, logChunksWritable].filter(
(writable): writable is ProjectLogWritable | LogChunksWritable => writable !== undefined
);

try {
//#region OPERATION LOGGING
// TERMINAL PIPELINE:
//
// +--> quietModeTransform? --> collatedWriter
// |
// normalizeNewlineTransform --1--> stderrLineTransform --2--> removeColorsTransform --> projectLogWritable
// |
// normalizeNewlineTransform --1--> stderrLineTransform --2--> removeColorsTransform --> fileWritablesSplitter -> projectLogWritable (optional)
// | | -> logChunksWritable (optional)
// +--> stdioSummarizer
aramissennyeydd marked this conversation as resolved.
Show resolved Hide resolved
const destination: TerminalWritable = projectLogWritable
? new SplitterTransform({
destinations: [
new TextRewriterTransform({
destination: projectLogWritable,
removeColors: true,
normalizeNewlines: NewlineKind.OsDefault
}),
stdioSummarizer
]
})
: stdioSummarizer;
const destination: TerminalWritable =
fileWritables.length > 0
? new SplitterTransform({
destinations: [
...fileWritables.map(
(writeable) =>
new TextRewriterTransform({
destination: writeable,
removeColors: true,
normalizeNewlines: NewlineKind.OsDefault
})
),
stdioSummarizer
]
})
: stdioSummarizer;
aramissennyeydd marked this conversation as resolved.
Show resolved Hide resolved

const stderrLineTransform: StderrLineTransform = new StderrLineTransform({
destination,
Expand Down