Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usage with Pino as a Transport #99

Open
thehobbit85 opened this issue Feb 14, 2023 · 1 comment
Open

Usage with Pino as a Transport #99

thehobbit85 opened this issue Feb 14, 2023 · 1 comment

Comments

@thehobbit85
Copy link

I wanted to use this library as a Pino Transport.
The problem is that Pino can only accept streams using the streams API which then doesn't allow the usage of other transports.
So if for example I wanted to save the logs to a file and also pretty-print them, I would have to setup both the FileStreamRotator and the pretty-print as streams using the stream API and I can't just setup the pretty-print as a normal transport.

And in my app I have 7 different transports and I really didn't want to have to change the code to use the stream API.

So here is what I came up with:

Create a file named 'logger.ts' and add this code to it:

import pino from 'pino'
import * as FileStreamRotator from 'file-stream-rotator'

const transport = pino.transport({
  targets: [
    {
      level: 'info',
      target: './logger.ts',
      options: {
        filename: '/tmp/test-%DATE%',
        frequency: 'daily',
        date_format: 'YYYY-MM-DD',
        size: '100M',
        max_logs: '10',
        audit_file: '/tmp/audit.json',
        extension: '.log',
        create_symlink: true,
        symlink_name: 'tail-current.log'
      }
    }
  ]
})

export const logger = pino(transport)
export default (options: any): any => FileStreamRotator.getStream(options)

Since Pino forces us to pass the target prop as string that points to a transport file, instead of creating a new file just for this, I export the stream as the default of this file and then point the target to myself.

It's super hacky but that's the only way I found that wouldn't require creating a new file and then having to deal with windows/mac/linux file paths nonsense.

If anyone has a better, cleaner solution, I would love to hear it . Thanks.

@AJStacy
Copy link

AJStacy commented Apr 12, 2023

I wanted to use this library as a Pino Transport. The problem is that Pino can only accept streams using the streams API which then doesn't allow the usage of other transports. So if for example I wanted to save the logs to a file and also pretty-print them, I would have to setup both the FileStreamRotator and the pretty-print as streams using the stream API and I can't just setup the pretty-print as a normal transport.

And in my app I have 7 different transports and I really didn't want to have to change the code to use the stream API.

So here is what I came up with:

Create a file named 'logger.ts' and add this code to it:

import pino from 'pino'
import * as FileStreamRotator from 'file-stream-rotator'

const transport = pino.transport({
  targets: [
    {
      level: 'info',
      target: './logger.ts',
      options: {
        filename: '/tmp/test-%DATE%',
        frequency: 'daily',
        date_format: 'YYYY-MM-DD',
        size: '100M',
        max_logs: '10',
        audit_file: '/tmp/audit.json',
        extension: '.log',
        create_symlink: true,
        symlink_name: 'tail-current.log'
      }
    }
  ]
})

export const logger = pino(transport)
export default (options: any): any => FileStreamRotator.getStream(options)

Since Pino forces us to pass the target prop as string that points to a transport file, instead of creating a new file just for this, I export the stream as the default of this file and then point the target to myself.

It's super hacky but that's the only way I found that wouldn't require creating a new file and then having to deal with windows/mac/linux file paths nonsense.

If anyone has a better, cleaner solution, I would love to hear it . Thanks.

Please check out adzejs as an alternative logger to Pino. It just works with everything. Here's an example of setting up this library with Adze:

import adze, { createShed, Configuration, Constraints } from 'adze';
import { Shed } from 'adze/dist/shed';
import * as FileStreamRotator from 'file-stream-rotator';

/*
We are applying a constraints type to our logger in order to force developers
to add their namespaces to a centralized list. This makes it easy to know what
namespaces are being used throughout the application for filtering purposes.
*/
interface AppConstraints extends Constraints {
  allowedNamespaces: 'optin' | 'optin-controller';
}

/**
 * Configure our Adze logger for the development environment.
 */
function setupDevLogger(shed: Shed) {
  // This Adze configuration is used in the development environment
  const devConfig: Configuration = {
    useEmoji: true,
    logLevel: 8,
  };

  // Create our listener for writing to our log file
  shed.addListener('*', async (data, render) => {
    const logString = render[1][0];
    logStream.write(`${logString}\n`);
  });

  // Set up our base logger
  return adze<AppConstraints>(devConfig).timestamp.seal();
}

/**
 * Configure our Adze logger for the production environment.
 */
function setupProdLogger(shed: Shed) {
  // This Adze configuration is used in the production environment
  const prodConfig: Configuration = {
    unstyled: true,
    machineReadable: true,
    logLevel: 5,
  };

  // Create our listener for writing to our log file
  shed.addListener('*', async (data, render) => {
    const logString = render[1][0];
    logStream.write(`${logString}\n`);
  });

  // Set up our base logger
  return adze<AppConstraints>(prodConfig).timestamp.seal();
}

// Create a rotating file stream for writing our logs to a file.
const logStream = FileStreamRotator.getStream({
  filename: './logs/%DATE%',
  frequency: 'daily',
  date_format: 'MM-DD-YYYY',
  size: '2M',
  max_logs: '14',
  audit_file: './logs/audit.json',
  extension: '.log',
  create_symlink: true,
  symlink_name: 'current.log',
});

// Create an instance of shed for controlling our loggers and adding listeners
const shed = createShed({ cacheLimit: 0 });

// Create our logger factory for use throughout our application
const logger = process.env.ENV === 'development' ? setupDevLogger(shed) : setupProdLogger(shed);

export default logger;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants