Skip to content

Commit

Permalink
Add a new, quieter logger.
Browse files Browse the repository at this point in the history
  • Loading branch information
rictic committed Aug 30, 2023
1 parent 7990bcf commit e8e11a0
Show file tree
Hide file tree
Showing 23 changed files with 1,302 additions and 122 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Versioning](https://semver.org/spec/v2.0.0.html).

<!-- ## [Unreleased] -->

## [Unreleased]

## Added

- The `WIREIT_LOGGER` environment variable can now be used to control the system that writes output the the command line.
- Added a new `quiet` logger that writes a single continuously updating line summarizing progress, and only passes along stdout and stderr from commands if there's a failure.

## [0.10.0] - 2023-07-10

### Added
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -847,13 +847,14 @@ The following syntaxes can be used in the `wireit.<script>.dependencies` array:

The following environment variables affect the behavior of Wireit:

| Variable | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `WIREIT_FAILURES` | [How to handle script failures](#failures-and-errors).<br><br>Options:<br><ul><li>[`no-new`](#failures-and-errors) (default): Allow running scripts to finish, but don't start new ones.</li><li>[`continue`](#continue): Allow running scripts to continue, and start new ones unless any of their dependencies failed.</li><li>[`kill`](#kill): Immediately kill running scripts, and don't start new ones.</li></ul> |
| `WIREIT_PARALLEL` | [Maximum number of scripts to run at one time](#parallelism).<br><br>Defaults to 2×logical CPU cores.<br><br>Must be a positive integer or `infinity`. |
| `WIREIT_CACHE` | [Caching mode](#caching).<br><br>Defaults to `local` unless `CI` is `true`, in which case defaults to `none`.<br><br>Automatically set to `github` by the [`google/wireit@setup-github-actions-caching/v1`](#github-actions-caching) action.<br><br>Options:<ul><li>[`local`](#local-caching): Cache to local disk.</li><li>[`github`](#github-actions-caching): Cache to GitHub Actions.</li><li>`none`: Disable caching.</li></ul> |
| `CI` | Affects the default value of `WIREIT_CACHE`.<br><br>Automatically set to `true` by [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables) and most other CI (continuous integration) services.<br><br>Must be exactly `true`. If unset or any other value, interpreted as `false`. |
| `WIREIT_MAX_OPEN_FILES` | Limits the number of file descriptors Wireit will have open concurrently. Prevents resource exhaustion when checking large numbers of cached files. Set to a lower number if you hit file descriptor limits. |
| Variable | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `WIREIT_FAILURES` | [How to handle script failures](#failures-and-errors).<br><br>Options:<br><ul><li>[`no-new`](#failures-and-errors) (default): Allow running scripts to finish, but don't start new ones.</li><li>[`continue`](#continue): Allow running scripts to continue, and start new ones unless any of their dependencies failed.</li><li>[`kill`](#kill): Immediately kill running scripts, and don't start new ones.</li></ul> |
| `WIREIT_PARALLEL` | [Maximum number of scripts to run at one time](#parallelism).<br><br>Defaults to 2×logical CPU cores.<br><br>Must be a positive integer or `infinity`. |
| `WIREIT_CACHE` | [Caching mode](#caching).<br><br>Defaults to `local` unless `CI` is `true`, in which case defaults to `none`.<br><br>Automatically set to `github` by the [`google/wireit@setup-github-actions-caching/v1`](#github-actions-caching) action.<br><br>Options:<ul><li>[`local`](#local-caching): Cache to local disk.</li><li>[`github`](#github-actions-caching): Cache to GitHub Actions.</li><li>`none`: Disable caching.</li></ul> |
| `CI` | Affects the default value of `WIREIT_CACHE`.<br><br>Automatically set to `true` by [GitHub Actions](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables) and most other CI (continuous integration) services.<br><br>Must be exactly `true`. If unset or any other value, interpreted as `false`. |
| `WIREIT_MAX_OPEN_FILES` | Limits the number of file descriptors Wireit will have open concurrently. Prevents resource exhaustion when checking large numbers of cached files. Set to a lower number if you hit file descriptor limits. |
| `WIREIT_LOGGER` | How to present progress and results on the command line.<br><br>Options:<br><ul><li>`quiet`: writes a single dyanmically updating line summarizing progress. Only passes along stdout and stderr from commands if there's a failure, or if the command is a service. The planned new default, please try it out.</li><li>`simple` (default): A verbose logger that presents clear information about the work that Wireit is doing.</li><li>`metrics`: Like `simple`, but also presents a summary table of results once a command is finished.</li></ul> |

### Glob patterns

Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@
".eslintignore",
".eslintrc.cjs",
"src/**/*.ts",
"vscode-extension/src/**/*.ts"
"vscode-extension/src/**/*.ts",
"tsconfig.json"
],
"output": []
},
Expand Down Expand Up @@ -402,7 +403,7 @@
"pnpm": "^7.0.0",
"prettier": "^2.6.2",
"selfsigned": "^2.0.1",
"typescript": "~5.1.6",
"typescript": "^5.2.2",
"uvu": "^0.5.3",
"vsce": "^2.7.0",
"vscode-languageclient": "^8.0.1",
Expand Down
43 changes: 40 additions & 3 deletions src/cli-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {MetricsLogger} from './logging/metrics-logger.js';
import {ScriptReference} from './config.js';
import {FailureMode} from './executor.js';
import {unreachable} from './util/unreachable.js';
import {Logger} from './logging/logger.js';
import {QuietLogger} from './logging/quiet-logger.js';
import {DefaultLogger} from './logging/default-logger.js';

export const packageDir = await (async (): Promise<string | undefined> => {
// Recent versions of npm set this environment variable that tells us the
Expand Down Expand Up @@ -42,8 +45,6 @@ export const packageDir = await (async (): Promise<string | undefined> => {
}
})();

export const logger = new MetricsLogger(packageDir ?? process.cwd());

export type Agent = 'npm' | 'pnpm' | 'yarnClassic' | 'yarnBerry';

export interface Options {
Expand All @@ -54,6 +55,7 @@ export interface Options {
cache: 'local' | 'github' | 'none';
failureMode: FailureMode;
agent: Agent;
logger: Logger;
}

export const getOptions = (): Result<Options> => {
Expand Down Expand Up @@ -182,6 +184,40 @@ export const getOptions = (): Result<Options> => {
}

const agent = getNpmUserAgent();

const argvOptions = getArgvOptions(script, agent);

const loggerResult = ((): Result<Logger> => {
const packageRoot = packageDir ?? process.cwd();
const str = process.env['WIREIT_LOGGER'];
if (!str) {
return {ok: true, value: new MetricsLogger(packageRoot)};
}
if (str === 'quiet') {
return {ok: true, value: new QuietLogger(packageRoot)};
}
if (str === 'simple') {
return {ok: true, value: new DefaultLogger(packageRoot)};
}
if (str === 'metrics') {
return {ok: true, value: new MetricsLogger(packageRoot)};
}
return {
ok: false,
error: {
reason: 'invalid-usage',
message:
`Expected the WIREIT_LOGGER env variable to be ` +
`"quiet", "simple", or "metrics", got ${JSON.stringify(str)}`,
script,
type: 'failure',
},
};
})();
if (!loggerResult.ok) {
return loggerResult;
}

return {
ok: true,
value: {
Expand All @@ -190,7 +226,8 @@ export const getOptions = (): Result<Options> => {
cache: cacheResult.value,
failureMode: failureModeResult.value,
agent,
...getArgvOptions(script, agent),
logger: loggerResult.value,
...argvOptions,
},
};
};
Expand Down
28 changes: 17 additions & 11 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,11 @@ import {Executor} from './executor.js';
import {WorkerPool} from './util/worker-pool.js';
import {unreachable} from './util/unreachable.js';
import {Failure} from './event.js';
import {logger, getOptions} from './cli-options.js';

const run = async (): Promise<Result<void, Failure[]>> => {
const optionsResult = getOptions();
if (!optionsResult.ok) {
return {ok: false, error: [optionsResult.error]};
}
const options = optionsResult.value;
import {packageDir, getOptions, Options} from './cli-options.js';
import {DefaultLogger} from './logging/default-logger.js';

const run = async (options: Options): Promise<Result<void, Failure[]>> => {
const logger = options.logger;
const workerPool = new WorkerPool(options.numWorkers);

let cache;
Expand Down Expand Up @@ -87,7 +83,7 @@ const run = async (): Promise<Result<void, Failure[]>> => {
await watcher.watch();
return {ok: true, value: undefined};
} else {
const analyzer = new Analyzer(options.agent);
const analyzer = new Analyzer(options.agent, logger);
const {config} = await analyzer.analyze(options.script, options.extraArgs);
if (!config.ok) {
return config;
Expand Down Expand Up @@ -120,10 +116,20 @@ const run = async (): Promise<Result<void, Failure[]>> => {
}
};

const result = await run();
const optionsResult = getOptions();
if (!optionsResult.ok) {
// if we can't figure out our options, we can't figure out what logger
// we should use here, so just use the default logger.
const logger = new DefaultLogger(packageDir ?? process.cwd());
logger.log(optionsResult.error);
process.exit(1);
}

const options = optionsResult.value;
const result = await run(options);
if (!result.ok) {
for (const failure of result.error) {
logger.log(failure);
options.logger.log(failure);
}
process.exitCode = 1;
}
6 changes: 6 additions & 0 deletions src/logging/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ export interface Logger {
// watch mode.
getWatchLogger?(): Logger;
}

/**
* When true, we're debugging the logger itself, so a logger should log with
* more verbosity, and not overwrite previously written lines.
*/
export const DEBUG = Boolean(process.env['WIREIT_DEBUG_LOGGER']);
55 changes: 55 additions & 0 deletions src/logging/quiet-logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {Event} from '../event.js';
import {Logger} from './logger.js';
import {WriteoverLine} from './quiet/writeover-line.js';
import {RunTracker, noChange, nothing} from './quiet/run-tracker.js';

/**
* A {@link Logger} that prints less to the console.
*
* While running, it prints a single line of status text with information about
* how the run is progressing. When the run is complete, it prints a one line
* summary of the results if successful, and logs failures with the
* corresponding script's stderr/stdout if something went wrong.
*/
export class QuietLogger implements Logger {
private runTracker;
private readonly _rootPackage: string;
private readonly _writeoverLine = new WriteoverLine();

constructor(rootPackage: string) {
this._rootPackage = rootPackage;
this.runTracker = new RunTracker(this._rootPackage, this._writeoverLine);
}

printMetrics() {
this._writeoverLine.clearAndStopSpinner();
this.runTracker.printSummary();
}

log(event: Event): void {
if (event.type === 'info' && event.detail === 'watch-run-start') {
this.runTracker = this.runTracker.makeInstanceForNewRun();
}
const line = this.runTracker.getUpdatedMessageAfterEvent(event);
if (line === noChange) {
// nothing to do
} else if (line === nothing) {
this._writeoverLine.clearAndStopSpinner();
} else {
this._writeoverLine.writeLine(line);
}
if (event.type === 'info' && event.detail === 'watch-run-end') {
this.printMetrics();
}
}

getWatchLogger(): Logger {
return this;
}
}
Loading

0 comments on commit e8e11a0

Please sign in to comment.