javascript 使用“using”关键字写入文件的一元日志函数

e5nqia27  于 2023-10-14  发布在  Java
关注(0)|答案(1)|浏览(79)

有一个新的上下文管理器。with悄然死去,所以自然是时候重新品牌和复兴了:)
设置:看着新的using关键字,我立即发现了一个场景,它将是一个非常棒的模式。Google Cloud Platform(GCP)的云功能有log()warn()error()。很多时候,我需要先在本地运行它们,有些日志非常广泛。我不想通过终端窗口查看,我想从一个帮助文件导入我自己的这些函数的实现,保持实现语法不变。这将允许我在本地文件夹中拥有用于调试和测试的.log文件。
我一直在努力做到这一点:

// localLogger.ts

import { createWriteStream } from "fs"
import { fileURLToPath } from "url"
import { dirname, join } from "path"

export function wrapLogs(
  callee: string,
  type: "info" | "warn" | "error" = "info"
) {
  const logs: {
    when: string
    logs: string
    payload?: any
  }[] = []
  const __importFile = fileURLToPath(import.meta.url)
  const __logFileDir = dirname(__importFile)
  const __logFile = join(__logFileDir, "../logs", `${type}.log`)
  const stream = createWriteStream(__logFile, {
    flags: "a",
    encoding: "utf8",
  })
  return function (input?: string, payload: any = {}) {
    if (input) {
      const timeStamp = new Date().toISOString().split("T")[1].slice(0, -1)
      logs.push({ when: timeStamp, logs: input })
      if (Object.keys(payload).length) {
        logs[logs.length - 1].payload = payload
      }
    }
    return {
      callee,
      logs,
      done: () => {
        logs.forEach((log) => {
          stream.write(`${log.when} - [${callee}] - ${type}: ${log.logs}\n`)
          if (log.payload) {
            stream.write(`payload: ${JSON.stringify(log.payload, null, 2)}\n`)
          }
        })
        stream.on("finish", () => {
          console.log("done")
        })
        stream.end()
      },
    }
  }
}

这很接近,但不是雪茄。这个实现需要在每个实现日志记录器的函数的末尾运行.done()方法--这并不理想,因为这为健忘的错误留下了很大的空间。这就是using理论上应该发挥作用的地方。

// implementer.ts
import { wrapLogs } from './localLogger.ts'

function myCloudFuntion(){
 const log = wrapLogs('myCloudFunction')
 // does something and then logs
 const data = { payload: 'relevant data' }
 log("some useful log here", data)
 // more stuff
 log().done() // <- this part i would like to do without
 return
}

所以在理想的世界里,我想这样定义日志记录器:

// localLogger.ts

...
// last return of the wrapLogs definition

    return {
      callee,
      logs,
      [Symbol.dispose]() {
        logs.forEach((log) => {
          stream.write(`${log.when} - [${callee}] - ${type}: ${log.logs}\n`)
          if (log.payload) {
            stream.write(`payload: ${JSON.stringify(log.payload, null, 2)}\n`)
          }
        })
        stream.on("finish", () => {
          console.log("done")
        })
        stream.end()
      },
    }

在实施文件中:

// implementer.ts

function myCloudFunction(){
  using log = wrapLogs("myCloudFunction")
  //...
  log("some message", data)
  return  // <- no more log().done()
}

不幸的是,这引起了各种各样的问题。欢迎任何帮助。这些是我进入单子领域和using的第一步,所以要温柔:)

qv7cva1a

qv7cva1a1#

看起来你正在尝试使用TypeScript中的using关键字实现一个自定义上下文管理器,类似于Python中的with关键字。虽然TypeScript没有像Python那样内置上下文管理器,但您可以通过一些修改来实现类似的功能。
这里有一种方法,允许您创建自定义日志记录器并自动关闭它们,而无需在实现文件中调用log().done():

1.修改localLogger.ts文件:

localLogger.ts文件中,可以创建一个自定义日志记录器类,它充当上下文管理器。这个类可以管理日志的打开和关闭。

import { createWriteStream } from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";

class Logger {
  private logs: { when: string; logs: string; payload?: any }[] = [];
  private stream: WriteStream;

  constructor(callee: string, type: "info" | "warn" | "error" = "info") {
    this.stream = createWriteStream(this.getLogFilePath(callee, type), {
      flags: "a",
      encoding: "utf8",
    });
  }

  private getLogFilePath(callee: string, type: string): string {
    const importFile = fileURLToPath(import.meta.url);
    const logFileDir = dirname(importFile);
    return join(logFileDir, "../logs", `${type}.log`);
  }

  public log(input?: string, payload: any = {}) {
    if (input) {
      const timeStamp = new Date().toISOString().split("T")[1].slice(0, -1);
      this.logs.push({ when: timeStamp, logs: input });
      if (Object.keys(payload).length) {
        this.logs[this.logs.length - 1].payload = payload;
      }
    }
  }

  public close() {
    this.logs.forEach((log) => {
      this.stream.write(`${log.when} - [${callee}] - info: ${log.logs}\n`);
      if (log.payload) {
        this.stream.write(`payload: ${JSON.stringify(log.payload, null, 2)}\n`);
      }
    });
    this.stream.end();
  }
}

export function wrapLogs(callee: string) {
  return new Logger(callee);
}

2.在您的implementer.ts文件中实现日志:

现在,在您的实现文件中,您可以使用wrapLogs函数来创建一个logger并自动关闭它,而无需显式调用log().done()

import { wrapLogs } from './localLogger.ts';

function myCloudFunction() {
  const log = wrapLogs('myCloudFunction');
  // ...
  log.log("some message", data);
  return; // The logger will automatically close when it goes out of scope
}

使用这种方法,您可以创建一个Logger类,用于处理打开、记录和关闭日志。日志记录器在超出作用域时自动关闭,这样就不需要在实现文件中显式调用log().done()

相关问题