Created
September 12, 2025 08:53
-
-
Save mortenscheel/6c70a5f65bd89dce828643a46e4c702e to your computer and use it in GitHub Desktop.
Tail laravel logs, skipping stack traces
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
const fs = require("fs"); | |
const readline = require("readline"); | |
const { spawn } = require("child_process"); | |
const path = require("path"); | |
// Parse command line arguments | |
const args = process.argv.slice(2); | |
const options = { | |
reset: args.includes("--reset"), | |
all: args.includes("--all"), | |
skipVendor: args.includes("--skip-vendor"), | |
}; | |
console.clear(); | |
// Remove options from args to get potential filepath | |
const filepath = | |
args.filter((arg) => !arg.startsWith("--"))[0] || | |
path.join(process.cwd(), "storage", "logs", "laravel.log"); | |
// Default skip patterns | |
const skippable = [/^#/, /^\[stacktrace\]/, /^"} {"uid"/]; | |
const isSkippable = (line) => { | |
// Don't skip anything if --all is specified | |
if (options.all) return false; | |
// Special handling for --skip-vendor | |
if (options.skipVendor) { | |
if (line.startsWith("#") && line.includes("/vendor")) { | |
return true; | |
} | |
} | |
if (["[", "#"].indexOf(line[0]) === -1) { | |
return true; | |
} | |
// Regular skip patterns | |
return skippable.some((regex) => regex.test(line)); | |
}; | |
// Reset log file if requested | |
if (options.reset && fs.existsSync(filepath)) { | |
try { | |
fs.unlinkSync(filepath); | |
fs.writeFileSync(filepath, "", { flag: "w" }); | |
console.log(`Log file reset: ${filepath}`); | |
} catch (error) { | |
console.error(`Error resetting log file: ${error.message}`); | |
process.exit(1); | |
} | |
} | |
// Validate the file exists | |
if (!fs.existsSync(filepath)) { | |
console.error(`Error: File not found: ${filepath}`); | |
console.error( | |
"Usage: node script.js [filepath] [--reset] [--all] [--skip-vendor]" | |
); | |
process.exit(1); | |
} | |
// Print startup information | |
console.log(`Monitoring: ${filepath}`); | |
if (options.all) { | |
console.log("Mode: Showing all log entries (--all)"); | |
} else if (options.skipVendor) { | |
console.log("Mode: Skipping vendor paths (--skip-vendor)"); | |
} else { | |
console.log("Mode: Standard filtering"); | |
} | |
console.log("Waiting for new log entries..."); | |
// Use tail -f -n 0 to only show new lines (skip existing content) | |
const tail = spawn("tail", ["-f", "-n", "0", filepath]); | |
const rl = readline.createInterface({ | |
input: tail.stdout, | |
crlfDelay: Infinity, | |
}); | |
let skipped = 0; | |
let timeoutId = null; | |
const checkTimeout = () => { | |
if (skipped > 0) { | |
console.log(`${skipped} lines skipped`); | |
skipped = 0; | |
} | |
}; | |
rl.on("line", (line) => { | |
// Clear any existing timeout | |
if (timeoutId) { | |
clearTimeout(timeoutId); | |
} | |
// Set a new timeout | |
timeoutId = setTimeout(checkTimeout, 100); | |
if (isSkippable(line)) { | |
skipped++; | |
} else { | |
if (skipped > 0) { | |
console.log(`${skipped} lines skipped`); | |
skipped = 0; | |
} | |
console.log(line); | |
} | |
}); | |
// Handle errors | |
tail.stderr.on("data", (data) => { | |
console.error(`Error: ${data}`); | |
}); | |
// Handle process exit | |
process.on("SIGINT", () => { | |
if (skipped > 0) { | |
console.log(`${skipped} lines skipped`); | |
} | |
console.log("Monitoring stopped"); | |
tail.kill(); | |
process.exit(0); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment