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 🙏

© 2024 – Pkg Stats / Ryan Hefner

eudoros

v1.4.1

Published

A small and simple logger with write-to-file support and dynamic log levels.

Downloads

423

Readme

🛠️ Eudoros - Compact & Flexible Logging Utility

NPM Version

A powerful and customizable logging library for Node.js, with support for custom log levels, formatting, and file logging.

Overview

Eudoros is a robust and flexible logging utility for Node.js applications. It allows you to define custom logging levels with configurable prefixes, formatting, and file logging capabilities. The library is designed to be highly extensible and easy to integrate into your project.

In Eudoros, your message strings and arguments passed into the logging methods are called payloads.

This utility comes with minimal defaults to ensure it works out of the box. When initializing without any configuration, it will create a single basic logging method. All logs are by default written to the ./logs directory. See Default Configuration for more details.

Fun fact for recruiters (*wink wink*): I made this in a under 24 hours (8h of sleep included) with almost non-existent previous TypeScript or module building knowledge. Began work 2 hours before this commit in the identity-service repo. This is my first npm package and I'm pretty proud of it :)

Features

  • Define custom log levels with configurable prefixes, handling options, formatting and processing (on log to file)
  • Supports various console methods (all valid methods: log, info, error, warn, debug)
  • Fully customizable Date object handling with a preferred static method or custom formatting function
  • Optional automatic formatting of payload arguments (numbers, arrays, objects)
  • Optional console log grouping and exception trace insertion
  • Option to output specific logs to separate files
  • Asynchronous logging using process.nextTick() to avoid blocking your main application
  • (new) Synchronous mode available! Just add synchronous: true to the configuration
  • Comprehensive error handling and internal error reporting

Installation

You can install Eudoros using npm npm install eudoros. Remember to use --save or --save-dev according to your needs.

Usage

You can manually choose whether to choose the ESM or CJS version. By default import { Eudoros } from 'eudoros' will import the CommonJS version. You can use the ECMAScript module version by specifying the export path import { Eudoros } from 'eudoros/esm'.

Basic Example

// index.js or logger.js
import { Eudoros } from 'eudoros';

const logger = new Eudoros({
  levels: [
    { label: 'debug', prefix: '[DEBUG]', logToFile: 'debug' },
    { label: 'info', prefix: '[INFO]', logToFile: true },
    { label: 'error', prefix: '[ERROR]', consoleMethodName: 'error', logToFile: 'error' },
  ],
  options: {
    outputDirectory: './logs',
    outputFileExtension: 'log',
    formatArgs: true,
  },
});

logger.debug('This is a debug message');
logger.info('This is an info message');
logger.error('This is an error message', new Error('Something went wrong'));

export default logger; // Export instance for use in other components

EudorosBuilder

As an alternative way to initialize the logger you can also use the EudorosBuilder class. This can be helpful if you want to loop over an array to add your levels.

Keep in mind that you cannot add new levels after initialization!

// index.js or logger.js
import { EudorosBuilder } from 'eudoros';

const builder = new EudorosBuilder({
  outputDirectory: './logs',
  formatArgs: true,
})
  .addLevel({
    label: 'debug',
    prefix: '[DEBUG]',
    logToFile: 'debug',
  })
  .addLevel({
    label: 'info',
    prefix: '[INFO]',
    logToFile: true,
  })
  // ...you can add as many as you like! Just don't overdo it.

const logger = builder.init();

logger.debug('This is a debug message');
logger.info('This is an info message');
logger.error('This is an error message', new Error('Something went wrong'));

export default logger; // Export instance for use in other components

init Function

The last way to initialize is the init function, made as an alternative to the class-based approach, because why not?

import { init } from 'eudoros';

const logger = init({
  levels: [
    { label: 'debug', prefix: '[DEBUG]', logToFile: 'debug' },
    { label: 'info', prefix: '[INFO]', logToFile: true },
    { label: 'error', prefix: '[ERROR]', consoleMethodName: 'error', logToFile: 'error' },
  ],
  options: {
    outputDirectory: './logs',
    formatArgs: true,
  },
});

logger.debug('This is a debug message');
logger.info('This is an info message');
logger.error('This is an error message', new Error('Something went wrong'));

Logging with domains (distinguishing components)

// auth.service.js
logger.withDomain('debug', 'AuthService', 'Validating token');
logger.withDomain('error', 'AuthService', 'Invalid token', token, error);

// user.service.js
logger.withDomain('info', 'UserService', 'Creating new user', userData);
logger.withDomain('warn', 'UserService', 'Duplicate email detected', email);

// payment.service.js
logger.withDomain('info', 'PaymentService', 'Processing payment', orderId);
logger.withDomain('error', 'PaymentService', 'Payment failed', orderId, error);

The withDomain method provides an alternative way to log messages with an additional domain tag that appears after the timestamp. This is useful for distinguishing logs from different components or modules in your application.

Specified domain tag will also be included in the file logs (if enabled), making them easier to filter and analyze.

[!NOTE] When using withDomain, the domain tag is formatted using the same format array as defined in your level configuration.

Method arguments

| Argument | Type | Description | |-----------|:---:|------------------------------------------------------------------------------------| | level | string | The logging level to use (must match one of your defined levels). | | domain | string | A string identifier for the component/module. | | ...args | $E.Payload[] | The logging payload (supports all the same formatting as regular logging methods). |

Default Configuration

// Default logging levels array if none specified
const default_levels = [{
    label: 'log',
    prefix: '[>]'
}];

// Default options
const default_options = {
    outputDirectory: './logs',
    outputFileExtension: 'log',
    formatArgs: true,
    formatDate: 'toISOString',
    consoleTimestamps: true
};

These defaults are merged with provided configuration using spread operator ({...defaults, ...yourOptions}), so you only need to specify the options you want to define or override.

Configuration Options

The Eudoros constructor accepts a $E.Config object with the following properties:

$E.Config

| Property | Type | Description | | --- |:---:| --- | | levels | Array<$E.Level> | An array of logging level objects. | | options | $E.Options | Optional configuration options for the logging system. |

$E.Options

| Property | Type | Default | Description | |-----------------------|:-----------------------:|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | synchronous | boolean | false | Whether to switch to synchronous mode, default false. This changes the behavior of the internal initLevels and handleLog functions. | | outputDirectory | string\|false | './logs' | Specifies the output directory for log files. If false, logging to files is disabled. | | outputFileExtension | string | log | Specifies the file extension to use for the log files. | | formatArgs | boolean | true | Determines whether to apply formatting to payload arguments (e.g., coloring Date instances, numbers, objects). | | formatDate | string\|$E.FormatDate | toISOString | Determines which Date method to use when handling dates, or a defines a custom function to handle the formatting instead (see $E.FormatDate). | | consoleTimestamps | boolean | true | Enable or disable timestamps in console logs. |

$E.Level

The logging level interface.

| Property | Type | Description | | --- |:---:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | label | string | The name of the logging level and the only required variable. | | prefix | string | The prefix that appears at the start of the log message in the console. | | format | [string, string]\|[string, string, string, string] | The formatting of the timestamp and domain elements (ANSI bindings or extra characters). | | logToFile | boolean\|string | Determines whether to output the log to a file.If a string, it adds the value as a substring to log-<here>-{date}.txt in the filename for this log level.If true logs to main log file.If false or unset disabled. | | trace | $E.Trace | Options for splitting the payload into message and trace, and grouping them together in separate console calls. | | consoleMethodName | $E.ConsoleMethod | The console method to use for this logging level (e.g., console.log, console.error). Defaults to log. | | consoleTimestamps | boolean | Override configuration level console timestamp settings. | | methodName | string | The name of the method that will be created, defaults to label. | | formatToString | $E.formatToString | A function that processes objects into a string with custom formatting, used only when logging to file. |

$E.Trace

[!IMPORTANT] When using the trace option, the last argument in the logging method will always be removed from the payload. It will be used in a subsequent console.trace() call if it's not undefined, null or otherwise falsy.

Options used to configure the grouped trace logging.

