Giter VIP home page Giter VIP logo

ololog's Introduction

Ololog!

Build Status Windows Build Status NPM

Examples (NEW!)

These examples demonstrate some non-trivial complex behaviors that could be achieved with Ololog by plugging into it's rendering pipeline. For simpler examples read further docs!

  1. Logging to a file and on screen at the same time (with different log levels)

  2. Collapsing repeated messages (with an incrementing counter)

    screen shot 2018-05-11 at 19 32 48
  3. Displaying log levels and custom tags

    screen shot 2019-01-22 at 22 46 59

TODO

  • HTML/DOM rendering
  • Improve tests coverage

Importing

For use with Node or with module bundlers (Browserify / WebPack / Rollup):

npm install ololog
const log = require ('ololog')

Using With Mocha

mocha --reporter ololog/reporter
  • Aligns log messages nicely
  • Supresses log output for nonfailed tests (disable with .only or this.verbose=true for a suite/test)
  • Automatically manages empty lines / whitespace for better legibility
  • Prints unhandled exceptions and promise rejections as nice stacktraces
  • Animated execution progress

NOTE: It is highly experimental yet, and things may not work as expected...

Browser Bundle

...for those who still uses <script> tag for module importing ;) Exposes the global ololog and ansicolor objects. Installs String extensions for ANSI styles. Not compressed.

<script src="https://unpkg.com/ololog"></script> <!-- from unpkg.com CDN -->
<script>
    log = ololog
    log ('something'.red)
</script>

Basic Usage

At first, it's similar to console.log:

log ('foo', 'bar', 'baz') // foo bar baz

Configuration

It exposes a method called .configure, which produces a new log instance with the new settings applied (not mutating the original one), which can be saved and re-used subsequently:

const log = require ('ololog').configure ({ concat: { separator: '' }})
log ('foo', 'bar', 'baz') // foobarbaz

...or you can apply the configuration method ad-hoc:

log.configure ({ concat: { separator: '' }}) ('foo', 'bar', 'baz') // foobarbaz

And you can chain the configuration calls, applying them subsequently:

log1 = log.configure ({ locate: false }) // removes the code location tag
log1 ('foo')

log2 = log1.configure ({ time: true }) // preserves previous settings + enables timestamps
log2 ('bar')

The variety of possible options will be covered just below โ€” there is a plenty of them!

Configuration engine is implemented as a separate external library, for everyone's use โ€” you can read more about it here. Contributions are welcome.

Debugging Of Functional Expressions

