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

Intercept workerd logs + write all debug logs to a hidden file #4341

Merged
merged 29 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
edc9754
don't rethrow errors in miniflare Log class
RamIdeas Nov 3, 2023
f0576d7
expose miniflare option: handleRuntimeStdio
RamIdeas Nov 3, 2023
ce37b6f
intercept workerd logs in wrangler
RamIdeas Nov 3, 2023
601987e
write all debug logs to a .wrangler/*.log file
RamIdeas Nov 3, 2023
4e5fbbc
initial heuristic to cleanup workerd logs
RamIdeas Nov 6, 2023
2329368
chore: remove wrangler deps from wrangler's build
RamIdeas Nov 6, 2023
b4e09b1
update heuristic to check for hex stack output
RamIdeas Nov 6, 2023
5f4705b
add tests
RamIdeas Nov 9, 2023
c2b2ebe
protect appendFile calls with mutex
RamIdeas Nov 9, 2023
c06b828
normalise stdout bound local network addresses
RamIdeas Nov 10, 2023
8767864
trim workerd stdout/stderr chunks before logging
RamIdeas Nov 10, 2023
189020b
fix linting
RamIdeas Nov 10, 2023
0a429da
fix tests
RamIdeas Nov 10, 2023
4ab3508
improve observability when waitUntil fails
RamIdeas Nov 10, 2023
b60bef3
change debug log default directory
RamIdeas Nov 13, 2023
d83214b
disable debug log file during jest unit-tests
RamIdeas Nov 13, 2023
1fe136f
update snapshots
RamIdeas Nov 13, 2023
88fbf14
try make test fail on assertion, not waitUntil
RamIdeas Nov 13, 2023
7569353
fix hyperdrive e2e tests
RamIdeas Nov 13, 2023
fd12824
upload debug logs as artifact
RamIdeas Nov 14, 2023
2dfea77
allow user to provide filepath *or* directory
RamIdeas Nov 17, 2023
e5d4c02
log debug-log-file location to terminal on exit
RamIdeas Nov 17, 2023
6b6ecdd
even if intecepted, log chunks from workerd to debug file
RamIdeas Nov 17, 2023
54815c0
fix Miniflare NoOpLog to now throw when logging errors
RamIdeas Nov 20, 2023
cd024dd
try use .wrangler dir in project root before package base path
RamIdeas Nov 20, 2023
a5c8bb5
rename WRANGLER_LOG_DIR to WRANGLER_LOG_PATH
RamIdeas Nov 20, 2023
8200491
add changeset
RamIdeas Nov 20, 2023
ea03a4a
write logs to file unconditionally
RamIdeas Nov 20, 2023
664e4a4
fallback to cwd not package base path
RamIdeas Nov 20, 2023
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
5 changes: 5 additions & 0 deletions .changeset/gentle-pans-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"miniflare": minor
---

Added a `handleRuntimeStdio` which enables wrangler (or any other direct use of Miniflare) to handle the `stdout` and `stderr` streams from the workerd child process. By default, if this option is not provided, the previous behaviour is retained which splits the streams into lines and calls `console.log`/`console.error`.
7 changes: 7 additions & 0 deletions .changeset/weak-peaches-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": minor
---

Wrangler now writes all logs to a .log file in the `.wrangler` directory. Set a directory or specific .log filepath to write logs to with `WRANGLER_LOG_PATH=../Desktop/my-logs/` or `WRANGLER_LOG_PATH=../Desktop/my-logs/my-log-file.log`. When specifying a directory or using the default location, a filename with a timestamp is used.

Wrangler now filters workerd stdout/stderr and marks unactionable messages as debug logs. These debug logs are still observable in the debug log file but will no longer show in the terminal by default without the user setting the env var `WRANGLER_LOG=debug`.
8 changes: 8 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,11 @@ jobs:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.TEST_CLOUDFLARE_ACCOUNT_ID }}
WRANGLER: pnpm --silent --package ${{ steps.find-wrangler.outputs.dir}} dlx wrangler
NODE_OPTIONS: "--max_old_space_size=8192"
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/

- name: Upload debug logs
if: always()
uses: actions/upload-artifact@v3
with:
name: e2e-test-debug-logs-${{ matrix.os }}-${{ matrix.node }}
path: ${{ runner.temp }}/wrangler-debug-logs/
8 changes: 8 additions & 0 deletions .github/workflows/pullrequests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ jobs:
TMP_CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
TMP_CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
NODE_OPTIONS: "--max_old_space_size=8192"
WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/

- name: Upload debug logs
if: always()
uses: actions/upload-artifact@v3
with:
name: e2e-test-debug-logs-${{ matrix.os }}-${{ matrix.node }}
path: ${{ runner.temp }}/wrangler-debug-logs/

- name: Run changeset version tests
run: node .github/changeset-version.test.js
Expand Down
1 change: 1 addition & 0 deletions packages/miniflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,7 @@ export class Miniflare {
requiredSockets,
inspectorAddress,
verbose: this.#sharedOpts.core.verbose,
handleRuntimeStdio: this.#sharedOpts.core.handleRuntimeStdio,
};
const maybeSocketPorts = await this.#runtime.updateConfig(
configBuffer,
Expand Down
4 changes: 4 additions & 0 deletions packages/miniflare/src/plugins/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import assert from "assert";
import { readFileSync } from "fs";
import fs from "fs/promises";
import path from "path";
import { Readable } from "stream";
import tls from "tls";
import { TextEncoder } from "util";
import { bold } from "kleur/colors";
Expand Down Expand Up @@ -137,6 +138,9 @@ export const CoreSharedOptionsSchema = z.object({
verbose: z.boolean().optional(),

log: z.instanceof(Log).optional(),
handleRuntimeStdio: z
.function(z.tuple([z.instanceof(Readable), z.instanceof(Readable)]))
.optional(),

upstream: z.string().optional(),
// TODO: add back validation of cf object
Expand Down
17 changes: 9 additions & 8 deletions packages/miniflare/src/runtime/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface RuntimeOptions {
requiredSockets: SocketIdentifier[];
inspectorAddress?: string;
verbose?: boolean;
handleRuntimeStdio?: (stdout: Readable, stderr: Readable) => void;
}

async function waitForPorts(
Expand Down Expand Up @@ -75,19 +76,17 @@ function waitForExit(process: childProcess.ChildProcess): Promise<void> {
});
}

function pipeOutput(runtime: childProcess.ChildProcessWithoutNullStreams) {
function pipeOutput(stdout: Readable, stderr: Readable) {
// TODO: may want to proxy these and prettify ✨
// We can't just pipe() to `process.stdout/stderr` here, as Ink (used by
// wrangler), only patches the `console.*` methods:
// https://github.com/vadimdemedes/ink/blob/5d24ed8ada593a6c36ea5416f452158461e33ba5/readme.md#patchconsole
// Writing directly to `process.stdout/stderr` would result in graphical
// glitches.
const stdout = rl.createInterface(runtime.stdout);
const stderr = rl.createInterface(runtime.stderr);
stdout.on("line", (data) => console.log(data));
stderr.on("line", (data) => console.error(red(data)));
// runtime.stdout.pipe(process.stdout);
// runtime.stderr.pipe(process.stderr);
rl.createInterface(stdout).on("line", (data) => console.log(data));
rl.createInterface(stderr).on("line", (data) => console.error(red(data)));
// stdout.pipe(process.stdout);
// stderr.pipe(process.stderr);
}

function getRuntimeCommand() {
Expand Down Expand Up @@ -144,7 +143,9 @@ export class Runtime {
});
this.#process = runtimeProcess;
this.#processExitPromise = waitForExit(runtimeProcess);
pipeOutput(runtimeProcess);

const handleRuntimeStdio = options.handleRuntimeStdio ?? pipeOutput;
handleRuntimeStdio(runtimeProcess.stdout, runtimeProcess.stderr);

const controlPipe = runtimeProcess.stdio[3];
assert(controlPipe instanceof Readable);
Expand Down
7 changes: 2 additions & 5 deletions packages/miniflare/src/shared/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ export class Log {

error(message: Error): void {
if (this.level < LogLevel.ERROR) {
// Rethrow message if it won't get logged
throw message;
// Ignore message if it won't get logged
mrbbot marked this conversation as resolved.
Show resolved Hide resolved
} else if (message.stack) {
// Dim internal stack trace lines to highlight user code
const lines = message.stack.split("\n").map(dimInternalStackLine);
Expand Down Expand Up @@ -116,9 +115,7 @@ export class NoOpLog extends Log {

protected log(): void {}

error(message: Error): void {
throw message;
}
error(_message: Error): void {}
}

// Adapted from https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js
Expand Down
4 changes: 2 additions & 2 deletions packages/miniflare/test/http/fetch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ test("fetch: performs http request with form data", async (t) => {
test("fetch: performs web socket upgrade", async (t) => {
const server = await useServer(t, noop, (ws, req) => {
ws.send("hello client");
ws.send(req.headers["user-agent"]);
ws.send(req.headers["user-agent"] ?? "");
ws.addEventListener("message", ({ data }) => ws.send(data));
});
const res = await fetch(server.http, {
Expand All @@ -69,7 +69,7 @@ test("fetch: performs web socket upgrade", async (t) => {
});
test("fetch: performs web socket upgrade with Sec-WebSocket-Protocol header", async (t) => {
const server = await useServer(t, noop, (ws, req) => {
ws.send(req.headers["sec-websocket-protocol"]);
ws.send(req.headers["sec-websocket-protocol"] ?? "");
});
const res = await fetch(server.http, {
headers: {
Expand Down
Loading