npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@dediapp/logger

v1.0.0

Published

Logger module

Readme

@dediapp/logger

Configurable winston logger

How to configure logger

Logger is based on winston library. This module allows to configure and create a winston logger via a JSON configuration file or via environment variables. Several properties and options are available to configure the logger.

Environment variables

Three environment variables are available:

  • LOG_TRANSPORTS: selects the "interface" to display logs. It must be equal to "Console" or "File" or event both "Console,File"
  • LOG_LEVEL: selects the level of logs that should be displayed (available values from the most restrictive to the less restrictive: "error", "warn", "info", "http", "verbose", "debug", "silly")
  • LOG_FILE: enables to specify the path to the file where logs should be written if LOG_TRANSPORTS is equal or contains the value "File"
LOG_TRANSPORTS=File
LOG_LEVEL=error
LOG_FILE=etc/dedi/winston.log

Configuration File

All winston's core configuration properties except format and levels can be set in a JSON configuration file. The property transports is set through the field log_transports which is detailed in the following part.
There are three more available properties:

  • default_meta: javascript object containing metadata that should be displayed in the log message
  • exception_handlers: array containing transports which specify where uncaughtException events should be displayed (see winston documention)
  • rejection_handlers: array containing transports which specify where uncaughtRejection events should be displayed (see winston documention)

These properties should be the value of a logging field

{
  "logging": {
    "log_level": "error",
    "silent": false,
    "log_transports": []
  }
}

NB: Winston level property is named log_level

Format

This loggger has a predefined format which is:
LEVEL | Date in ISO format | log message

Between date and log message it is possible to add request details:

  • ip: ip address where the request comes from
  • matrixUserId: id of the user which sent the request
  • requestURL: requested url
  • endpointPath: requested API endpoint
  • httpMethod: http method of the request
  • status: response status

Any other detail can be added and it will be displayed after log message

Aditionnal details are displayed in the following order:
LEVEL | Date in ISO format | ip | matrixUserId | httpMethod | requestURL | endpointPath | status | log message | additionnal details

Transports

In this module, logger's log_transports field is set to an array of objects which contain two properties:

  • type: winston transport that the logger should use. "Console" and "File" transports listed in this winston documentation are available. The field's value must be the transport name and must start with a capital letter ("Console", "File").
  • options: object containing selected transport options, they are all detailed on this page.

NB: It is not specified in winston documentation but transport options can also contain the following properties:

  • level: a string that specifies which logger level is associated with this transport
  • silent: boolean flag indicating whether to suppress output
  • handleExceptions: boolean flag indicating that transport should log uncaughtException events
  • handleRejections: boolean flag indicating that transport should log uncaughtRejection events
{
  "logging": {
    "log_level": "error",
    "log_transports": [{
      "type": "Console",
      "options": {
        "level": "error",
        "consoleWarnLevels": ["error", "info"]
      }
    }]
  }
}

If no transports is specified in the configuration and description files, then the default value is [{"type":"Console"}]

NB: The LOG_TRANSPORTS environment property has the priority over the JSON configuration file/object log_transports field

Rotate File

This module enables to configure transports based on the winston-daily-rotate-file library. Almost all options listed in this documentation are available in this module, only stream option is missing.

{
  "logging": {
    "log_level": "error",
    "log_transports": [{
      "type":"DailyRotateFile",
      "options": {
        "zippedArchive": true,
        "dirname":"./logs",
        "filename": "dedi-%DATE%.log",
        "maxSize": "10m",
        "maxFiles": "5d"
      }
    }],
  }
}

Default values

All default values are defined in the configuration description file src/config.json or your custom description object.
For the following properties: log_level, silent, exit_on_error if they are null or undefined both in configuration and description files then the default values will come from winston library.
Transports options default values will come from winston library too, except for filename option

Logs in file

When LOG_TRANSPORTS is set to "File" or contain "File"

LOG_TRANSPORTS=File
# or
LOG_TRANSPORTS=Console,File

If LOG_FILE is not set then the default filename will be dedi.log

Same with JSON configuration file or conf object, if log_transports array contains a File transport and no options are specified

logging: {
  ...
  log_transports: [
    {type: 'File'}
  ]
  ...
}

If filename option and LOG_FILE are not set, when logTransports contains "File", then the default filename will be dedi.log

For rotate file, it will only check filename option and if it is not set the default filename will be dedi-%DATE%.log with %DATE% replaced by the day date.

How to use it

Create logger

To create a logger you have to use the getLogger method. It takes two optional parameters, conf and confDesc, two configuration objects as described before

First, the module checks if we have defined the path to a configuration file in the DEDI_LOGGER_CONF environment variable. Otherwise, it will check if the file etc/dedi/logger.conf exists and read the configuration from this file. Then, it will check if conf is not null or undefined, and use it if it is the case. If none of these options work, the configuration will come from src/config.json file or your custom description object.

You can define your own description object as the second parameter of getLogger method, but it is not recommended to set this property.

Example: conf parameter not null

import { EFormatType, ETransportType, getLogger } from '@dediapp/logger'

const logger = getLogger({
  logging: {
    log_level: 'error',
    log_transports: [
      {
        type: ETransportType.FILE,
        options: {
          dirname: 'etc/dedi/logs',
          filename: 'dedi.log'
        }
      }
    ]
  }
})

Example: set DEDI_LOGGER_CONF with configuration file path

import { getLogger } from '@dediapp/logger'