Ololog returns its first argument (a feature that console.log doesn't have), and it greatly simplifies debugging of functional expressions, as you can simply wrap part of an expression to log:

array.map (x => log (x) + 1)

It is far less ugly than with console.log:

array.map (x => { console.log (x); return x + 1 })

Also, if you don't like that behavior, you can override it. For example, returning the last argument instead of first:

log = log.configure ({

    returnValue: (text, { initialArguments }) => initialArguments[initialArguments.length - 1]
})

ANSI Styling

Backed by the ansicolor library, colored output is supported for the terminal environment and for the Chrome DevTools console. On other platforms, ANSI codes are safely stripped from the output, so they don't mess up anything.

Apply styling by calling the ansicolor methods on arbitrary strings:

require ('ansicolor').nice // importing in .nice mode extends the String prototype, but there's a safe functional mode as well (see the docs...)

log (('foo'.dim.red + 'bar'.bgLightCyan).underline)

...or by using the built-in shorthand methods (no need to import ansicolor, but we lose the ability to colorize just a part of a string):

log.red ('red text')
log.bright.red.underline ('multiple styles combined')

See all the supported styling options here.

Smart Indentation / Newline Handling

To add indentation to a multiline text or complex objects, you can simply provide the indentation symbols as a first argument:

log ('    ', 'foo\nbar\nbar')
    foo
    bar
    bar

The remarkable thing is that you can provide any text that would be used to offset what's coming after it. This is especially useful with printing long objects that span across many lines:

log ('This is my object:', { foo: 10, bar: 20, qux: 30 })
This is my object: { foo: 10,
                     bar: 20,
                     qux: 30  }

Compare it to the crappy console.log output, which doesn't care about readability:

This is my object: { foo: 10,
 bar: 20,
 qux: 30  }

Ololog also handles the ANSI escape codes correctly while computing the proper the indentation width:

const { bright } = require ('ansicolor')

log.magenta (bright.green ('This is my object:'), { foo: 10, bar: 20, qux: 30 })

Screen Shot 2019-06-27 at 13 39 08

Using The indent Option

The other way is to use the indent config option:

log.configure ({ indent: { level: 3 } }) ('foo\nbar\nbaz\n')

Shorthand method:

log.indent (2) ('foo\n', 'bar\n', 'baz')

You can also set the indentation pattern should be used:

log = log.configure ({ indent: { pattern: '\t' } })

Smart Object Printing

All magic is provided by the external String.ify library. Read the docs to see all the available configuration options. There are plenty of them! Contributions are welcome.

GIF Animation

Default output:

log (obj) // prints example object
{ asks: [ { price: "1000", amt: 10 },
          { price: "2000", amt: 10 }  ],
  bids: [ { price: "500", amt: 10 },
          { price: "100", amt: 10 }  ]   }

Longer strings:

log.maxLength (70) (obj)
{ asks: [{ price: "1000", amt: 10 }, { price: "2000", amt: 10 }],
  bids: [{ price: "500", amt: 10 }, { price: "100", amt: 10 }]    }

Shorter strings:

log.maxLength (20) (obj)
{ asks: [ {  price: "1000",
               amt:  10     },
          {  price: "2000",
               amt:  10     }  ],
  bids: [ {  price: "500",
               amt:  10    },
          {  price: "100",
               amt:  10    }  ]   }

Disabling right keys alignment:

log.noRightAlignKeys (anotherObj)
{ obj: [ { someLongPropertyName: 1,
           propertyName: 2,
           anotherProp: 4,
           moreProps: 5             },
         { propertyName: { someVeryLongPropertyName: true,
                           qux: 6,
                           zap: "lol"                      } } ] }

Disabling fancy nesting:

log.noFancy (anotherObj)
{
    obj: [
        {
            someLongPropertyName: 1,
            propertyName: 2,
            anotherProp: 4,
            moreProps: 5
        },
        {
            propertyName: {
                someVeryLongPropertyName: true,
                qux: 6,
                zap: "lol"
            }
        }
    ]
}

No fancy nesting + setting indentation width to 2 spaces:

log.configure ({ stringify: { fancy: false, indentation: '  ' } }) (yetAnotherObj)
{
  obj: [
    {
      propertyName: 2,
      moreProps: 5
    }
  ]
}

Single line mode:

log.noPretty (obj)
{ asks: [{ price: "1000", amount: 10 }, { price: "2000", amount: 10 }], bids: [{ price: "500", amount: 10 }, { price: "100", amount: 10 }] }

Changing max print depth / max array length:

log.maxDepth (1).maxArrayLength (100) (obj) // or log.configure ({ stringify: { maxDepth: 1, maxArrayLength: 100 } })
log.unlimited (obj) // disables limiting

Setting floating-point output precision:

log.precision (2) ({ foo: 123.456789 })
{ foo: 123.45 }

Passing other configuration options to string.ify (read the its docs for more info):

log.configure ({

    stringify: {
        pure:            false,
        json:            false,
        maxDepth:        5,
        maxLength:       50,
        maxArrayLength:  60,
        maxObjectLength: 200,
        maxStringLength: 60,
        precision:       undefined,
        formatter:       undefined,
        pretty:         'auto',
        rightAlignKeys:  true,
        fancy:           true,
        indentation:    '    '
    }
    
}) (obj)

Avoid Too Long Call Chains

Please not that in case of multiple configuration options it is preferable to do that:

log.configure ({ stringify: { precision: 2, maxLength: 20, noFancy: true, maxDepth: 8 }})

...instead of:

log.precision (2).maxLength (20).noFancy.maxDepth (8)

...because the latter generates too deep callstack which could disrupt the displaying of the call location tag along with the message! The problem is yet to be solved in future pipez versions.

Using With Custom Stringifier

Replacing the default printer with q-i (as an example):

const log = require ('ololog').configure ({ stringify: { print: require ('q-i').stringify } })
log ({ foo: true, bar: 42 })

pic

You can also override the arguments stringification stage completely (see more on overriding default behavior):

log = require ('ololog').configure ({ stringify (args, cfg) { return args.map (x => myCustomStringifier (x, cfg)) } })

// ...providing additional configuration somewhere later...
log = log.configure ({ stringify: { /* this object will be passed down as `cfg` to myCustomStringifier */ }})

Pretty Printing Error Instances

This feature is implemented in the StackTracey library. See it's docs for more (you can configure the path shortening / library calls skipping).

log.bright.red (e) // where `e` is an instance of Error

or (if you want the output go to stderr and supress the grey location badge):

log.bright.red.error.noLocate (e)

Screen Shot 2019-04-06 at 00 56 17

Using As The Default Exception Printer In Node

process.on ('uncaughtException',  e => { log.bright.red.error.noLocate (e); process.exit (1) })
process.on ('unhandledRejection', e => { log.bright.red.error.noLocate (e); process.exit (1) })

Or you can simply call the handleNodeErrors helper when importing Ololog:

const log = require ('ololog').handleNodeErrors ()

See Also: panic-overlay

You can improve the error reporting not only in Node projects, but also in browsers. See the panic-overlay library which shares the same codebase with Ololog:

Displaying Call Location

Have you ever encountered a situation where you need to quickly find in the code the place where the logging is called, but it's not so easy to do? With call location tags it's really easy. And it's enabled by default.

log message

call

Disabling:

log.configure ({ locate: false }) (...)

...or:

log.noLocate (...)

Custom printer:

log.configure ({ locate: { print: ({ calleeShort, fileName, line }) => ... } }) (...)

Displaying outer call location (upwards the stack), can be useful when implementing library code / wrappers:

log.configure ({ locate: { shift: 1 }}) (...)

Manually setting call location (see the StackTracey library, which serves the purpose):

log.configure ({ locate: { where: new StackTracey ().at (2) } }) (...)

Timestamping

Disabled by default. To enable (with default options):

log = log.configure ({ time: true })

Configure formatting:

log = log.configure ({ time: { yes: true, format: 'iso' } })

Here is the correspondence between the format option value and the related Date method used for rendering:

format value Date method
"locale" (default) .toLocaleString ()
"iso" .toISOString ()
"utc" .toUTCString ()
null .toString ()

Providing locale and timezone options (available when format is set to locale):

log.configure ({
    time: {
        yes: true,
        format: 'locale',
        locale: 'en-US',
        options: { timeZone: 'America/Denver' }
    }
})

Providing a custom printer:

log.configure ({ time: { yes: true, print: x => (String (x) + ' | ').bright.cyan }}) ('Lorem ipsum dolor sit amet\nconsectetur adipiscing elit..')

pic

Backdating:

log.configure ({ time: { yes: true, when: new Date ('2017-02-27T12:45:19.951Z') }}) (...)

Specifying Additional Semantics (errors / warnings / info messages)

You can add the .error call modifier, which tells Ololog to render with the console.error instead of the console.log:

log.error ('this goes to stderr')
log.bright.red.error ('bright red error!')

Other console methods are supported as well:

log.info ('calls console.info')
log.warn ('calls console.warn')
log.debug ('calls console.debug')

Displaying The INFO / WARN / ERROR / DEBUG Tags

There is a tag stage (disabled by default) that displays the log level:

const log = require ('ololog').configure ({ tag: true })

log       ('a regular message')
log.info  ('an info message')
log.warn  ('a warning')
log.error ('an error')
log.debug ('a debug message')

screen shot 2019-01-22 at 22 22 44

Customized Tag Printer

You can completely override the tag stage, introducing new parameters and behavior (a clusterId in this example):

const bullet = require ('string.bullet') // NB: these packages are part of Ololog, no need to install them separately
const { cyan, yellow, red, dim } = require ('ansicolor')

const log = require ('ololog').configure ({

    locate: false,
    time: true,
    tag: (lines, {
            level = '',
            levelColor = { 'info': cyan, 'warn': yellow, 'error': red.bright.inverse, 'debug': blue},
            clusterId
          }) => {
        
        const clusterStr = clusterId ? ('CLUSTER[' + (clusterId + '').padStart (2, '0') + ']') : ''
        const levelStr = level && (levelColor[level] || (s => s)) (level.toUpperCase ())

        return bullet (dim (clusterStr.padStart (10)) + '\t' + levelStr.padStart (6) + '\t', lines)
    }
})
log.configure ({ tag: { clusterId: 1  } })       ('foo')
log.configure ({ tag: { clusterId: 3  } }).info  ('bar')
log.configure ({ tag: { clusterId: 27 } }).error ('a multiline\nerror\nmessage')

The output:

screen shot 2019-01-22 at 22 46 59

You can also use Custom Methods feature to make it even more concise:

log = log.methods ({

    // adds `clusterId` helper
    clusterId (n) { return this.configure ({ tag: { clusterId: n } }) }
})

log.clusterId (1)        ('foo')
log.clusterId (3) .info  ('bar')
log.clusterId (27).error ('a multiline\nerror\nmessage')

Limiting Max Argument Length

log.configure ({ trim: { max: 5 } }) ('1234567890', 'abcdefgh') // 1234โ€ฆ abcdโ€ฆ

Getting The Rendered Text

The following will execute all stages before the 'render' (screen output) stage, returning its argument:

log.before ('render') ({ foo: 42 }) // '{ foo: 42 }'

The other way of getting the text (for example, if you want to intercept it and output to your custom renderer, like Blessed) is to override the default render step, see below...

Overriding The Default Behavior

You can provide a custom implementation for certain steps in the Ololog's pipeline. For example, you can replace the render step to output the rendered text to somewhere else other than console.log:

log = log.configure ({

    render (text, { consoleMethod = '' /* can be also debug/info/error/warn */ }) {

        // receives '{ foo: 42 }' and outputs it to the Blessed library
        box.pushLine (text)
        box.scroll (1)
        screen.render ()
    }
})

log ({ foo: 42 })

You can look up all the default steps you could replace here:

https://github.com/xpl/ololog/blob/master/ololog.js#L67

Injecting Custom Code Before/After Steps

You can also bind new code to the existing methods in an aspect-oriented programming style, executing it before, after or instead โ€“ and thus overriding the default behavior. See the pipez library, which provides all the fun โ€” with its help you could build incredibly configurable things similar to Ololog easily.

For example, if you want to write .error calls not just on screen, but to a separate file, you can do following (by injecting a custom hook after the render call):

const ololog = require ('ololog')
    , ansi   = require ('ansicolor')
    , fs     = require ('fs')
    
const log = require ('ololog').configure ({

    'render+' (text, { consoleMethod = '' }) { // adds this method after `render`
        if (consoleMethod === 'error') {
            fs.appendToFile ('error.log', '\n' + ansi.strip (text)) // strip ANSI styling codes from output
        }
        return text
    }
})

Here's a complete example on how to set up a file logging that supports different log levels:

Here's another trick that you could do by injecting a handler before the render step (that would be +render instead of render+):

Adding Custom Helper Methods

You can add your own shorthand methods/properties (will add new properties globally for any instance of the ololog, but this may change in future). An example, demonstrating how the actual indent and red chain-style helpers were implemented:

log.methods ({

    indent (level) { return this.configure ({ indent: { level: level }}) }
    get red ()     { return this.configure ({ 'concat+': lines => lines.map (ansicolor.red) }) } // executes it after the 'concat'
})

No-op Device

Use .noop to obtain a reduced instance that does nothing apart from returning its first argument:

const doesNothing = log.noop
doesNothing.bright.red ('this never shows') // simply returns 'this never shows'

Powered By

Projects That Use Ololog

  • CCXT โ€“ a cryptocurrency trading library with 100+ exchanges.

ololog's People

Contributors

dependabot[bot] avatar ourarash avatar xpl 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

ololog's Issues

Add license

Hey @xpl! I noticed that there is no license attached to this repository. I would like to use this for a commercial project but without any license declared in the repository, this will be impossible.

Would it be possible to add a license?

Typescript definition issues (time, methods)

using the example log = log.configure ({ time: { yes: true, format: 'iso' } }) leads to a typescript issue as yes is not defined. It seems it is missing from the types definition

ololog/reporter: TypeError: (intermediate value).clean.at is not a function

TypeError: (intermediate value).clean.at is not a function

How to repeat:

git clone https://github.com/unlight/node-package-starter.git
cd node-package-starter
npm i
npm i -D  ololog
# change src/index.spec.ts, change line with 'Hello world' to
# expect(library.hello()).toEqual('Hello world!!!');
node -r ts-node/register/transpile-only node_modules/mocha/bin/_mocha --reporter ololog/reporter  src/**/*.spec.ts

Result:

            const location = new StackTracey ().clean.at (2)
                                                      ^

TypeError: (intermediate value).clean.at is not a function
    at Function.ololog.impl.render (D:\Dev\node-package-starter\node_modules\ololog\reporter.js:62:55)
    at Function.modifiedFunctions.<computed> (D:\Dev\node-package-starter\node_modules\pipez\pipez.js:48:45)
    at Function.modifiedFunctions.<computed> (D:\Dev\node-package-starter\node_modules\pipez\pipez.js:48:45)
    at Function.modifiedFunctions.<computed> (D:\Dev\node-package-starter\node_modules\pipez\pipez.js:48:45)
    at D:\Dev\node-package-starter\node_modules\pipez\pipez.js:23:73
    at Array.reduce (<anonymous>)
    at Function.Object.assign.configure (D:\Dev\node-package-starter\node_modules\pipez\pipez.js:23:39)
    at process.<anonymous> (D:\Dev\node-package-starter\node_modules\ololog\reporter.js:10:48)
    at process.emit (events.js:327:22)
    at process.EventEmitter.emit (domain.js:467:12)
    at process.emit (D:\Dev\node-package-starter\node_modules\source-map-support\source-map-support.js:495:21)
    at process._fatalException (internal/process/execution.js:163:25)

Expected:

Formatted exception
https://github.com/xpl/ololog#using-with-mocha

Env:

bump stacktracey because annoying warning.

warning  in ./node_modules/.pnpm/[email protected]/node_modules/get-source/get-source.js    

Module not found: Error: Can't resolve 'fs' in 'C:\me\dev\tabdeck\node_modules\.pnpm\[email protected]\node_modules\get-source'
 @ ./node_modules/.pnpm/[email protected]/node_modules/stacktracey/stacktracey.js 8:23-45  
 @ ./node_modules/.pnpm/[email protected]/node_modules/ololog/build/ololog.js 14:18-40
 @ ./src/glue/globals.js 7:37-54

I believe that you are version 2.0 with stacktracey.

ReferenceError: Buffer is not defined

I am building an app with Electron and Ololog does not work in my front-end.
I get the following error:

index.js:60 Uncaught (in promise) ReferenceError: Buffer is not defined
    at dataUriToBuffer (index.js:60:16)
    at SourceMapResolver (get-source.js:84:61)
    at SourceMapResolverFromFetchedFile (get-source.js:77:22)
    at _resolve (get-source.js:37:59)
    at Object.resolve (get-source.js:44:36)
    at StackTracey.withSource (stacktracey.js:186:55)
    at stacktracey.js:234:36
    at Array.map (<anonymous>)
    at StackTracey.<computed> [as map] (stacktracey.js:332:52)
    at StackTracey.withSources (stacktracey.js:234:21)

I am using Vite and Svelte, however when I tried to reproduce it with just those two frameworks (without Electron), it works just fine.
I think that it might not execute the Browser version for whatever reason.
Is it possible to enforce that?

xhr request fails in iframe

Thanks for the best logging library out there!

One glitch I bumped into, when calling log.info from inside iframe, an iframe which I instantiate as BlobURL.

The call would be here

            try {
                if (isBrowser) {

                    let xhr = new XMLHttpRequest ()

                        xhr.open ('GET', path, false /* SYNCHRONOUS XHR FTW :) */)
                        xhr.send (null)

                    this.text = xhr.responseText

                } else {

The error in Chrome

6cb0327a-6bb3-4ae6-87cf-91d6c71c5e80:5667 GET blob:http://localhost:3000/4c010b36-0716-4494-8acf-ddb045159385/ net::ERR_FILE_NOT_FOUND

The iframe I create btw like this

    const iFrameHtml = [
      `<!doctype html>`,
      `<html lang="en">`,
      `<head>`,
      `</head>`,
      `<body>`,
      `<script type="text/javascript" src="${ScriptProcessorNodeWorker()}"></script>`,
      `</body>`,
    ].join('\n');

    const iFrameBlob = new Blob([iFrameHtml], { type: 'text/html' });
    const iFrame = document.createElement('iframe');
    iFrame.src = URL.createObjectURL(iFrameBlob);
    iFrame.sandbox.add('allow-scripts', 'allow-same-origin');
    document.body.appendChild(iFrame);

Future expansion: Winston?

So, traditionally I use debug for console logging (which ololog could replace, if it had the filters) and winston for centralized logging.

What's your plan for how ololog will expand going forward?

Color object properies as console.log

I couldn't find a guideline how to preserve colors for object properies, so the console output may look similar to the one produced by console.log:
image

const log = require ('ololog')
const os =          require("os");
const path = require('path');

log({"hello": "world!"});
console.log({"hello": "world!"});

Does the module provide such capabilities?

React native support?

It would be nice to use Ololog in react-native. Right now it seems it primary doesn't work because the browser check is incorrect so react-native is detected as a browser and undefined properties are read.

is_browser = (typeof window !== 'undefined') && (window.window === window) && window.navigator

should be

is_browser = (typeof window !== 'undefined' && typeof document !== 'undefined') && (window.window === window) && window.navigator

in ololog and all of it's dependencies, otherwise react-native gets detected as a browser environment and crashes accessing undefined APIs.

You can also test for react-native directly with

isReactNative  = (typeof navigator != 'undefined' && navigator.product == 'ReactNative'),

It also seems that stacktracey is incompatible with react-native, primarily because of:

  1. react-native does not support synchronous XMLHttpRequests
  2. get-source assumes some node APIs exist that don't on react-native, namely process.cwd is undefined.

How feasible do you think it is to make ololog support react-native out of the box? If the browser checks are fixed it seems to be mostly working except for source mapping. When I tried to async load the source map from metro (react-native's bundler) it just hangs because the source map is enormous. I'm not really familiar with how source mapping works and editing non typescript JS written by somebody else is challenging so I'm not sure if I'm able to figure it out right now.

background color

is that possible to get a background color for the printed string? how to achieve this effect?

Vanilla JS?

newbie question - seeing unexpected error when using ololog as below. I include the lib like this:
<script src="https://unpkg.com/ololog"></script>
then i setup simply like this:

let log = ololog;
log.configure ({
  indent: { level: 3 },  //indent level
  locate:true,
  tag:true, //shows the 'iNFo' tag (or whatever) in front of msg
  time:false //timestamps
 });

but I see a console error on startup from the file get-source.js that i don't understand..

get-source.js:142 GET http://127.0.0.1:5500/index.html/ 404 (Not Found)
(anonymous) @ get-source.js:142
SyncPromise @ SyncPromise.js:9
fetchFileSync @ get-source.js:138
(anonymous) @ get-source.js:27
m @ get-source.js:17
SourceFile @ get-source.js:30
getSource @ get-source.js:113
withSource @ stacktracey.js:166
(anonymous) @ stacktracey.js:214
StackTracey.<computed> @ stacktracey.js:312
withSources @ stacktracey.js:214
clean @ stacktracey.js:237
locate @ ololog.js:119
modifiedFunctions.<computed> @ pipez.js:48
modifiedFunctions.<computed> @ pipez.js:48
(anonymous) @ pipez.js:23
Object.assign.configure @ pipez.js:23
(anonymous) @ logger.js:26

Non browser compatible node-module required

For reasons too long to explain here, I can't include browser compatible polyfills for built-in nodejs modules.

So when I'm compiling targeting the browser with rollup I'm getting

[!] Error: Could not load util (imported by node_modules/stacktracey/stacktracey.js): ENOENT: no such file or directory, open 'util'
Error: Could not load util (imported by node_modules/stacktracey/stacktracey.js): ENOENT: no such file or directory, open 'util'

perhaps some easy isBrowser will fix this. I'm also sure that it should be possible to find require ('util').inspect browserified (using built-in modules if in nodejs env).

Feature request: severity

I was able to hack a severity level so that a message only prints if its severity is above the min severity level. This is useful when for example you run the program in a verbose vs non-verbose mode.

Here is what worked for me:

const bullet = require("string.bullet");
const { cyan, yellow, red, dim, blue } = require("ansicolor");

var log = require("ololog").configure({
  locate: false,
  infoSeverity: 5,
  tag: (
    lines,
    {
      level = "",
      minSeverity=10,
      severity = 11,
      levelColor = {
        info: cyan,
        warn: yellow,
        error: red.bright.inverse,
        debug: blue
      }
    }
  ) => {
    const levelStr =
      level && (levelColor[level] || (s => s))(level.toUpperCase());
    if (severity >= minSeverity) {
      return bullet(levelStr.padStart(6) + "  ", lines);
    } else return [];
  }
});

log("This prints!");

log
.configure({tag:{severity:12}})
.info("This will print, severity 12!");

log
.configure({tag:{severity:1}})
.info("This will print, severity 1!");

log
.configure({tag:{severity:15}})
.info("This will print, severity 15!");

log = log
.configure({tag:{minSeverity:1000}}); // change severity

log
.configure({tag:{severity:12}})
.info("This will not print, severity 12!");

log
.configure({tag:{severity:1}})
.info("This will not print, severity 1!");

log
.configure({tag:{severity:15}})
.info("This will not print, severity 15!");

However, this is ugly. Ideally, it should be like this:

var log = require("ololog").configure({
  locate: false,
  infoMinSeverity: 5,
  warnMinSeverity: 6,
  debugMinSeverity: 8,
  errorMinSeverity: 10,
  minSeverity: 15, //without tag
});

log.severity(5).info('This is my message');
log.configure({infoMinSeverity:0}).info('This is my message');

Intercepting the 'time' section of the log message?

Hi,

Great tool. I especially love the fact that we can intercept and modify the concat and render stages.

One thing I was not able to do:

I would like to format the timestamp in the following fashion:

[2019-01-19T15:40:28.535Z] (INFO) This is just a message reporting a variable:
                        	  [1, 2, 3, 4, 5, 6] (info @ logging.js:60)

I know we can add a custom printer for the time, but that changes the output to:

[Sat Jan 19 2019 15:17:03 GMT+0000 (Greenwich Mean Time)]

which is not something that I would like to do? So here is what I am trying to achieve:

  • Add [ to the start and ] to the end of the timestamp.
  • Change the color of the timestamp (I know I can do that through the custom printer, but the custom printer is changing the look of the date)
  • Adding a (INFO) signature between the timestamp and the message block, so the second line of the message does not spill below the (INFO) signature.

So it looks a bit like this:
format

Obviously, I tried this:

const logging = log.configure ({
    /*  Injects a function after the "concat" step            */
    'concat+' (blocks) {
        console.log(blocks)
        return blocks;
    },
    time: {
        yes: true,
        format: 'iso'
    }
});

as an attempt to intercept the text stream and try re-format it, but I got this:

[ '\u001b[33m\u001b[22m\u001b[1mThis is just a message reporting a variable:\u001b[22m\u001b[39m',
  '\u001b[33m\u001b[22m\u001b[1m\u001b[22m\u001b[39m [1, 2, 3, 4, 5, 6]' ]

... so the timestamp was not there :)

stringify doesn't work in this case, I think

Context is

  • nodejs @14.5
  • ololog @1.1.156
  • string.ify @1.0.61

Transpiled with babel:

    "@babel/plugin-transform-runtime": "^7.9.6",
    "@babel/runtime": "^7.10.2",
    "@babel/cli": "^7.8.4",
    "@babel/core": "^7.10.2",
    "@babel/preset-env": "^7.10.2",

while NODE_ENV=development

import { URL } from 'url';
import ololog from 'ololog';

const log =   ololog.configure({
    stringify: { fancy: false, indentation: '  ', maxDepth: 9, maxStringLength: 135 },
  })

log(new URL('http://www.fml.com')); // <-- just want that one to work
log((new URL('http://www.fml.com')).toString());
log(JSON.stringify(new URL('http://www.fml.com')));

outputs:

{  } (<anonymous> @ apis.js:41)
http://www.fml.com/ (<anonymous> @ apis.js:42)
"http://www.fml.com/" (<anonymous> @ apis.js:43)

How to use with blessed library

I was trying to use this with the npm blessed library, so that I have two boxes: one for output log and one for showing progress which doesn't scroll.

I used:

let renderedText = ololog.before('render')(...args);

and was able to make set of new functions called mainLog. I could make mainLog.info(), error, and warn to work, but I can't make without any tags, e.g. mainLog("print this item");

My complete code is here.
In general, how would you do this?

Document `yes` switch for custom (time) printer

If you follow the documentation for the custom printer for timestamps (https://github.com/xpl/ololog#timestamping), it will show you nothing. That is because the example code lacks the yes switch you need to enable the custom printer.

So this current example:

log.configure ({ time: { print: x => (String (x) + ' | ').bright.cyan }}) ('Lorem ipsum dolor sit amet\nconsectetur adipiscing elit..')

Should be (added yes: true):

log.configure ({ time: { yes: true, print: x => (String (x) + ' | ').bright.cyan }}) ('Lorem ipsum dolor sit amet\nconsectetur adipiscing elit..')

Not sure if it applies to other custom printers as well. It works without the yes on the locate custom printer.

How to disable stringifying?

Hey, I love this library, however in some cases I would like to output the javascript object without stringifying. How can this be done? Thanks!

suggestion: local storage enable/disable

I like ololog a lot better than debug.

But one feature we use organizationally with debug is the local storage enablement.

Screen Shot 2020-09-10 at 4 24 33 PM

It may already be familiar to anyone reading this. But in case not, the way it works is with local storage debug missing or empty, all debug() output is disabled. If its value is *, all debug() output is enabled. Finally it can be set to a comma-separated list of context names, which correlate with require('debug')('context:name')('hello world').

This seems like 2 features unavailable with ololog - 1) local storage enablement and 2) named logging contexts.

If either or both of these features are actually available please just let me know. I'm not perfectly aware of everything ololog can do.

But the local storage enablement alone prevents me from using ololog in our frontend (react) apps.

Because I have a choice, I think, I can enable it or disable it in the build by using ololog.noop when NODE_ENV==='production' and configuring it as wanted otherwise. Or I can leave it enabled.

In the first case, if there's a problem in production, people will be upset we can't see the logging. In the second, the app will seem spammy, people here would prefer to not have logging output by default from our code.

If it seems like it might be possible to add one or both of these features I'd be willing to try to submit a PR according to whatever constraints you might have for it.

custom stringifier doesn't work

I tried the example from the docs:

const obj = { foo: true, bar: 42 }
  
const log = require ('ololog').configure ({ stringify: { print: require ('q-i').stringify } })
log(obj)

const { stringify } = require('q-i')
console.log(stringify(obj))

It turns out that while q-i works by itself, with ololog it doesn't:

image

Typescript definition "object" types issue

Hi,
When importing into my typescript project, I was forced to import it as a js library and not use the type definition. This was due to several parameters defined as object types.
Typescript does not like this, and so it should either be changed to any or an interface should be created for such parameters.
example:

type StageCallback = (input: any, config?: object) => any;

the config?: object means that we are unable to send in any config parameters. It should either be config?: any or config?: IStageCallbackConfig where you define the interface elsewhere.
There are several appearances of this which need fixing in the definition file

How to permanently reconfigure

Suppose I configure the log once. How can I reconfigure it afterwards such that the effect stays permanent. See example below:

var log = require("ololog").configure({
  locate: false,
  tag:false
});

log("doesn't print locate or tag :)");

log.configure({locate:true, tag: true});

log.info("doesn't print locate or tag despite configure :("); 

log.configure({locate:true, tag: true}).info("prints locate or tag but it's ugly!"); 

TypeScript declaration files export 'null' symbol

The TypeScript definition file ololog.d.ts exports symbol null which VS Code's TypeScript auto import feature is eager to import any time the symbol null is autocompleted.

For example, pressing the autocomplete key at the end of this line:

const rudeObj = { hello: "world", value: nul
will cause nul to be auto completed to null, and the null symbol to be automatically imported from ololog.

import ololog, { null } from 'ololog';

The result is invalid code, because null cannot be assigned to for obvious reasons.

It strikes me that it is not good practice to export a symbol that is a language keyword. It is possible that this is simply bad behavior on VS Code's part, but note that this is not the behavior of an extension.

null: ololog,

Before you ask, yes, I am too lazy to type the word 'null' ๐Ÿ˜„

Define timezone for timestamps

Is there any way to define your current timezone or an offset?
Right now the timestamps from the logger are 2 hours behind.

I couldn't find this in the docs.

Thanks.

Chrome Console output does not output location correctly

While running ololog in React I have noticed that it does not output location file from the point where it is called but shows always as event raised by ololog.js:145.

with location config = false it will show:

3/22/2021, 11:22:14 AM	"My Log>> XXX"       ololog.js:145

with location config = false it will show:

3/22/2021, 11:22:14 AM	"My Log>> XXX"       ololog.js:145
(<computed> โ†’ <computed> โ†’ <computed> @ pipez.js:47)

while log was raised in the file example.js.

Even in your demo it will output something like:
https://xpl.github.io/ololog/

foo ra (<computed> โ†’ <computed> โ†’ <computed> โ†’ <computed> @ pipez.js:48)  ololog.js:145 

Feature request: Automatic wrap long lines

Current behavior when using timestamp and tags and trying to log long lines

[time] [tag] Lorem ipsum dolor sit amet
[time] [tag] Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
[time] [tag] Lorem ipsum dolor sit amet

But it is more nicer when it looks like:

[time] [tag] Lorem ipsum dolor sit amet
[time] [tag] Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
             tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
             quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
[time] [tag] Lorem ipsum dolor sit amet

I suppose it is possible when I manually add linebreaks

log('Lorem ipsum dolor sit amet\ntempor incididunt ut labore\n et dolore magna aliqua. Ut enim ad minim veniam')

It would be nice if it happends automatically (break lines depending of available columns in terminal - https://github.com/sindresorhus/term-size)

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.