typescript 运行前检查期间未创建任何winston日志文件

tyky79it  于 2023-01-27  发布在  TypeScript
关注(0)|答案(1)|浏览(166)

我有一个使用winston和winston-daily-rotate-file的打字脚本项目。在项目开始时,我检查是否存在环境变量。如果没有,我想使用logger.error()记录丢失的变量。但由于某种原因,错误日志从未创建。日志确实出现在我的控制台中。

注:

日志记录器和检查环境变量的函数来自一个定制的npm模块,因为我想在我的所有其他项目中重用这个逻辑,所以日志记录器实际上放在node_modules/my-custom-project/util/logger. ts中

控制台输出:
yarn run v1.22.19
$ ts-node src/index.ts
Debugger attached.
info: Starting project Test {"timestamp":"2023-01-19T07:49:53.342Z","type":"start-project"}
error: Missing environment variable DEFAULT_REQUIRED_VARIABLE {"timestamp":"2023-01-19T07:49:53.348Z"}
error: Exiting because of missing environment variables {"data":["DEFAULT_REQUIRED_VARIABLE"],"timestamp":"2023-01-19T07:50:05.447Z"}
节点模块/我的自定义项目/实用程序/日志记录器. ts
import * as winston from "winston";
import DailyRotateFile from "winston-daily-rotate-file";

const infoTransport: DailyRotateFile = new DailyRotateFile({
  level: "info",
  filename: "./logs/%DATE%/combined.log",
  datePattern: "YYYY-MM-DD-HH",
  maxSize: "20m",
  maxFiles: "14d",
  utc: true,
});
const warnTransport: DailyRotateFile = new DailyRotateFile({
  level: "warn",
  filename: "./logs/%DATE%/warn.log",
  datePattern: "YYYY-MM-DD-HH",
  maxSize: "20m",
  maxFiles: "14d",
  utc: true,
});
const errorTransport: DailyRotateFile = new DailyRotateFile({
  level: "error",
  filename: "./logs/%DATE%/error.log",
  datePattern: "YYYY-MM-DD-HH",
  maxSize: "20m",
  maxFiles: "14d",
  utc: true,
});

const logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [infoTransport, warnTransport, errorTransport],
});

if (process.env.NODE_ENV !== "test") {
  logger.add(
    new winston.transports.Console({
      format: winston.format.simple(),
    })
  );
}

export default logger;
node_modules/我的自定义项目/实用程序/要求环境变量. ts
export default (extraVariables: string[]): boolean => {
  let success = false;
  const missing: string[] = [],
    requiredVariables = [
      "DEFAULT_REQUIRED_VARIABLE",
      ...extraVariables,
    ];

  for (let variable of requiredVariables) {
    if (!(variable in process.env)) {
      missing.push(variable);
      logger.error(`Missing environment variable ${variable}`); // <-- no log file create, but log appears in my console?
    }
  }

  if (missing.length > 0) {
    handleError({
      error: {
        message: "Exiting because of missing environment variables",
        data: missing,
      },
      ...
    });
  } else {
    success = true;
  }
  return success;
};
索引. ts
const run = async () => {
  let log: Log = {
    message: `Starting project ${process.env.PROJECT_NAME}`,
    type: "start-project",
    data: new Date().toISOString,
  };
  logger.info(log);
  if (!requireEnvironmentVariables(['NON_DEFAULT_REQUIRED_VARIABLE']) process.exit();
  ...
};

run().catch((error) => handleError(error));
我尝试了以下操作:
  • 正在将node_modules/my-custom-project/util/logger.tsnode_modules/my-custom-project/util/requireEnvironmentVariables.ts移动到我的本地项目。
  • 在检查变量之前调用logger.info()。不创建日志文件。
  • 如果所有环境变量都存在,并且在运行此函数后调用第一个logger.info(),则它似乎工作正常?
编辑:

我找到logger. on方法,它可以用来监听finish事件:

logger.on('finish', (info) => {
  // Still nog logs written here...
})

但是日志在那个时候并不存在,而且这里的info参数是未定义的,没有用。

gr8qqesn

gr8qqesn1#

我最终发现这个问题很难用winston logger解决。它在GitHub上打开了an issue。我求助于pino,在那里我找到了这个关于多流的例子。最终这是我的解决方案:

import { createWriteStream, existsSync, mkdirSync } from "fs";
import path from "path";
import pino, { stdTimeFunctions } from "pino";
import pretty from "pino-pretty";

import getLogDir from "./getLogDir";
import getLogFileName from "./getLogFileName";
import LogSequence from "./LogSequence";

const logSequence = LogSequence.getInstance(),
  logDir = getLogDir();

let nextSequenceNumberFound = false,
  logFileName = getLogFileName(logSequence.sequence),
  logFilePath = "";

// Create logs folder if it does not exist
if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });

// Decide filename with unique sequence, within every hour the sequence gets upped
while (nextSequenceNumberFound === false) {
  logFilePath = path.join(logDir, logFileName);

  // Try to find file with sequence number
  let fileExists = existsSync(logFilePath);

  // If it exists, try to find the next one
  if (fileExists) {
    logSequence.incrementSequence();
    logFileName = getLogFileName(logSequence.sequence);

    // Else, we know what to call the next file
  } else nextSequenceNumberFound = true;
}

const fileStream = createWriteStream(logFilePath),
  streams = [
    { stream: fileStream },
    {
      stream: pretty({
        colorize: true,
        translateTime: true,
        ignore: "pid",
      }),
    },
  ];

const logger = pino(
  {
    enabled:
      process.env.NODE_ENV !== "test" && process.env.NODE_ENV !== "production",
    formatters: {
      level(label) {
        return { level: label };
      },
    },
    level: "debug",
    nestedKey: "payload",
    timestamp: stdTimeFunctions.isoTime,
  },
  pino.multistream(streams)
);

export default logger;

例如,在我的测试中,我可以:

beforeAll((done) => {
  logger.info("Testing...");
  logger.flush();

  done();
});

test("getLog", () => {
  fileStream.once("close", () => {
    // Log files are available here
  });
});

相关问题