pinojs / pino

🌲 super fast, all natural json logger
http://getpino.io
MIT License
14.21k stars 875 forks source link

no such file or directory when setting to different log destination directory #1388

Closed convers39 closed 2 years ago

convers39 commented 2 years ago
const day = dayjs().format('YYYY-MM-DD')
// fs.writeFile(`/app/logs/${day}_logs.log`, '', () => {})

const pinoLogger = pino(
  {
    level: LOG_LEVEL,
    prettyPrint: {
      colorize: true, // colorizes the log
      levelFirst: true,
      translateTime: 'yyyy-mm-dd, h:MM:ss TT'
    }
  },
  // pino.destination(`${__dirname}/${day}_logs.log`) -> create file automatically
  pino.destination(`/app/logs/${day}_logs.log`) -> crashed with no such file or directory 
)

export default pinoLogger

I want to put the log file in a folder in the root dir of my app, the app is running in docker and the root dir is /app.

The problem here is that, when I use the __dirname as the destination, the log file will be created automatically if it does not exist. But when set to the root dir folder, the app will crash with this error:

image

An interesting thing is if I create an empty file manually as server/logs/YYYY-MM-DD_logs.log (the server folder is mapping to /app in the container), the app will not crash and all works fine.

I was trying to create the file with fs.writeFile or fs.writeFileSync but it seems not working.

I don't want to save all logs files in the same folder with my code, is there any hint on this issue?

UPDATE:

  1. when I restart the containers with compose down and up, the file will be created automatically in /app/logsfolder.
  2. If I delete the created file, the app will crash and does not create a new one until I restart he containers
  3. I tried to add chmod 666 /app/logs in the dockerfile and rebuild, but got the same issue.
convers39 commented 2 years ago

Change to the code below and seems working:

const day = dayjs().format('YYYY-MM-DD')

const commonOptions = {
  colorize: true,
  levelFirst: true,
  translateTime: 'SYS:yyyy-mm-dd, hh:MM:ss TT Z'
  // mkdir: true,
  // append: true,
  // sync: false
}

const transport = pino.transport({
  targets: [
    {
      target: 'pino-pretty',
      level: 'info',
      options: {
        ...commonOptions,
        destination: `./logs/${day}_logs.log`
      }
    },
    {
      target: 'pino-pretty',
      level: 'error',
      options: {
        ...commonOptions,
        destination: `./logs/${day}_errors.log`
      }
    }
  ]
})

const pinoLogger = pino(transport)
mcollina commented 2 years ago

I think you missed the mkdir option:

const day = dayjs().format('YYYY-MM-DD')
// fs.writeFile(`/app/logs/${day}_logs.log`, '', () => {})

const pinoLogger = pino(
  {
    level: LOG_LEVEL,
    prettyPrint: {
      colorize: true, // colorizes the log
      levelFirst: true,
      translateTime: 'yyyy-mm-dd, h:MM:ss TT'
    }
  },
  // pino.destination(`${__dirname}/${day}_logs.log`) -> create file automatically
  pino.destination({ dest: `/app/logs/${day}_logs.log`, mkdir: true }) 
)

export default pinoLogger
mcollina commented 2 years ago

Anyway, I would recommend you to move to use pino-pretty as a stream:

const pino = require('pino')
const pretty = require('pino-pretty')
const stream = pretty({
  colorize: true
})
const logger = pino({ level: 'info' }, stream)

// Nothing is printed
logger.debug('hi')
convers39 commented 2 years ago

Anyway, I would recommend you to move to use pino-pretty as a stream:

const pino = require('pino')
const pretty = require('pino-pretty')
const stream = pretty({
  colorize: true
})
const logger = pino({ level: 'info' }, stream)

// Nothing is printed
logger.debug('hi')

Hi,

Thank you for your explanation. Yes, I noticed that the mkdir option should be set to true, so by default, it is false?

And I changed to multistreams so that I can output to different files with corresponding levels, but the pretty stream just output nothing to the console.. Outputs to files are working well.

If I remove the level prop and go with stream prop only, the pretty stream works but in that case I cannot seperate files.

Anyway, not a big problem as I would not use pretty in prod env. Thanks again.

const commonOptions = {
  // levelFirst: false,
  translateTime: 'SYS:yyyy-mm-dd HH:MM:ss Z',
  mkdir: true,
  append: true,
  sync: false
}

const levels = {
  fatal: 60,
  error: 50,
  warn: 40,
  info: 30,
  debug: 20
  // trace: 10
}

// this will work but cannot seperate logs by levels?
// const streams = [
//   { stream: pretty({ colorize: true, ...commonOptions }) },
//   {
//     stream: pino.destination({
//       dest: `./logs/${day}/combined.log`,
//       ...commonOptions
//     })
//   }
// ]

const streams = Object.keys(levels).map((level) => {
  return {
    level: level as Level,
    stream:
      level === 'debug'
        ? pretty({ colorize: true, ...commonOptions })
        : pino.destination({
            dest: `./logs/${day}/app-${level}.log`,
            ...commonOptions
          })
  }
})

const pinoLogger = pino(
  { level: LOG_LEVEL },
  pino.multistream(streams, { levels, dedupe: true })
)
github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.