| Property | Type | Description | | --- | --- | --- | | groupLabel | string | The label passed into console.group(). | | groupPrefix | string | The prefix for the group label. | | format | [string, string] | The formatting of the trace output. |

Example use case

someFunction({foo, bar}, cb => { /* business logic */ }).catch(e => {
  log.critical('Cannot perform this action!', x, y, z, err)
})

Will result in...

[⚠] 2024-11-13T19:14:28.774Z Critical error encountered.
   [✗] Cannot perform this action! / x / y / z
   Trace: Error: Something went wrong
       at ...stack trace...

$E.FormatToString

[!NOTE] The formatToString function is only called when writing to files, not for console output.

interface FormatToString {
    (payload: Payload): string
}

This function is especially useful when defining a special logging level for requests or auditing purposes, where usually we directly pass variables with objects or arrays in a specific order for file logging purposes.

It accesses the payload variables and prepares a string to be used on the handleLog method, allowing your log to also display in a human-readable form in your application console.

| Argument | Type | Description | | --- |:---:|----------------------------------------------------------------| | payload | Payload | The logging payload (array of arguments passed to log method). | | Returns | string | Formatted string to be written to the log file. |

Example implementation

const formatToString = (payload) => {
    const [request] = payload; // Assuming first arg is request object
    return `${request.method} ${request.url} - ${request.status}`;
}

$E.FormatDate

[!NOTE] The formatDate function also processes the Date objects passed into the payload.

interface FormatDate {
    (date: Date): string
}

This function allows more flexibility when handling dates, as it processes all Date objects.

| Argument | Type | Description | |---------|:--------:|--------------------------------------------------------------| | date | Date | The Date object to modify. | | Returns | string | Formatted string to be used for all logging purposes. |

Other Types

$E.FilePayloadHead

This type represents the metadata header of each log entry when writing to files.

| Property | Type | Description | | --- |:---:|----------------------------------------------------------------| | timestamp | string | ISO timestamp of when the log was created. | | level | string | The logging level used (matches the level's label). | | domain | string\|undefined | Optional domain tag if the log was created using withDomain. |

$E.FilePayload

The complete log entry structure that gets written to files. Each line in the log file is a JSON string containing:

| Property | Type | Description | |-------------------------|:--------------------:|------------------------------------------------------| | ...lineHead | $E.FilePayloadHead | All properties from $E.FilePayloadHead. | | args | Array<Payload> | Array of all arguments passed to the logging method. |

$E.Payload

The payload is an array of arguments. The table below represents the valid types that can be passed as logging arguments and the way they are formatted.

| Type | File Log Format | Console Format (when formatArgs: true) | | --- |------------------------|------------------------------------| | string | Raw string | Raw string | | number | Number | Yellow colored text | | boolean | Boolean | Raw boolean | | object | JSON string | Cyan colored JSON string | | Array<any> | Comma-separated string | Green colored comma-separated list | | Date | Formatted string | Magenta colored string | | Error | Error toString() | Raw error (for stack traces) |

$E.ConsoleMethod

Valid console methods that can be used for logging.

| Value | Description | | --- | --- | | 'log' | Standard output (default) | | 'info' | Informational output | | 'error' | Error output | | 'warn' | Warning output | | 'debug' | Debug output |

Internal Error Handling

Eudoros includes a built-in error reporting system that ensures logging failures don't crash your application. When an error occurs within the logger itself, it will:

  1. Create a visually distinct error group in the console with a warning symbol (⚠️)
  2. Include timestamp of the exception
  3. Display a descriptive error message
  4. Show a stack trace if an error object is available
  5. Continue operation without interrupting the application

For example, if writing to a log file fails, you'll see:

[⚠] 2024-11-13T19:14:28.774Z Eudoros caught an exception.
    [>] Cannot write log to file!
    Error: EACCES: permission denied
        at ...stack trace...

Common scenarios where internal error handling activates:

  • Invalid log level configuration
  • File system permission issues
  • Custom format function errors
  • Invalid console method names

Contributing

You are welcome to contributions to Eudoros! If you have any ideas, bug reports, or pull requests, feel free to submit them to the GitHub repository.

License

Eudoros is licensed under the Apache License 2.0.