Giter Club home page Giter Club logo

bevry / caterpillar Goto Github PK

View Code? Open in Web Editor NEW
402.0 15.0 14.0 2.78 MB

Caterpillar is the ultimate logging system for Deno, Node.js, and Web Browsers. Log levels are implemented to the RFC standard. Log entries can be filtered and piped to various streams, including coloured output to the terminal, the browser's console, and debug files. You can even write your own transforms.

License: Other

TypeScript 98.86% JavaScript 1.14%
transform-streams pipe logger logging client-side nodejs caterpillar deno

caterpillar's Introduction

Caterpillar

Status of the GitHub Workflow: bevry NPM version NPM downloads
GitHub Sponsors donate button ThanksDev donate button Patreon donate button Liberapay donate button Buy Me A Coffee donate button Open Collective donate button crypto donate button PayPal donate button
Discord server badge Twitch community badge

Caterpillar is the ultimate logging system for Deno, Node.js, and Web Browsers. Log levels are implemented to the RFC standard. Log entries can be filtered and piped to various streams, including coloured output to the terminal, the browser's console, and debug files. You can even write your own transforms.

Usage

Complete API Documentation.

Examples

Overview

The RFC Log Levels are provided by the rfc-log-levels package which follows RFC 3164 - The BSD Syslog Protocol.

Log Entries that are within the lineLevel range, will have their line information fetched using the get-current-line package.

The Logger is what you write your log messages to, which you then pipe to destinations and transforms.

The Filter transport is used to filter out log levels that we do not want to pass onto the next destination.

The Human transport is used to convert the Log Entries into a human readable and colourful output.

The Browser transport is used to send the human output, including colours, to the Web Browser console.

The Transform is used to write your own transforms, and is what all the others are based from.

Node.js Guide

To get started for Node.js, setup a new Node.js project for this guide and install Caterpillar.

mkdir caterpillar-guide
cd caterpillar-guide
npm init
npm install --save caterpillar
touch index.js

Then edit our index.js file with the following, that will output all the log messages in JSON format to stdout, and can be run via node index.js:

const { Logger } = require('caterpillar')
const logger = new Logger()

logger.pipe(process.stdout)

logger.log('warn', 'this is a warning, which is level', 4)
logger.warn('this is a warning, which is level', 4)
logger.log('debug', 'this is a debug message, which is level', 7)
logger.warn('this is a debug message, which is level', 7)

Outputting in JSON format is not a nice experience, instead we can do better by using the Human transport such that it is human readable.

const { Logger, Human } = require('caterpillar')
const logger = new Logger()

logger.pipe(new Human()).pipe(process.stdout)

logger.log('warn', 'this is a warning, which is level', 4)
logger.warn('this is a warning, which is level', 4)
logger.log('debug', 'this is a debug message, which is level', 7)
logger.warn('this is a debug message, which is level', 7)

However, perhaps we want to still store the JSON format for querying later. We can pipe the human format to stdout as before, but we can pipe the raw output to a debug file.

const { Logger, Human } = require('caterpillar')
const logger = new Logger()

const { createWriteStream } = require('fs')
logger.pipe(createWriteStream('./debug.log'))

logger.pipe(new Human()).pipe(process.stdout)

logger.log('warn', 'this is a warning, which is level', 4)
logger.warn('this is a warning, which is level', 4)
logger.log('debug', 'this is a debug message, which is level', 7)
logger.warn('this is a debug message, which is level', 7)

Now let's stay for some reason, we want to capitalise all the log messages that are warning levels and higher, we can do this by making our own transport by extending the Transform.

const { Logger, Transform, Human } = require('caterpillar')
const logger = new Logger()

const { createWriteStream } = require('fs')
logger.pipe(createWriteStream('./debug.log'))

class Uppercase extends Transform {
    format(entry) {
        if (entry.levelNumber <= 4) {
            entry.args.forEach(function (value, index) {
                if (typeof value === 'string') {
                    entry.args[index] = value.toUpperCase()
                }
            })
        }
        return entry
    }
}

logger.pipe(new Uppercase()).pipe(new Human()).pipe(process.stdout)

logger.log('warn', 'this is a warning, which is level', 4)
logger.warn('this is a warning, which is level', 4)
logger.log('debug', 'this is a debug message, which is level', 7)
logger.warn('this is a debug message, which is level', 7)

Futhermore, the user probably doesn't need to see debug messages, even though they are useful for debugging. We can filter out the debug messages for the user, but maintain them for the debug.log file by applying the Filter transport to the pipe that goes to stdout.

