简体   繁体   English

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

[英]No winston log files are created during pre-run check

I have a typescript project using winston and winston-daily-rotate-file.我有一个使用 winston 和 winston-daily-rotate-file 的 typescript 项目。 At the start of the project I check for environment variables that are present.在项目开始时,我检查存在的环境变量。 If not, I want to log the missing variable using logger.error() .如果没有,我想使用logger.error()记录丢失的变量。 But for some reason the error log is never created.但由于某种原因,永远不会创建错误日志。 The logs do appear in my console.日志确实出现在我的控制台中。

Note:笔记:

The logger and function to check environment variables come from a custom npm module, because I want to reuse this logic for all other projects of mine.用于检查环境变量的记录器和 function 来自自定义 npm 模块,因为我想将此逻辑重用于我的所有其他项目。 So the logger is actually placed in node_modules/my-custom-project/util/logger.ts所以记录器实际上是放在 node_modules/my-custom-project/util/logger.ts

Console output:控制台 output:
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"}
node_modules/my-custom-project/util/logger.ts node_modules/my-custom-project/util/logger.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/my-custom-project/util/requireEnvironmentVariables.ts node_modules/my-custom-project/util/requireEnvironmentVariables.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;
};
index.ts索引.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));

I tried the following:我尝试了以下内容:

  • Moving node_modules/my-custom-project/util/logger.ts and node_modules/my-custom-project/util/requireEnvironmentVariables.ts to my local project.node_modules/my-custom-project/util/logger.tsnode_modules/my-custom-project/util/requireEnvironmentVariables.ts到我的本地项目。
  • Calling logger.info() before checking the variables.在检查变量之前调用logger.info() No log files are created.没有创建日志文件。
  • If all environment variables are present, and the first logger.info() is called AFTER this function has ran, it seems to work fine?如果所有环境变量都存在,并且在这个 function 运行之后调用第一个logger.info() ,它似乎工作正常?

Edit:编辑:

I found logger.on method , it can be used to listen to the finish event:我找到了 logger.on 方法,它可以用来监听 finish 事件:

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

But the logs don't exist at that point.但此时日志不存在。 Also, the info parameter here is undefined and useless.此外,这里的 info 参数未定义且无用。

I eventually found out that this issue is hard to solve with the winston logger.我最终发现这个问题很难用 winston logger 解决。 It has an issue open on GitHub about this.它在 GitHub 上有一个关于此的问题 I resorted to pino where I found this example about MultiStreams.我求助于pino ,在那里我找到了这个关于 MultiStreams 的例子 Eventually this was my solution:最终这是我的解决方案:

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;

Then for example in my tests I could do:然后例如在我的测试中我可以这样做:

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

  done();
});

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM