Coder Social home page Coder Social logo

signale's Introduction

Signale

Highly configurable logging utility

Header

Build Status NPM Downloads

Description

Hackable and configurable to the core, signale can be used for logging purposes, status reporting, as well as for handling the output rendering process of other node modules and applications.

Read this document in: 简体中文.

You can now support the development process through GitHub Sponsors.

Visit the contributing guidelines to learn more on how to translate this document into more languages.

Come over to Gitter or Twitter to share your thoughts on the project.

Highlights

  • 19 out-of-the-box loggers
  • Hackable to the core
  • Clean and beautiful output
  • Integrated timers
  • Custom pluggable loggers
  • TypeScript support
  • Interactive and regular modes
  • Secrets & sensitive information filtering
  • Filename, date and timestamp support
  • Scoped loggers and timers
  • Scaled logging levels mechanism
  • String interpolation support
  • Multiple configurable writable streams
  • Simple and minimal syntax
  • Globally configurable through package.json
  • Overridable configuration per file and logger

Contents

Install

Yarn

yarn add signale

NPM

npm install signale

Usage

Default Loggers

Import signale and start using any of the default loggers.

View all of the available loggers.
  • await
  • complete
  • error
  • debug
  • fatal
  • fav
  • info
  • note
  • pause
  • pending
  • star
  • start
  • success
  • wait
  • warn
  • watch
  • log

const signale = require('signale');

signale.success('Operation successful');
signale.debug('Hello', 'from', 'L59');
signale.pending('Write release notes for %s', '1.2.0');
signale.fatal(new Error('Unable to acquire lock'));
signale.watch('Recursively watching build directory...');
signale.complete({prefix: '[task]', message: 'Fix issue #59', suffix: '(@klauscfhq)'});
Default Loggers

Custom Loggers

To create a custom logger define an options object yielding a types field with the logger data and pass it as argument to a new signale instance.

const {Signale} = require('signale');

const options = {
  disabled: false,
  interactive: false,
  logLevel: 'info',
  scope: 'custom',
  secrets: [],
  stream: process.stdout,
  types: {
    remind: {
      badge: '**',
      color: 'yellow',
      label: 'reminder',
      logLevel: 'info'
    },
    santa: {
      badge: '🎅',
      color: 'red',
      label: 'santa',
      logLevel: 'info'
    }
  }
};

const custom = new Signale(options);
custom.remind('Improve documentation.');
custom.santa('Hoho! You have an unused variable on L45.');
Custom Loggers

Here is an example where we override the default error and success loggers.

const {Signale} = require('signale');

const options = {
  types: {
    error: {
      badge: '!!',
      label: 'fatal error'
    },
    success: {
      badge: '++',
      label: 'huge success'
    }
  }
};

const signale = new Signale();
signale.error('Default Error Log');
signale.success('Default Success Log');

const custom = new Signale(options);
custom.error('Custom Error Log');
custom.success('Custom Success Log');
Default Loggers

The options object can hold any of the following attributes: disabled, interactive, logLevel, secrets, stream, scope and types.

disabled
  • Type: Boolean
  • Default: false

Disables the logging functionality of all loggers belonging to the created instance.

interactive
  • Type: Boolean
  • Default: false

Switches all loggers belonging to the created instance into the interactive mode.

logLevel
  • Type: String
  • Default: 'info'

Sets the general logging level of the created instance. Can be one of the following:

  • 'info' - Displays all messages from all loggers.
  • 'timer' - Displays messages only from the time, timeEnd, debug, warn, error & fatal loggers.
  • 'debug' - Displays messages only from the debug, warn, error & fatal loggers.
  • 'warn' - Displays messages only from the warn, error & fatal loggers.
  • 'error' - Displays messages only from the error & fatal loggers.
secrets
  • Type: (String|Number)[]
  • Default: []

An array holding secrets/sensitive-information to be removed from the body and metadata of to-be-logged messages and replaced with the default '[secure]' string.

stream
  • Type: stream.Writable|stream.Writable[]
  • Default: process.stdout

Destination to which the data is written, can be a single valid Writable stream or an array holding multiple valid Writable streams.

scope
  • Type: String|String[]

Name of the scope the logger is reporting from.

types
  • Type: Object

Holds the configuration of the custom and default loggers.

Additionally, the configuration object of each custom/default logger type, defined in the types option, can hold any of the following attributes: badge, label, color, logLevel & stream.

badge
  • Type: String

The icon corresponding to the logger.

label
  • Type: String

The label used to identify the type of the logger.

color
  • Type: String

The color of the label, can be any of the foreground colors supported by chalk.

logLevel
  • Type: String
  • Default: 'info'

The log level corresponding to the logger. Messages originating from the logger are displayed only if the log level is greater or equal to the above described general logging level logLevel of the Signale instance.

stream
  • Type: stream.Writable|stream.Writable[]
  • Default: process.stdout

Destination to which the data is written, can be a single valid Writable stream or an array holding multiple valid Writable streams.

Scoped Loggers

To create a scoped logger from scratch, define the scope field inside the options object and pass it as argument to a new signale instance.

const {Signale} = require('signale');

const options = {
  scope: 'global scope'
};

const global = new Signale(options);
global.success('Successful Operation');
Scope Vanilla

To create a scoped logger based on an already existing one, use the scope() function, which will return a new signale instance, inheriting all custom loggers, timers, secrets, streams, configuration, log level, interactive mode & disabled statuses from the initial one.

const signale = require('signale');

const global = signale.scope('global scope');
global.success('Hello from the global scope');

function foo() {
  const outer = global.scope('outer', 'scope');
  outer.success('Hello from the outer scope');
  
  setTimeout(() => {
    const inner = outer.scope('inner', 'scope'); 
    inner.success('Hello from the inner scope');
  }, 500);
}

foo();
Scope Existing

Interactive Loggers

To initialize an interactive logger, create a new signale instance with the interactive attribute set to true. While into the interactive mode, previously logged messages originating from an interactive logger, will be overridden only by new ones originating from the same or a different interactive logger. Note that regular messages originating from regular loggers are not overridden by the interactive ones.

const {Signale} = require('signale');

const interactive = new Signale({interactive: true, scope: 'interactive'});

interactive.await('[%d/4] - Process A', 1);

setTimeout(() => {
  interactive.success('[%d/4] - Process A', 2);
  setTimeout(() => {
    interactive.await('[%d/4] - Process B', 3);
    setTimeout(() => {
      interactive.error('[%d/4] - Process B', 4);
      setTimeout(() => {}, 1000);
    }, 1000);
  }, 1000);
}, 1000);
Interactive Mode

Writable Streams

By default, all signale instances log their messages to the process.stdout stream. This can be modified, to match your own preference, through the stream property, where you can define a single or multiple valid Writable streams, which will be used by all logger types to log your data. Additionally, it is possible to define one or more Writable streams exclusively for a specific logger type, thus write data independently from the rest logger types.

const {Signale} = require('signale');

const options = {
  stream: process.stderr, // All loggers will now write to `process.stderr`
  types: {
    error: {
      // Only `error` will write to both `process.stdout` & `process.stderr`
      stream: [process.stdout, process.stderr]
    }
  }
};

const signale = new Signale(options);
signale.success('Message will appear on `process.stderr`');
signale.error('Message will appear on both `process.stdout` & `process.stderr`');
Writable Streams

Secrets Filtering

By utilizing the secrets option, secrets and other sensitive information can be filtered out from the body as well as the metadata, i.e. scope names etc, of to-be-logged messages. The option is part of the configuration object passed to a Signale instance on its initialization, and is of type Array<String|Number>. The array can hold multiple secrets, all of which are removed, if present, from the to-be-logged messages and are replaced with the default '[secure]' string. Additionally, when the unary signale.scope(name) function is used, the returned Signale instance inherits all the secrets belonging to its parent. The secrets checking process is performed in a case-sensitive manner. Also, the unary signale.addSecrets() and the nullary signale.clearSecrets() functions are available through the API for adding and clearing secrets respectively.

It is critical and highly recommended to not type directly secrets in your code, thus the following example serves only as a simple & easily reproducible usage demonstration.

const {Signale} = require('signale');

// In reality secrets could be securely fetched/decrypted through a dedicated API 
const [USERNAME, TOKEN] = ['klaussinani', 'token'];

const logger1 = new Signale({
  secrets: [USERNAME, TOKEN]
});

logger1.log('$ exporting USERNAME=%s', USERNAME);
logger1.log('$ exporting TOKEN=%s', TOKEN);

// `logger2` inherits all secrets from its parent `logger1`
const logger2 = logger1.scope('parent');

logger2.log('$ exporting USERNAME=%s', USERNAME);
logger2.log('$ exporting TOKEN=%s', TOKEN);
Secrets Filtering

Timers

Timer are managed by the time() and timeEnd() functions. A unique label can be used to identify a timer on initialization, though if none is provided the timer will be assigned one automatically. In addition, calling the timeEnd() function without a specified label will have as effect the termination of the most recently initialized timer, that was created without providing a label.

const signale = require('signale');

signale.time('test');
signale.time();
signale.time();

setTimeout(() => {
  signale.timeEnd();
  signale.timeEnd();
  signale.timeEnd('test');
}, 500);
Timers

Configuration

Global

To enable global configuration define the options under the signale namespace in your package.json.

The following illustrates all the available options with their respective default values.

{
  "signale": {
    "displayScope": true,
    "displayBadge": true,
    "displayDate": false,
    "displayFilename": false,
    "displayLabel": true,
    "displayTimestamp": false,
    "underlineLabel": true,
    "underlineMessage": false,
    "underlinePrefix": false,
    "underlineSuffix": false,
    "uppercaseLabel": false
  }
}
View all of the available options in detail.
displayScope
  • Type: Boolean
  • Default: true

Display the scope name of the logger.

displayBadge
  • Type: Boolean
  • Default: true

Display the badge of the logger.

displayDate
  • Type: Boolean
  • Default: false

Display the current local date in YYYY-MM-DD format.

displayFilename
  • Type: Boolean
  • Default: false

Display the name of the file that the logger is reporting from.

displayLabel
  • Type: Boolean
  • Default: true

Display the label of the logger.

displayTimestamp
  • Type: Boolean
  • Default: false

Display the current local time in HH:MM:SS format.

underlineLabel
  • Type: Boolean
  • Default: true

Underline the logger label.

underlineMessage
  • Type: Boolean
  • Default: false

Underline the logger message.

underlinePrefix
  • Type: Boolean
  • Default: false

Underline the logger prefix.

underlineSuffix
  • Type: Boolean
  • Default: false

Underline the logger suffix.

uppercaseLabel
  • Type: Boolean
  • Default: false

Display the label of the logger in uppercase.

Local

To enable local configuration call the config() function on your signale instance. Local configurations will always override any pre-existing configuration inherited from package.json.

In the following example, loggers in the foo.js file will run under their own configuration, overriding the package.json one.

// foo.js
const signale = require('signale');

// Overrides any existing `package.json` config
signale.config({
  displayFilename: true,
  displayTimestamp: true,
  displayDate: false
}); 

signale.success('Hello from the Global scope');
Local Config

Also, scoped loggers can have their own independent configuration, overriding the one inherited by the parent instance or package.json.

// foo.js
const signale = require('signale');

signale.config({
  displayFilename: true,
  displayTimestamp: true,
  displayDate: false
});

signale.success('Hello from the Global scope');

function foo() {
  // `fooLogger` inherits the config of `signale`
  const fooLogger = signale.scope('foo scope');

  // Overrides both `signale` and `package.json` configs
  fooLogger.config({
    displayFilename: true,
    displayTimestamp: false,
    displayDate: true
  });

  fooLogger.success('Hello from the Local scope');
}

foo();
Scope Config

API

signale.<logger>(message[, message]|messageObj|errorObj)

logger
  • Type: Function

Can be any default or custom logger.

message
  • Type: String

Can be one or more comma delimited strings.

const signale = require('signale');

signale.success('Successful operation');
//=> ✔  success  Successful operation

signale.success('Successful', 'operation');
//=> ✔  success  Successful operation

signale.success('Successful %s', 'operation');
//=> ✔  success  Successful operation
errorObj
  • Type: Error Object

Can be any error object.

const signale = require('signale');

signale.error(new Error('Unsuccessful operation'));
//=> ✖  error  Error: Unsuccessful operation
//        at Module._compile (module.js:660:30)
//        at Object.Module._extensions..js (module.js:671:10)
//        ...
messageObj
  • Type: Object

Can be an object holding the prefix, message and suffix attributes, with prefix and suffix always prepended and appended respectively to the logged message.

const signale = require('signale');

signale.complete({prefix: '[task]', message: 'Fix issue #59', suffix: '(@klaussinani)'});
//=> [task] ☒  complete  Fix issue #59 (@klaussinani)

signale.complete({prefix: '[task]', message: ['Fix issue #%d', 59], suffix: '(@klaussinani)'});
//=> [task] ☒  complete  Fix issue #59 (@klaussinani)

signale.scope(name[, name])

Defines the scope name of the logger.

name
  • Type: String

Can be one or more comma delimited strings.

const signale = require('signale');

const foo = signale.scope('foo'); 
const fooBar = signale.scope('foo', 'bar');

foo.success('foo');
//=> [foo] › ✔  success  foo

fooBar.success('foo bar');
//=> [foo] [bar] › ✔  success  foo bar

signale.unscope()

Clears the scope name of the logger.

const signale = require('signale');

const foo = signale.scope('foo'); 

foo.success('foo');
//=> [foo] › ✔  success  foo

foo.unscope();

foo.success('foo');
//=> ✔  success  foo

signale.config(settingsObj)

Sets the configuration of an instance overriding any existing global or local configuration.

settingsObj
  • Type: Object

Can hold any of the documented options.

// foo.js
const signale = require('signale');

signale.config({
  displayFilename: true,
  displayTimestamp: true,
  displayDate: true
});

signale.success('Successful operations');
//=> [2018-5-15] [11:12:38] [foo.js] › ✔  success  Successful operations

signale.time([, label])

  • Return Type: String

Sets a timers and accepts an optional label. If none provided the timer will receive a unique label automatically.

Returns a string corresponding to the timer label.

label
  • Type: String

Label corresponding to the timer. Each timer must have its own unique label.

const signale = require('signale');

signale.time();
//=> ▶  timer_0  Initialized timer...

signale.time();
//=> ▶  timer_1  Initialized timer...

signale.time('label');
//=> ▶  label    Initialized timer...

signale.timeEnd([, label])

  • Return Type: Object

Deactivates the timer to which the given label corresponds. If no label is provided the most recent timer, that was created without providing a label, will be deactivated.

Returns an object {label, span} holding the timer label and the total running time.

label
  • Type: String

Label corresponding to the timer, each timer has its own unique label.

const signale = require('signale');

signale.time();
//=> ▶  timer_0  Initialized timer...

signale.time();
//=> ▶  timer_1  Initialized timer...

signale.time('label');
//=> ▶  label    Initialized timer...

signale.timeEnd();
//=> ◼  timer_1  Timer run for: 2ms

signale.timeEnd();
//=> ◼  timer_0  Timer run for: 2ms

signale.timeEnd('label');
//=> ◼  label    Timer run for: 2ms

signale.disable()

Disables the logging functionality of all loggers belonging to a specific instance.

const signale = require('signale');

signale.success('foo');
//=> ✔  success  foo

signale.disable();

signale.success('foo');
//=>

signale.enable()

Enables the logging functionality of all loggers belonging to a specific instance.

const signale = require('signale');

signale.disable();

signale.success('foo');
//=>

signale.enable();

signale.success('foo');
//=> ✔  success  foo

signale.isEnabled()

Checks whether the logging functionality of a specific instance is enabled.

const signale = require('signale');

signale.success('foo');
//=> ✔  success  foo

signale.isEnabled();
// => true

signale.disable();

signale.success('foo');
//=>

signale.isEnabled();
// => false

signale.addSecrets(secrets)

Adds new secrets/sensitive-information to the targeted Signale instance.

secrets
  • Type: (String|Number)[]

Array holding the secrets/sensitive-information to be filtered out.

const signale = require('signale');

signale.log('$ exporting USERNAME=%s', 'klaussinani');
//=> $ exporting USERNAME=klaussinani

signale.addSecrets(['klaussinani']);

signale.log('$ exporting USERNAME=%s', 'klaussinani');
//=> $ exporting USERNAME=[secure]

signale.clearSecrets()

Removes all secrets/sensitive-information from the targeted Signale instance.

const signale = require('signale');

signale.addSecrets(['klaussinani']);

signale.log('$ exporting USERNAME=%s', 'klaussinani');
//=> $ exporting USERNAME=[secure]

signale.clearSecrets();

signale.log('$ exporting USERNAME=%s', 'klaussinani');
//=> $ exporting USERNAME=klaussinani

Development

For more info on how to contribute to the project, please read the contributing guidelines.

  • Fork the repository and clone it to your machine
  • Navigate to your local fork: cd signale
  • Install the project dependencies: npm install or yarn install
  • Lint code for errors: npm test or yarn test

Related

  • qoa - Minimal interactive command-line prompts
  • taskbook - Tasks, boards & notes for the command-line habitat
  • hyperocean - Deep oceanic blue Hyper terminal theme

Who's Using It?

View in detail all the packages and repositories that are using Signale here.

Team

License

MIT

signale's People

Contributors

amilajack avatar brettimus avatar bttmly avatar danielruf avatar klaudiosinani avatar mariosinani avatar rjoydip avatar villabunterkunt avatar xiaoshude avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

signale's Issues

Extra tools inside Signale with a simple API

Is your feature request related to a problem? Please describe.
What can I do when I log something ?

Describe the solution you'd like

Hi @klauscfhq ! Signale looks awesome !

I'm currently working on a new API design architecture in my company and I'd like to use Signale to log information and errors because it's so beautiful.

Logging things is really really important on big projects with millions of users. Log is great, but usually we need to be notified when something happens.

We're currently using Bugsnag and Slack to get reports of bugs and log the activity.

It's a common pattern but sometimes developers need to use 3 or 4 others libraries and write a lot of code to do that correctly.

What do you think about adding a new API to Signale to plug some tools like that?

To be honest I don't know if it might be on the Signale scope, but I'd like to know your opinion.

What I mean by plug a tool it's something like that:

Just an idea, maybe not the best API

const slack = defaultChannel => ({
  notify: configured => (signaleType, message, extra) => {
    // send message to slack
  },
  configure: (...args) => {
    // call on each new signal instance
    // set api keys, prepare environment config...
  }
})

const bugsnag = {
  notify: configured => (signaleType, message, extra) => {
    // send message to bugsnag
  },
  configure: (...args) => {
    // call on each new signal instance
    // set api keys, prepare environment config...
  }
}

// Each keys might be a signale type
Signale.hook({
  errors: [bugsnag, slack('errors-production')],
  userLogout: [slack('user-logout')],
  // ... others types
})

What do you think about that ? :)

Feature request: support printf-like formatting

Is your feature request related to a problem? Please describe.
Cannot be used directly as a placement of the console object as string formatting is not supported:

console.log('Operation %s successful', 'xyz');
// => Operation xyz successful

const signale = require('signale');
signale.success('Operation %s successful', 'xyz');
// => ✔  success   Operation %s successful xyz

In this example %s is not replaced by the following arguments like it's with console.log.

Describe the solution you'd like
Add printf-like formatting for strings passed to any logger. Strings can be formatted with util.format().

Additionally the replaced values could be highlighted with a color specific to each logger. For example signale.success('Operation %s successful', 'xyz'); could write ✔ success Operation xyz successful with xyz in green as it is the color associated with the success logger.

Additional context
Possible implementation to use:

Multiple logger instances with different options

Describe the bug
Different logger instances created with different options ends up sharing the same options for the last created instance across all instances.

To Reproduce
Create 2 different instances of Signale with different options before starting to log anything :

const {Signale} = require('signale');
const options = {
  types: {
    error: {
      badge: '!!',
      label: 'fatal error'
    },
    success: {
      badge: '++',
      label: 'huge success'
    }
  }
};
const signale = new Signale();
const custom = new Signale(options);

// then log
signale.error('Default error log');
custom.error('Custom error log');

Expected behavior
Instances created with different options should use the options they were created with.

Screenshots

Sample from the README
screen shot 2561-06-17 at 21 44 26

Put in practice, everything is ok :
case_1_code
case_1_output

Sample, behaves inconsistently :
case_2_code
case_2_output

Another sample, behaves inconsistently :
case_3_code
case_3_output

Technical Info (please complete the following information)

  • OS: MacOS (High Sierra 10.13.4)
  • Signale Version: 1.2.0
  • Node.js Version: v.8.10

Additional context
This issue seems very similar with #44.

p.s : I love your lib ❤️

interactive not working with IntelliJ runnerw.exe

Describe the bug
Using the interactive demo, running this code will not work in JetBrains IDE's which are using runnerw.exe to run node.exe and the code.

You will get the following error:

"C:\Program Files\JetBrains\PhpStorm 2018.1.6\bin\runnerw.exe" "C:\Program Files\nodejs\node.exe" D:\test\index.js
[interactive] » ...  awaiting  [1/4] - Process A
D:\test\node_modules\signale\signale.js:240
      stream.moveCursor(0, -1);
             ^

TypeError: stream.moveCursor is not a function
    at Signale._write (D:\test\node_modules\signale\signale.js:240:14)
    at _formatStream.forEach.stream (D:\test\node_modules\signale\signale.js:251:14)
    at Array.forEach (<anonymous>)
    at Signale._log (D:\test\node_modules\signale\signale.js:250:35)
    at Signale._logger (D:\test\node_modules\signale\signale.js:257:10)
    at Timeout.setTimeout [as _onTimeout] (D:\test\index.js:8:17)
    at ontimeout (timers.js:498:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:290:5)

Process finished with exit code 1

It happens as soon as the second log message should appear.

To Reproduce

Expected behavior
Get a nice interactive output like in the signale project readme.md

Technical Info

  • OS: Windows 10 Build 1803 64 Bit
  • Signale Version: 1.2.1
  • Node.js Version: v8.11.3
  • IDE Version: PhpStorm 2018.1.6 (runnerw.exe Version 1.0.0.1)

I would be happy if i can help you testing in this case. Feel free to contact me 👋

Align output when using multiple scopes

Is your feature request related to a problem? Please describe.

Much of the logger output is aligned to columns. You can see it in screenshots in the README.

However scopes are not, which looks weird and seems inconsistent.

Describe the solution you'd like

Right now each instance only knows about one scope, so it wouldn't know what the maximum possible scope length is in order to add the right amount of padding. But there are a few ways around this. We could pass in all the scopes to each instance. It’s a little gross. Or one instance could be responsible for multiple scopes. That would require altering the interface a bit. Something like:

const { Signale } = require("signale")

const options = {
  scopes: ["server", "client"]
}

const logger = new Signale(options)
logger.server.start("Listening")
logger.client.start("Connecting")

If you're using multiple scopes you might have already created a similar interface yourself to simplify usage. For example, I don’t re-instantiate new instances with the scope I need in different parts of my application. I have one module that contains all the instances, each with their own scope, and then I access the one I need, much like in the example above.

Add support for uppercase labels

Is your feature request related to a problem? Please describe.
Add the ability to switch labels to uppercase, while preserving lowercase as the default state.

Describe the solution you'd like
Include an uppercaseLabel option that can be utilized through the config() method.

Additional context

// example.js
const signale = require('signale');

signale.config({uppercaseLabel: false}); // Default state
signale.success('Successful operation');
//=>  ✔  success    Successful operation

signale.config({uppercaseLabel: true});
signale.success('Successful operation');
//=>  ✔  SUCCESS    Successful operation

Print stringified and colorized objects

Is your feature request related to a problem? Please describe.
Right now signale cannot log plain objects stringified as JSON:

signale.success({ test: 123 }) // => ✔  success   
signale.success({ test: 123 }, { test: 123 }) // => ✔  success   [object Object] [object Object]

Describe the solution you'd like
It would be nice if we can log stringified objects with colorized output like in util.inspect or even skip braces and colons to display something like:

✔  success
     test: 123
     server:
       port: 8080

This feature would break messageObj based logs but I think that we can use scopes instead

Config displayFilename path.js error

Describe the bug
Adding displayFilename: true config throw this error:
'"The "path" argument must be of type string"'
Stack error:

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string
at assertPath (path.js:39:11)
at Object.basename (path.js:1300:5)
at stack.map.x (/MYAPP/node_modules/signale/signale.js:63:41)
at Array.map (<anonymous>)
at Signale.get filename [as filename] (MYAPP/node_modules/signale/signale.js:63:27)
at Signale._formatFilename (MYAPP/node_modules/signale/signale.js:91:21)
at Signale._meta (MYAPP/node_modules/signale/signale.js:115:22)
at Signale._buildSignale (MYAPP/node_modules/signale/signale.js:142:26)
at Signale._logger (MYAPP/node_modules/signale/signale.js:79:20)
at Object.<anonymous> (MYAPP/src/hooks/logger.js:17:12)

To Reproduce
Install feathers.js.
Replace winston by signale in sr/index.js and scr/hooks/logger.js. It's work.
Add this config after const logger = require('signale');:

logger.config({
  displayFilename: true
});

💥 Boom! 💥

Technical Info (please complete the following information)

  • OS: OSX 10.13.1 (17B1003)
  • Signale Version: ^1.0.1
  • Node.js Version: v9.11.1

Logging a SyntaxError crashes signale

Describe the bug
Logging an unraised Error causes Signale to explode because it expects a .stack property which is undefined.

TypeError: Cannot read property 'split' of undefined
    at Signale._buildSignale (/home/code/js/armstrong/node_modules/signale/signale.js:163:41)
    at Signale._logger (/home/code/js/armstrong/node_modules/signale/signale.js:81:20)

According to MSDN, which is linked from MDN as being more relevant for IE and V8, the .stack property starts out as undefined, and is populated only later.

It seems what I've hit is one of those cases where the .stack property isn't set at the time of Signale's processing of the Error.

Actually none of that is relevant.

What's happening is that another library is generating a SyntaxError while parsing something else, and not setting the stack property.

To Reproduce
Make an Error, set .stack to undefined, give it to Signale:

const { log } = require('signale')
const e = new SyntaxError
e.stack = undefined
log(e)

// TypeError: Cannot read property 'split' of undefined
//    at Signale._buildSignale (/home/code/js/armstrong/node_modules/signale/signale.js:163:41)
//    at Signale._logger (/home/code/js/armstrong/node_modules/signale/signale.js:81:20)

Technical Info (please complete the following information)

  • OS: Linux
  • Signale Version: 1.1.0
  • Node.js Version: 10.1.0

Does not support print symbol

If I want to print the value of the symbol type variables,signale will throw a type error.

TypeError: Cannot convert a Symbol value to a string

signale/signale.js:141  msg = args.join(' ');

Should we support the printing of symbol type variables?

Option to hide lable (icon only)

Is your feature request related to a problem? Please describe.
I'd like loglines to only have the icon, not the label (like "success" etc).

Describe the solution you'd like
An option displayLabel

import with webpack

How can I import it with webpack?
import signale from "signale"
I get error

index.js:2 Uncaught Error: Cannot find module "fs"
    at webpackMissingModule (index.js:2)
    at Object../node_modules/path-exists/index.js (index.js:2)
    at __webpack_require__ (bootstrap:19)
    at Object.<anonymous> (index.js:3)
    at Object../node_modules/locate-path/index.js (index.js:24)
    at __webpack_require__ (bootstrap:19)
    at Object../node_modules/find-up/index.js (index.js:3)
    at __webpack_require__ (bootstrap:19)
    at Object../node_modules/pkg-conf/index.js (index.js:3)
    at __webpack_require__ (bootstrap:19)

output to devtools console

Is your feature request related to a problem? Please describe.
currently, signale output goes to the CLI but there is no console output if you debug using chrome devtools (i'm using ndb).

Describe the solution you'd like
i would like for the output to also work in chrome devtools.

Additional context
screenshot 2018-08-09 13 09 06

clone method

Is your feature request related to a problem? Please describe.
One way to clone Signale instance is through .scope() method. Wouldn't be convenient if you could clone instance for change just interactivity without changing its scope, like this:

const interactive = signale.clone({ interactive: true }); 

It seems pretty easy to change in the code base:

  clone(configObj) {
    return new Signale(Object.assign(this.currentOptions, ...configObj));
  } 

What are your thoughts about this idea?

Errors when running with node 8.11

/Users/merickson/Documents/code/node/test-signale/node_modules/signale/signale.js:149
signale.push(chalktype.color);
^

TypeError: type.badge.padEnd is not a function
at Signale._buildSignale (/Users/merickson/Documents/code/node/test-signale/node_modules/signale/signale.js:149:49)
at Signale._logger (/Users/merickson/Documents/code/node/test-signale/node_modules/signale/signale.js:79:20)
at Object. (/Users/merickson/Documents/code/node/test-signale/index.js:3:9)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:389:7)

To Reproduce
Using node 8.11, I have a simple index.js calling the same routes that you do in the demo

Expected behavior
Expect to see output as shown in demo

Screenshots
image

Technical Info (please complete the following information)

  • OS: macOS 10.12.6

  • Signale Version: 1.0.1

  • Node.js Version: 8.11

Additional context
I have tested with node 8.9 and newer node versions and all seems to work just fine (seems to be node 8.11 issue -- which is important for us as it is the latest 8.x LTS)

after duplicate block, block copy can do nothing

Describe the bug
after duplicate, block copy can't test, drag and drop connector, click block copy not show left panel

To Reproduce
Steps to reproduce the behavior.

  1. Create a block
  2. Duplicate block
  3. Test block copy
  4. See error

VSCode Debugging not showing logs

Describe the bug
If you debug an js file in VSCode with signale logs, they don't show up in the debug output

To Reproduce
Steps to reproduce the behavior.
Simple package with just signale as dependencie

const signale = require('signale');

signale.info('foo');
console.log('bar')

'bar' gets logged, 'foo' not
Expected behavior
A clear and concise description of what you expected to happen.
i don't see any logs.
Loggin to a file stream works

Screenshots
If applicable, add screenshots to help explain your problem.

Technical Info (please complete the following information)

  • OS: Windows 10
  • Signale Version: 1.1.0
  • Node.js Version: 9.6.1 & 10.1.0

Additional context
Add any other context about the problem here.

`time` and `timeEnd` don't respect underline*: false

Describe the bug

Setting config.underlineLabel does not remove the underline from the time and timeEnd methods.

To Reproduce

Here's the code I'm working with - I've disabled any of the available underline* properties, though underlineLabel should be all that's needed:

// index.js
const { Signale } = require('signale')

const logger = new Signale({
  config: {
    underlineLabel: false,
    underlineMessage: false,
    underlinePrefix: false,
    underlineSuffix: false
  }
})

logger.time('A timer')
logger.timeEnd('A timer')
node index.js

image

Expected behavior

I'd expect the underlineLabel: false setting to apply to the time and timeEnd methods like it does for others.

Looks like that's being set here, without a check for _config.underlineLabel:

https://github.com/klaussinani/signale/blob/ae5701e610034629b44e028010a18b593e0b64c0/signale.js#L325

Technical Info (please complete the following information)

  • OS: MacOS
  • Signale Version: ^1.3.0
  • Node.js Version: 10.13.0

Additional context

I discovered this in my testing of JasonEtco/actions-toolkit#45 - for some reason, the GitHub Actions log display adds additional spaces for labels with an underline:

image

I dug into it and discovered this code. I'm sure its needed for regular terminals/output, but it borks a little in Actions so I just disable underlines entirely (since they wouldn't show up anyway):

https://github.com/klaussinani/signale/blob/ae5701e610034629b44e028010a18b593e0b64c0/signale.js#L212-L216