const { Logger, Transform, Filter, Human } = require('caterpillar')
const logger = new Logger()

const { createWriteStream } = require('fs')
logger.pipe(createWriteStream('./debug.log'))

class Uppercase extends Transform {
    format(entry) {
        if (entry.levelNumber <= 4) {
            entry.args.forEach(function (value, index) {
                if (typeof value === 'string') {
                    entry.args[index] = value.toUpperCase()
                }
            })
        }
        return entry
    }
}

logger
    .pipe(new Filter({ filterLevel: 5 }))
    .pipe(new Uppercase())
    .pipe(new Human())
    .pipe(process.stdout)

logger.log('warn', 'this is a warning, which is level', 4)
logger.warn('this is a warning, which is level', 4)
logger.log('debug', 'this is a debug message, which is level', 7)
logger.warn('this is a debug message, which is level', 7)

As fetching line information is computationally expensive process, for large applications for performance we probably only want to fetch the line information for messages that we actually show to the user. As such, we should make the filterLevel and the lineLevel the same.

const { Logger, Transform, Filter, Human } = require('caterpillar')
const level = 5
const logger = new Logger({ lineLevel: level })

const { createWriteStream } = require('fs')
logger.pipe(createWriteStream('./debug.log'))

class Uppercase extends Transform {
    format(entry) {
        if (entry.levelNumber <= 4) {
            entry.args.forEach(function (value, index) {
                if (typeof value === 'string') {
                    entry.args[index] = value.toUpperCase()
                }
            })
        }
        return entry
    }
}

logger
    .pipe(new Filter({ filterLevel: 5 }))
    .pipe(new Uppercase())
    .pipe(new Human())
    .pipe(process.stdout)

logger.log('warn', 'this is a warning, which is level', 4)
logger.warn('this is a warning, which is level', 4)
logger.log('debug', 'this is a debug message, which is level', 7)
logger.warn('this is a debug message, which is level', 7)

Finally, if we are using Caterpillar in web browser environments, instead of Node.js, instead of doing:

const { Logger, Transform, Filter, Human } = require('caterpillar')
// ...
logger.pipe(new Human()).pipe(process.stdout)
// ...

We would pipe to the Browser transform instead of to stdout.

const { Logger, Transform, Filter, Human, Browser } = require('caterpillar')
// ...
logger.pipe(new Human()).pipe(new Browser())
// ...

With this, you now have enough information to leverage the cross-platform power of Caterpillar for most purposes, and the power to write your own custom transforms which can be published as their own packages and shared.

Install

  • Install: npm install --save caterpillar
  • Import: import * as pkg from ('caterpillar')
  • Require: const pkg = require('caterpillar')
import * as pkg from 'https://unpkg.com/caterpillar@^8.2.0/edition-deno/index.ts'
<script type="module">
    import * as pkg from '//cdn.skypack.dev/caterpillar@^8.2.0'
</script>
<script type="module">
    import * as pkg from '//unpkg.com/caterpillar@^8.2.0'
</script>
<script type="module">
    import * as pkg from '//dev.jspm.io/[email protected]'
</script>

This package is published with the following editions:

  • caterpillar aliases caterpillar/index.cjs which uses the Editions Autoloader to automatically select the correct edition for the consumer's environment
  • caterpillar/source/index.ts is TypeScript source code with Import for modules
  • caterpillar/edition-browsers/index.js is TypeScript compiled against ES2022 for web browsers with Import for modules
  • caterpillar/edition-es2022/index.js is TypeScript compiled against ES2022 for Node.js 14 || 16 || 18 || 20 || 21 with Require for modules
  • caterpillar/edition-es2017/index.js is TypeScript compiled against ES2017 for Node.js 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with Require for modules
  • caterpillar/edition-es2015/index.js is TypeScript compiled against ES2015 for Node.js 6 || 8 || 10 || 12 || 14 || 16 || 18 || 20 || 21 with Require for modules
  • caterpillar/edition-es5/index.js is TypeScript compiled against ES5 for Node.js 4 || 6 || 8 || 10 || 12 || 14 || 16 with Require for modules
  • caterpillar/edition-es2017-esm/index.js is TypeScript compiled against ES2017 for Node.js 12 || 14 || 16 || 18 || 20 || 21 with Import for modules
  • caterpillar/edition-types/index.d.ts is TypeScript compiled Types with Import for modules
  • caterpillar/edition-deno/index.ts is TypeScript source code made to be compatible with Deno

History

Discover the release history by heading on over to the HISTORY.md file.

Backers

Code

Discover how to contribute via the CONTRIBUTING.md file.

Authors