process.env.DEDI_LOGGER_CONF = 'home/dwho/logger.conf'
const logger = getLogger()
/*
  For example, home/dwho/logger.conf file content is:
  {
    logging: {
      log_level: 'error',
      log_transports: [
        {
          type: ETransportType.FILE,
          options: {
            dirname: 'etc/dedi/logs',
            filename: 'dedi.log'
          }
        }
      ]
    }
  }
*/

Example: etc/dedi/logger.conf file exists

import { getLogger } from '@dediapp/logger'

const logger = getLogger()
/*
  For example, etc/dedi/logger.conf file content is:
  {
    logging: {
      log_level: 'error',
      log_transports: [
        {
          type: ETransportType.FILE,
          options: {
            dirname: 'etc/dedi/logs',
            filename: 'dedi.log'
          }
        }
      ]
    }
  }
*/

Example: use default configuration from src/config.json

import { getLogger } from '@dediapp/logger'

const logger = getLogger()
/*
  src/config.json file content is:
  {
    "logging": {
      "log_level": "info",
      "log_transports": [{
        "type":"Console"
      }],
      "silent": false,
      "exit_on_error": false,
      "default_meta": null,
      "exception_handlers": [],
      "rejection_handlers": []
    }
  }
*/

Example: use your own configuration description object

import { EFormatType, ETransportType, getLogger } from '@dediapp/logger'

const logger = getLogger(null, {
  logging: {
    log_level: 'error',
    log_transports: [
      {
        type: ETransportType.FILE,
        options: {
          dirname: 'etc/dedi/logs',
          filename: 'dedi.log'
        }
      }
    ]
  }
})

Use logger methods

The created logger can log messages thanks to the following methods:

  • error(message: string, details?: Record<string, string| number>)
  • warn(message: string, details?: Record<string, string| number>)
  • info(message: string, details?: Record<string, string| number>)
  • http(message: string, details?: Record<string, string| number>)
  • verbose(message: string, details?: Record<string, string| number>)
  • debug(message: string, details?: Record<string, string| number>)
  • silly(message: string, details?: Record<string, string| number>)
import { getLogger } from '@dediapp/logger'

const logger = getLogger()

logger.error('This is an error message')
// Output: ERROR | 2028-12-08T21:36:22.011Z | This is an error message

logger.info(
  'This is an info message',
  {
    ip: '127.0.0.1',
    matrixUserId: '@dwho:example.com',
    httpMethod: 'GET',
    requestUrl: 'https://example.com/example/how/to/use/logger',
    endpointPath: '/example/how/to/use/logger',
    status: 200,
    detail1: 'additionnal detail 1',
    detail2: 'additionnal detail 2'
  }
)
// Output: INFO | 2028-12-08T21:36:22.011Z | 127.0.0.1 | @dwho:example.com | GET | https://example.com/example/how/to/use/logger | /example/how/to/use/logger | This is an info message | additionnal detail 1 | additionnal detail 2

// Order of additionnal details does not matter
logger.debug(
  'This is a debug message',
  {
    endpointPath: '/example/how/to/use/logger',
    httpMethod: 'GET',
    requestUrl: 'https://example.com/example/how/to/use/logger',
    matrixUserId: '@dwho:example.com',
    ip: '127.0.0.1',
    status: 200,
    detail1: 'additionnal detail 1',
    detail2: 'additionnal detail 2'
  }
)
// Output: DEBUG | 2028-12-08T21:36:22.011Z | 127.0.0.1 | @dwho:example.com | GET | https://example.com/example/how/to/use/logger | /example/how/to/use/logger | 200 | This is a debug message | additionnal detail 1 | additionnal detail 2

logger.silly(
  'This is an info message',
  {
    endpointPath: '/example/how/to/use/logger',
    httpMethod: 'GET',
    matrixUserId: '@dwho:example.com',
    status: 200
  }
)
// Output: SILLY | 2028-12-08T21:36:22.011Z | @dwho:example.com | GET | /example/how/to/use/logger | 200 | This is a silly message

// Methods won't crash if they are called with unsupported additionnal detail 
logger.debug(
  'This is an debug message',
  {
    endpointPath: '/example/how/to/use/logger',
    httpMethod: 'GET',
    matrixUserId: '@dwho:example.com',
    status: 200,
    falsyDetail: 'falsy'
  }
)
// Output: DEBUG | 2028-12-08T21:36:22.011Z | @dwho:example.com | GET | /example/how/to/use/logger | 200 | This is a debug message

The log method is also available and requires one more parameter to specify log level

import { getLogger } from '@dediapp/logger'

const logger = getLogger()
logger.log('error', 'This is an error message')
// Output: ERROR | 2028-12-08T21:36:22.011Z | This is an error message

logger.log(
  'info',
  'This is an info message',
  {
    ip: '127.0.0.1',
    matrixUserId: '@dwho:example.com',
    httpMethod: 'GET',
    requestUrl: 'https://example.com/example/how/to/use/logger',
    endpointPath: '/example/how/to/use/logger',
    status: 200,
    detail1: 'additionnal detail 1',
    detail2: 'additionnal detail 2'
  }
)
// Output: INFO | 2028-12-08T21:36:22.011Z | 127.0.0.1 | @dwho:example.com | GET | https://example.com/example/how/to/use/logger | /example/how/to/use/logger | This is an info message | additionnal detail 1 | additionnal detail 2

Copyright and license

Copyright (c) 2023-present DediApp https://dedim.com.tr

License: GNU AFFERO GENERAL PUBLIC LICENSE