logging.ts 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { MainLogger } from "electron-log"
  2. import log from "electron-log/main.js"
  3. import { readFileSync, readdirSync, statSync, unlinkSync } from "node:fs"
  4. import { dirname, join } from "node:path"
  5. const MAX_LOG_AGE_DAYS = 7
  6. const TAIL_LINES = 1000
  7. let logger: MainLogger
  8. export const getLogger = () => logger
  9. export function initLogging() {
  10. log.transports.file.maxSize = 5 * 1024 * 1024
  11. initConsoleTransport()
  12. cleanup()
  13. return (logger = log)
  14. }
  15. export function tail(): string {
  16. try {
  17. const path = log.transports.file.getFile().path
  18. const contents = readFileSync(path, "utf8")
  19. const lines = contents.split("\n")
  20. return lines.slice(Math.max(0, lines.length - TAIL_LINES)).join("\n")
  21. } catch {
  22. return ""
  23. }
  24. }
  25. function cleanup() {
  26. const path = log.transports.file.getFile().path
  27. const dir = dirname(path)
  28. const cutoff = Date.now() - MAX_LOG_AGE_DAYS * 24 * 60 * 60 * 1000
  29. for (const entry of readdirSync(dir)) {
  30. const file = join(dir, entry)
  31. try {
  32. const info = statSync(file)
  33. if (!info.isFile()) continue
  34. if (info.mtimeMs < cutoff) unlinkSync(file)
  35. } catch {
  36. continue
  37. }
  38. }
  39. }
  40. function initConsoleTransport() {
  41. const write = log.transports.console.writeFn.bind(log.transports.console)
  42. log.transports.console.writeFn = (options) => {
  43. try {
  44. write(options)
  45. } catch (err) {
  46. if (!isBrokenPipe(err)) throw err
  47. log.transports.console.level = false
  48. }
  49. }
  50. }
  51. function isBrokenPipe(err: unknown) {
  52. return typeof err === "object" && err !== null && "code" in err && err.code === "EPIPE"
  53. }