Maintainers

Contributors

Finances

GitHub Sponsors donate button ThanksDev donate button Patreon donate button Liberapay donate button Buy Me A Coffee donate button Open Collective donate button crypto donate button PayPal donate button

Sponsors

  • Andrew Nesbitt — Software engineer and researcher
  • Balsa — We're Balsa, and we're building tools for builders.
  • Codecov — Empower developers with tools to improve code quality and testing.
  • Poonacha Medappa
  • Rob Morris
  • Sentry — Real-time crash reporting for your web apps, mobile apps, and games.
  • Syntax — Syntax Podcast

Donors

License

Unless stated otherwise all works are:

and licensed under:

caterpillar's People

Contributors

balupton avatar dependabot-preview[bot] avatar dependabot[bot] avatar github-actions[bot] avatar thelfensdrfer 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

caterpillar's Issues

logger.log and then process.exit doesn't show anything

When I want to log an error and exit a process nothing gets outputted.

example

if somethingBad
    logger.log "error", "something bad happended"
    process.exit 1

But if I use console.log instead it will output the message.

Is there a way to flush the logger?

problem with deno sample on https://repl.it/@balupton/caterpillar-deno#index.ts

running the sample from https://repl.it/@balupton/caterpillar-deno#index.ts with deno (version 1.4.2) I receive the error

error: Import 'https://unpkg.com/[email protected]/edition-deno/index.ts' failed: 404 Not Found
Imported from "https://unpkg.com/[email protected]/edition-deno/logger.ts:1"

a solution was to import the library not with unpkg.com but with jspm.dev

import { Logger, Filter, Human } from 'https://jspm.dev/caterpillar'

or skypack.dev

import { Logger, Filter, Human } from 'https://cdn.skypack.dev/caterpillar'

In this way the sample works perfectly

Getting Started docs needed.

I tried a demo and had a quick look at the docs, but what I'm missing is a plain English getting started section. I'm not into typescript and often find wading through code generated docs painful and I give up and move on. My 2c.

Logger metadata

Various loggers enable metadata to be included in logger output. In Pino etc. this is handled by child loggers. In Consola you can use log.wthTag( name ) to create a logger with a name.

This enables you to know more about the source of log entries. It is especially important when filenames aren't included in the log output, or where filenames are useless such as in the browser when all source files are bundled together in one file.

I can't see a way to accomplish this in caterpillar at present.

My suggestion is to allow a metadata object to be included in Logger( LoggerOptions ). This would then be included in LogEntry and therefore available everywhere.

You would then do new Logger( { metaObj, ... } ) to create the logger instances you needed.

I would also use the metaObj in a Filter() transform to filter out entries matching certain metadata which I'm not interested in at a point in time or only pipe it to a specific target.

Export `ConsoleFormatter`

Hi there!

It doesn't seem like ConsoleFormatter is accessible outside the module -- guess you forgot it in module.exports? :)

Passing options down the pipe

It would be useful to be able to pass options along the pipe.

For example Human has an option color as does Browser, which would typically be set the same. Both default to true, however if you want them to be false then you need to include { color: false } for both.

Instead if Human( opts ) could be passed to Browser etc. both client code and usage would be simplified as { color: false } would only need to be specified once.

Similarly it would be handy if LogEntry could be passed down the pipe then the Browser transform could access LogEntry passed to Human().

Finally it would be useful if Transform's could access Logger options.

I do however realize that these suggestions maybe outside the design scope or even unwanted.

Formatting output

I would like to add a line break between each log entry in my file, how can I do that?

Does default level really work?

Following your document example to the letter but for:

// Import
var level  = process.argv.indexOf('-d') === -1 ? 6 : 7;
var logger = new (require('caterpillar').Logger)({level:level});
var filter = new (require('caterpillar-filter').Filter)();
var human  = new (require('caterpillar-human').Human)();

The following doesn't seem to have any effect:

logger.log('this is level 6, the default level');

More control over formatter config

Hi

It seems that there is no easy way to easily customize the message output in the console. For example while using docpad regularly, I find it a bit cluttered because of the huge size of the filePath / lineNumber every 2 lines.

There may be a way to do it now, by extending the Console Formatter class and overloading the format class but issue #1 has to be fixed to export Console Formatter in the first place.

The ideal will be to be able do to it through config arguments.

flow type complaining with recent flow type version

> flow check

node_modules/caterpillar/source/logger.js:237
237:            const err = new Error()
                            ^^^^^^^^^^^ constructor call
247:                    stack = err.__previous__ && err.__previous__.stack
                                                                     ^^^^^ property `stack`. Property cannot be accessed on
