1.0.0 • Published 6 years ago

web-central-logging v1.0.0

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

Build Status Coverage Status Maintainability

web-central-logging

Utilities for aggregating frontend logs

  • Automatically send logs to syslogs/rsyslog
  • Redux middlewares for logging actions and crashes
  • Highly customizable

Installation

npm install web-central-logging

or

yarn add web-central-logging

Usage with Redux

import { applyMiddleware, createStore, compose } from 'redux';

import WebCLS, { crashReporter, actionLogger } from 'web-central-logging';

const logger = new WebCLS({ url: '/logs', maxBufferLength: 10 });

const store = createStore(
  reducer,
  initialState,
  applyMiddleware([
    crashReporter(logger),
    // ...
    actionLogger(logger)
  ])
);

Usage without redux

import WebCLS from 'web-central-logging';

const logger = new WebCLS({ url: '/logs', maxBufferLength: 10 });

logger.info({ message: 'User has logged in' });

someCallback((err) => {
    if(err) {
        logger.error(err);
    }
});

WebCLS will send the buffered logs in a POST request to the backend.

check server config for more details.

ActionLogger

actionLogger(logger [, options]) is a redux middleware that adds redux actions into the WebCLS's buffer as info level logs.

PropertyRequiredTypeDefaultDescription
actionFilterNoFunctionf => ffunction to filter actions See more
stateFilterNoFunction() => nullfunction to filter state See more
levelNoStringinfosyslog level

actionFilters and stateFilters can be applied to filter out what is logged. see more

CrashReporter

crashReporter(logger [, options]) is a redux middleware which reports any crash, uncaught errors & uncaught promises to WebCLS.

PropertyRequiredTypeDefaultDescription
stateFilterNoFunction() => nullfunction to filter state See more
levelNoStringinfosyslog level

WebCLS

WebCLS(config)

PropertyRequiredTypeDefaultDescription
urlYesString_Url at with logs should be sent
maxBufferLengthNoNumber100size of buffer after which logs will be flushed to the server
sessionIdRequiredNoBooltrueLogs will only be sent if a session has been made by setting a sessionId using logger.setSessionId
intervalNoNumbernoneLogs will be sent if Buffer is full or Timer has passed the interval
overwriteBufferNoBooltrueif set false old logs will not be overwritten unless logs are flushed explicitly using logger.flush()
automaticFlushNoBoolflushautomatically flushes logs if buffer is full or interval has passed
fetchConfigNoObject{}send extra fetch parameters like headers, cookies etc. This follows TC39 standard
extraParamsNoObject{}send extra fields with each log
fireOnGlobalErrorsNoBooltrueThis will flush all the logs to the server if there is an uncaught error
__send__NoFunction_Setting this will overwrite the default Flushing behaviour.
Methods
logger.info(log[, state])
logger.warn(log[, state])
logger.error(log[, state])
logger.debug(log[, state])
logger.emerg(log[, state])

NOTE: state can be anything that represents the state of application at time of log

logger.flush()

Calling flush will flush all the current logs to the server. return a fetch promise.

logger.addHooks(function)

Hooks are functions that receives the Buffered logs and sessionId

Note: Hooks are automatically called before flush so mutating the logs array will result in mutation in subsequent hooks call and flush call as well.

Example

Register WebCLS's sessionId with Sentry

    logger.addHook((logs, sessionId) => {
        if (typeof Raven !== 'undefined') {
            Raven.setDataCallback((data) => {
                data.extra.sessionURL = sessionId;
                return data;
            });
        }
    });
logger.setSessionId(string)

It is used to set session Id. eg: when a user logs in, logger.setSessionId(string) can be called inside a reducer to create a session

logger.setExtraDataCallback(function)

This can be used to pass extra fields to every single log line.

It is called before every logging.

Filters

Filters are pure functions which filters the data to be logged. They are highly useful when you want to hide sensitive data in logs or reduce the payload size. Filters should be pure functions.

There are two types of Filters

ActionFilter

This is used to filter Actions. By default everything in action is logged

Example
// Filter.js

function actionFilter(action) {
  switch (action.type) {
    // do not log actions that starts with @@
    case /^@@/.test(action.type): 
      return null; // return null to Skip logging
    case action.type === 'PAYMENT_INIT': 
      // trim userCardInfo field from action
      const newAction = JSON.parse(JSON.stringify(action)); // As filters are pure
      delete newAction.userCardInfo;
      return newAction;
    default:
      return action;
  }
}

StateFilter

This is used to filter state. By default state is not logged but if you want to log state this filter can be used.

Example
// Filter.js

function stateFilter(state, action) {
    const newState = JSON.parse(JSON.stringify(state));
    switch (action.type) {
        case 'ADD_TO_CART':
            return {
                products: newState.products
            };
        case 'USER_LOGGED_IN':
            // let's say we don't want to log access token
            newState.user.accessToken = null;
            return {
                user: state.user
            };
        default:
            return null; // don't log state
    }
}

Server

By default WebCLS will send a fetch request to url field provided in the config.

Integration with Express

WebCLS comes with a middleware for express that send logs to syslogs

// app.js 

const express = require('express');
const bodyparser = require('body-parser');
const syslogsLogger = require('web-central-logging/lib/syslogsLogger');

const app = express();

app.use(bodyParser.json());
app.use('/logs', syslogsLogger({ name: 'myApp' }));

//...

module.exports = app;

syslogsLogger(name [,level, facility, streams])

PropertyRequiredTypeDefaultDescription
nameYesString_Your app's name which will be reflected in syslogs
levelNoStringdebugMinimum allowed Stream level. eg: if level is error then only error or higher level logs will pass through and lower level logs like info, debug will not appear in syslogs
facilityNobsyslog facilitybsyslog.local4see here
streamsNo[bunyan stream]_see here

Request Body

In case you are not using express as backend or want to do something different with logs, you can easily do that as WebCLS sends a POST request to provided url.

Example
    {
        "message": [{
            "timestamp": 1514311801722,
            "action" : {
                "type": "MY_FIRST_ACTION",
                "payload": "Some payload",
            },
            "level": "info",
            "extra" : {},
            "state": {
                "before": {
                    "key": "i am the filtered state before action"
                },
                "after": {
                    "key": "i am the filtered state after action"
                }
            },
        }],
         "sessionId": "ua78bxj34",
    }
  • message is an Array of logs
  • sessionId can be set using logger.setSessionId(id), if not set this field will be undefined.
  • timestamp is the time at which log was registered.
  • action is a filtered or default redux action.
  • state is a filtered or default redux state. By default it is {}
  • extra this field can be used to send extra params with each logs by setting extraParams object in WebCLS config
  • level is syslog level, actionLogger sets level info for each log and crashReporter sets error level for each log.

How to Contribute

  1. yarn or npm install to install npm development dependencies.
  2. yarn build or npm run build will compile the source into dist.
  3. yarn test or npm run test will run the unit test suit.

License

MIT