fix(fetch): remove vm.log.level coupling from verbose fetch logging

Previously, verbose fetch logging would be enabled when vm.log.level was
set to debug or verbose. This created an unexpected coupling between
compiler/transpiler logging levels and runtime fetch verbosity.

Now, verbose fetch logging is only enabled via explicit opt-in:
1. BUN_CONFIG_VERBOSE_FETCH environment variable
2. explicit `verbose: true` or `verbose: "curl"` option in fetch options

This fixes #26724 where users experienced unexpected [fetch] verbose logs
during `bun test` when using testcontainers/dockerode.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Bot
2026-02-04 00:58:47 +00:00
parent ddefa11070
commit be21eaa778
2 changed files with 146 additions and 4 deletions

View File

@@ -219,10 +219,12 @@ fn fetchImpl(
var disable_timeout = false;
var disable_keepalive = false;
var disable_decompression = false;
var verbose: http.HTTPVerboseLevel = if (vm.log.level.atLeast(.debug)) .headers else .none;
if (verbose == .none) {
verbose = vm.getVerboseFetch();
}
// Only enable verbose fetch logging via explicit opt-in:
// 1. BUN_CONFIG_VERBOSE_FETCH environment variable
// 2. explicit `verbose: true` or `verbose: "curl"` option in fetch options
// Note: We no longer check vm.log.level here, as that's for compiler/transpiler
// logging and shouldn't affect runtime fetch verbosity.
var verbose: http.HTTPVerboseLevel = vm.getVerboseFetch();
var proxy: ?ZigURL = null;
var redirect_type: FetchRedirect = FetchRedirect.follow;

View File

@@ -0,0 +1,140 @@
import { describe, expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
describe("issue #26724: verbose fetch logging should not be enabled by default", () => {
test("fetch should not output verbose logs without BUN_CONFIG_VERBOSE_FETCH", async () => {
using dir = tempDir("issue-26724", {
"test.ts": `
const response = await fetch("https://httpbin.org/get");
console.log("status:", response.status);
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "run", "test.ts"],
env: {
...bunEnv,
BUN_CONFIG_VERBOSE_FETCH: undefined, // Explicitly ensure it's not set
},
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should not contain verbose fetch output (> or [fetch])
expect(stderr).not.toContain("[fetch]");
expect(stderr).not.toContain("> HTTP/1.1");
expect(stdout).toContain("status: 200");
expect(exitCode).toBe(0);
});
test("fetch should output verbose logs when BUN_CONFIG_VERBOSE_FETCH=1", async () => {
using dir = tempDir("issue-26724-verbose", {
"test.ts": `
const response = await fetch("https://httpbin.org/get");
console.log("status:", response.status);
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "run", "test.ts"],
env: {
...bunEnv,
BUN_CONFIG_VERBOSE_FETCH: "1",
},
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should contain verbose fetch output
expect(stderr + stdout).toContain("> HTTP/1.1");
expect(stdout).toContain("status: 200");
expect(exitCode).toBe(0);
});
test("node:http requests should not output verbose logs without BUN_CONFIG_VERBOSE_FETCH", async () => {
using dir = tempDir("issue-26724-nodehttp", {
"test.ts": `
import http from 'node:http';
const options = {
hostname: 'httpbin.org',
port: 80,
path: '/get',
method: 'GET',
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
console.log('status:', res.statusCode);
});
});
req.on('error', (err) => {
console.error('error:', err.message);
});
req.end();
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "run", "test.ts"],
env: {
...bunEnv,
BUN_CONFIG_VERBOSE_FETCH: undefined, // Explicitly ensure it's not set
},
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should not contain verbose fetch output (> or [fetch])
expect(stderr).not.toContain("[fetch]");
expect(stderr).not.toContain("> HTTP/1.1");
expect(stdout).toContain("status: 200");
expect(exitCode).toBe(0);
});
test("bun test should not output verbose fetch logs without BUN_CONFIG_VERBOSE_FETCH", async () => {
using dir = tempDir("issue-26724-buntest", {
"fetch.test.ts": `
import { test, expect } from "bun:test";
test("fetch works", async () => {
const response = await fetch("https://httpbin.org/get");
expect(response.status).toBe(200);
});
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "test", "fetch.test.ts"],
env: {
...bunEnv,
BUN_CONFIG_VERBOSE_FETCH: undefined, // Explicitly ensure it's not set
},
cwd: String(dir),
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should not contain verbose fetch output (> or [fetch])
const output = stdout + stderr;
expect(output).not.toContain("[fetch]");
expect(output).not.toContain("> HTTP/1.1");
expect(output).toContain("1 pass");
expect(exitCode).toBe(0);
});
});