Let me know if I can clarify anything! Happy to open a PR fixing this if y'all are into it.

Global log disable

Is your feature request related to a problem? Please describe.
I'm incorporating signale into a project, and could not find an easy way to configure signale to be globally disabled in tests, across all files and scopes.

Describe the solution you'd like

signale.config({
    disable: process.env.NODE_ENV === 'test'
})

Please let me know if there's a way to do this already and whether I can start working on this. Thanks!

Typescript types

Are there any plans to support typescript and add d.ts file to the project?

Add clean log level

Is your feature request related to a problem? Please describe.
It would be great to have an option for a clean logger method, without any labels out of the box. It is useful when you want clean message (for code frame for example) but don't want to use console.log.

Describe the solution you'd like
Something like this (method name can be changed to a preferred one):

const file = await readFile(e.loc.file || e.id, 'utf8')
signale.clean(codeFrameColumns(file, { start: e.loc }, { highlightCode: true }))

Logo design proposal

Good day @klauscfhq , I am a graphics designer and an open source enthusiast. I passed by your project and i thought of proposing a logo design for your good project. Ill be doing it as a gift for free. I need your permission first before i start my design. Thanks and best regards! - Tobaloidee

Browser compatibility

Is your feature request related to a problem? Please describe.
We would like to use your package as an abstraction for console.log in both frontend (aka the browser) and backend (Node.js).

Describe the solution you'd like
Are you planning on making the package work in the browser console aswell? Or how would you achieve it?

Thanks in advance!

How can i get readable log

Describe the bug
when i output the log to file, I got a file that content is human unreadable. something like that:

�[90m[2018-6-2]�[39m �[90m[18:01:14]�[39m �[90m›�[39m �[32m✔ �[39m SUCCESS
�[90m[2018-6-2]�[39m �[90m[18:01:14]�[39m �[90m›�[39m �[31m✖ �[39m SOME ERROR

To Reproduce
source code:

const fs = require('fs')
const {Signale} = require('signale')

const writeStream = fs.createWriteStream('out.txt', {
  flags: 'a',
  encoding: 'utf8',
  autoClose: true
})

const signale = new Signale({
  stream: writeStream
})

signale.success('SUCCESS')
signale.error('SOME ERROR')

thank for your work and this awesome module!

Filename output not correct when invoke logger indirectly

If I write my custom logger function ,for example in logger.ts using signale like below:

import  signale =require('signale');

signale.config({
  underlineLabel: false,
  displayFilename: true,
  displayBadge: false
})
export function success(content, ...args: any[]):void {
   signale.success(content)
}

If I invoke my success function in another file for example app.ts,filename output will be logger.ts but not app.ts expected.

Setting the log level

Is your feature request related to a problem? Please describe.
This is probably more of a question than a feature request. Is there a way to set the log level? Currently its outputting everything to my terminal.

Describe the solution you'd like
Ideally it would be nice to set the log level.

new Signale({
  loglevel: 'debug'
});

Set global callback function for `success`, `error` , etc etc

Is your feature request related to a problem? Please describe.
Would it be possible to allow one to set a global callback for each individual log type? Like whenever one calls .success() , it would run a particular callback globally, and if one calls .error() it would also run another global callback etc....same for all of the other logging commands.

Describe the solution you'd like
Allow one to set a global callback for each log command. Success, Error, Fatal, Info... etc etc

Add conditional logging

It would be nice to add a property to the custom options that can control logging on a certain condition

Example

const option = {
  stream: process.stdout,
  debug: {
     //...
     condition: process.env.LOG_LEVEL === 'info'
  }
};

proccess.env.LOG_LELEV = 'info';
logger.debug('Some debug info');
> Some debug info

proccess.env.LOG_LEVEL = 'error';
logger.debug('Some debug info');
>

Replace using Date.toLocaleDateString()/Date.toLocaleTimeString() with own implementation

Is your feature request related to a problem? Please describe.
For the date and timestamp the library uses Date.toLocaleDateString() and Date.toLocaleTimeString(), which has different output for different Node versions.
For instance, Node lts/carbon returns [2019-3-2] [13:00:00] and Node lts/dubnium returns [3/2/2019] [1:00:00 PM].

Describe the solution you'd like
Use an own implementation to format the date and timestamp (preferably [2019-3-2] [13:00:00] in my case) , so this is consistent for different Node versions. Possibly add the option to specify the format through the configuration for Signale.

Support logging of JSON objects

Hey, thanks for this awesome JS logging solution. 💟

Is your feature request related to a problem? Please describe.
I'd like to log a JSON object to the console. Currently signale doesn't log anything when passing an object to the log methods.

Describe the solution you'd like
JSON objects get formatted and logged to the console.

Additional context
Here's a screenshot of the code and the resulting log output

bildschirmfoto 2018-06-11 um 12 53 45

Multiple interactive loggers

Is it possible to have multiple interactive loggers that update independently of each other (either separated by scope or Signale instance)? It seems that the current behavior is that the most recent call to an interactive logger will overwrite any previous interactive output.

Here's an example of what I'm trying and the desired output:

const { Signale } = require('signale');

const interactive = new Signale({ interactive: true, scope: 'scope 1' });

setTimeout(() => {
    interactive.success('[%d/4] - Process A', 2);
    setTimeout(() => {
        interactive.await('[%d/4] - Process B', 3);
        setTimeout(() => {
            interactive.error('[%d/4] - Process B', 4);
            setTimeout(() => {}, 2000);
        }, 4000);
    }, 3000);
}, 2000);

const interactive2 = new Signale({ interactive: true, scope: 'scope 2' });

setTimeout(() => {
    interactive2.info('[%d/3] - starting it...', 1);
    setTimeout(() => {
        interactive2.await('[%d/3] - doing it...', 2);
        setTimeout(() => {
            interactive2.success('[%d/3] - finished it!', 3);
            setTimeout(() => {}, 2000);
        }, 4000);
    }, 3000);
}, 2000);

Output:
Only displays the "scope 2"/interactive2 logs

[scope 2] › ✔  success   [3/3] - finished it!

Desired output:

[scope 1] › ✖  error     [4/4] - Process B
[scope 2] › ✔  success   [3/3] - finished it!

Feature Request: Logo!

@klauscfhq It would be awesome for this project to have a matching logo showcasing its character, would you be interesting into adding one? 🙏

Customizable timer start/end text

Is your feature request related to a problem? Please describe.
As of right now, there is no way to change the text used when a timer is started or ended. It's hard-coded in.

Describe the solution you'd like
It would be awesome if we could specify custom text and colors for this instead! For example:

const log = new Signale({
  timers: {
    start: {
      // similar to types, just without a label
      badge: '👌',
      color: 'green',
      text: 'Custom timer started...'
    },
    end: {
      badge: '👍',
      color: 'red',
      text: ['Timer with custom text ran for:', 'and also has text here'],
      time: 'red' // color for time value
    }
  }
});

log.time('example');
setTimeout(() => { log.timeEnd('example') }, 1000);
// 👌 example     Custom timer started...
// 👍 example     Timer with custom text ran for: 1s and also has text here

We could also use options on specific timers.
signale.time(label, options)

log.time('another example', {
  start: { color: 'cyan', 'badge': '!' },
  end: { text: 'woah custom text and this timer ran for' }
});

setTimeout(() => { log.timeEnd('another example') }, 1000);
// ! another example     Custom timer started...
// 👍 another example     woah custom text and this timer ran for 1s

Additional context
The text option could either take a single string (putting the time after it), or an array of two strings (putting the time between them).

Also, to avoid having to type out a whole configuration, another option could possibly be to simply grab an existing one. To have a timer's start log behave as if it was logged with signale.star(), you could maybe do the following. This isn't a necessary function but it could be useful to some people.

signale.time('label', { start: { type: signale.star } }); // or perhaps just the string "star"

And if for whatever reason someone wanted the same configuration for both start and end without having two copies of it, these could be possible ways to implement that.

// put options in "both"
signale.time('label', { both: { color: 'red' } });

// OR just bring options outside
signale.time('label', { color: 'red' });

// however this works, start and end can still be specified to override things
signale.time('label', { color: 'red', start: { color: 'green' } });
// starts with green, ends with red

Of course, all of this would be optional in a configuration, since there's already a default for how timers should display.

meteor - import does not work

import signale from "signale";
or
const signale = require('signale');

do not work in a meteor project. Empty object {} is defined.

Progress indicator

Awesome project.

It would be nice to display a progress bar that is dynamically updated. Useful for downloading content. Similar to node-progress

Something like...

signale.progress('Downloading content', {current:0, total:100})

// and then call tick to increase the progress
signale.tick()

displays...

// progress      Downloading content [=====             ] 29% 39/bps 3.7s

I have tried using node progress along side signale, but it requires an interrupt() function to be called if you want to log other things during progress. This could be built in, so that if a progress is running, then the new signale.[command] appears above the bar.

I think it could be kept simple and doesn't need to be as advanced as node-progress.

What do you think?
Nic

signale.debug() colored in red

Describe the bug
signale.debug() prints red badge but it's blue on the screenshots

To Reproduce

signale.debug(true)

Expected behavior
Should print blue badge according to the screenshots in README

Technical Info (please complete the following information)

  • OS: Archlinux
  • Signale Version: 1.3.0
  • Node.js Version: 10

TypeError: type.badge.padEnd is not a function in node 6

Describe the bug
Calling signale methods in node 6.11.2 seem to return a TypeError

To Reproduce
Call any of the signale methods, in node 6 environment , it will fail with the following error.

  TypeError: type.badge.padEnd is not a function
  Signale._buildSignale (node_modules/signale/signale.js:198:49)
  Signale._logger (node_modules/signale/signale.js:257:20)
  fetch.then.then.catch.e (src/api/subscriptions.api.js:35:15)

Expected behavior
The logger should work as expected

Technical Info (please complete the following information)

  • OS: macOS 10.13.5
  • Signale Version: 1.2.1
  • Node.js Version: 6.11.2

🙋‍♂️ Interactive Logger

It would be really cool if signale would provide a way to create interactive loggers (not sure if that's what there called, but lemme explain 😄)

Pretty much if I have an interactive CLI that continuously changes it's output, I want to override any previous output whenever I log something new.

For example, this:

signale.pending();

setTimeout(()=>{
  signale.success();
}, 500)

Should output:

☐  pending

and then 500ms later replace it with:

✔  success

Instead of just writing both and ending up with both:

☐  pending
✔  success

This oubviously shouldn't be the default, but it would be really cool if this would be a feature that could be enabled.

tldr; add option to override previous output

Multiple write streams?

Hi,

Signale is awesome, but any idea how should I handle real life use cases such as logging stuff into console AND logging stuff into filesystem or websockets? It seems like a heavy limitation to have maximum one out stream available in config?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.