247:                    stack = err.__previous__ && err.__previous__.stack
                                                    ^^^^^^^^^^^^^^^^ property `__previous__` of unknown type

node_modules/caterpillar/source/logger.js:237
237:            const err = new Error()
                            ^^^^^^^^^^^ constructor call
260:                    lines = stack.toString().split('\n')
                                ^^^^^^^^^^^^^^^^ call of method `toString`. Method cannot be called on
260:                    lines = stack.toString().split('\n')
                                ^^^^^ property `__previous__` of unknown type

node_modules/caterpillar/source/logger.js:285
285:                const parts = line.split(':')
                                  ^^^^^^^^^^^^^^^ call of method `split`
 11:    line:number,
             ^^^^^^ number. This type is incompatible with the expected return type of
256:     split(separator: string | RegExp, limit?: number): Array<string>;
                                                                  ^^^^^^ string. See lib: /private/tmp/flow/flowlib_25e12824/core.js:256


Found 3 errors

Only fetch line info if a new `debug` config option is true (false by default)

Update catepillar-human to use debug property.

This will be a major breaking change. As instead of just doing .setConfig({level: 7}) if they want debugging, they must now also do .setConfig({debug: true, level: 7}).

So will need to have to do something for this... Perhaps something like:

const config = this.getConfig()
const debug = config.debug != null ? config.debug : config.level === 7

However, if we specify a default like false, then the above won't work.

Maybe just gotta break b/c compat.

Would also be interesting to see the performance comparison of this.

LineInfo and Curriyng

I've extended the Logger to be used with Socket.io. I map each log levels to a new method :
log.info(msg) is equal to log('info', msg) but when I log, the lineinfo refers to the logger function, instead of the real place the logging method is called.

Is there a way to configure where to get the stack info from?

lib/logger.js

var _ = require('lodash');

module.exports = function(level){
    var logger = new (require('caterpillar').Logger)({level:level});
    var filter = new (require('caterpillar-filter').Filter)();
    var human  = new (require('caterpillar-human').Human)();

    this.levels = logger.config.levels;

     // Pipe logger output to filter, then filter output to stdout
    logger.pipe(filter).pipe(human).pipe(process.stdout);


      //map  each level to a method
      _.keys(this.levels).map(function mapLevel(levelName){
         logger[levelName] = function(msg){
             return logger.log.apply(logger, [levelName].concat(arguments));
          }
      });

      return logger;
  };

GIving the logger to socket.io

var logger = require('./lib/logger')(7);
var io = require('socket.io').listen(server, {logger : logger});

Then I got this output:

info: { '0': 'socket.io started' }
    → [2013-06-29 17:10:12.018] [anonymous function) [as info] (/home/bertrand/dev/workspace/node-htop/lib/logger.js:28] [Logger.logger.(anonymous function) [as 
```)

Getting Error while running on Browser using vite package manager

Issue :

  • Trying to use caterpillar logger in an frontend app ( using vite, react etc ) on browser
  • Getting error in the console and unable to proceed further

> Logger Instantiation Code

import { Logger, Human, Browser } from 'caterpillar';

// Caterpillar logger
const cLogger = new Logger();
cLogger.pipe(new Human()).pipe(new Browser());

cLogger.log('warn', 'this is a warning, which is level', 4);
cLogger.warn('this is a warning, which is level', 4);

> Error On Console

browser-external:util:9 Module "util" has been externalized for browser compatibility. Cannot access "util.inspect" in client code. See https://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
get @ browser-external:util:9

human.js:72 Uncaught (in promise) TypeError: (0 , import_util.inspect) is not a function
    at human.js:72:15
    at Array.map (<anonymous>)
    at Human.formatArguments (human.js:70:14)
    at Human.format (human.js:105:24)
    at Human.write (transform.js:28:27)
    at transform.js:38:32

> Package.json File Contents

{
  "name": "vite-react-zustand-tryout",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "auto-zustand-selectors-hook": "^2.0.0",
    "caterpillar": "^8.2.0",
    "immer": "^10.1.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "zustand": "^4.5.2"
  },
  "devDependencies": {
    "@types/react": "^18.2.66",
    "@types/react-dom": "^18.2.22",
    "@vitejs/plugin-react-swc": "^3.5.0",
    "autoprefixer": "^10.4.19",
    "eslint": "^8.57.0",
    "eslint-plugin-react": "^7.34.1",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.6",
    "postcss": "^8.4.38",
    "tailwindcss": "^3.4.3",
    "vite": "^5.2.0"
  }
}

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.