npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@financial-times/n-event-logger

v0.0.7

Published

log all your API service calls and function calls with a single line of code

Downloads

23

Readme

n-event-logger CircleCI Coverage Status

log all your API service calls and function calls with a single line of code

quickstart

import { withLogger, withServiceLogger, eventLogger } from '@financial-times/n-event-logger';
// enhancer function names might be changed to the following after alpha
import { autoLog, autoLogAll, eventLogger } from '@financial-times/n-event-logger';

auto log different status of a function call (commonly an action under an operation)

const data = await withLogger(yourCallFunction)(params, meta);
const result = withLogger(someOtherFunction)(params, meta);

enhance all methods in api service module ensure that it would be logged wherever used

/*-- some-api-service --*/
export default withServiceLogger{ CallA, CallB };

/*-- some-controller-or-middleware --*/
import APIService from 'some-api-service';

await APIService.CallA(params, meta);
await APIService.CallB(params, meta);

more strcutured operation/action log

const meta = { transactionId, userId, operation };
const event = eventLogger(meta);

try {
    event.action('someAction').success();
    event.success();
} catch(e) {
    event.failure(e);
}

set key names of fields to be muted in .env to reduce log for development

LOGGER_MUTE_FIELDS=transactionId, userId

before/after

// before
try {
    logger.info(meta, { action: 'yourCallFunction' }, params);
    const data = await yourCallFunction(params, metaSubset);
    logger.info(meta, { action: 'yourCallFunction' }, params, { result: 'success' });
} catch(e) {
    // some error handling and parsing...
    logger.info(meta, { action: 'yourCallFunction' }, params, { result: 'failure' }, parsedError);
}
// after: 7+ lines (depends on error parsing) => 1 line
const data = await withLogger(yourCallFunction)(params, meta);
const meta = { transactionId, userId, operation };

// before
logger.info(meta);
try {
    logger.info(meta, { action: 'someAction', result: 'success' });
    logger.info(meta, { result: 'success' });
} catch(e) {
    // some error hanldling and parsing
    logger.error(meta, { result: 'failure' }, parsedError);
}

// after: some less key strokes
const event = eventLogger(meta);
try {
    event.action('someAction').success();
    event.success();
} catch(e) {
    event.failure(e);
}

install

npm install @financial-times/n-event-logger

gotcha

function args format standard

One opinionated pre-requisite is to have the callFunction input format as (params, meta) so that the callFunction can be invoked correctly with extra meta for logger

exception/error

out-of-box parse support for the following standard types of errors

  • Fetch Response Error
  • Fetch (Network) Error
  • Node Native Error Objects

if your custom Error types are extended from native Error class, the logger might not be able to pick up custom information fields well, just use an object not constructed by Error

usage

enhance a single API service call

/*-- api-service.js --*/
import { withLogger } from '@financial-times/n-event-logger';

export const callSomeAPIService = (params, meta) => {
    const options = {
        headers: {
            /* some meta data specific headers... */
        }
    };

    /* maybe some code before fetch... */

    return fetch(url, options)
        .then(/* some code for response... */)
        .catch(/* some error hanlding... */);
}

// this would record the name of the function 'callSomeAPIService' as action in the logger automatically
export const enhancedCallSomeAPIService = (params, meta) => withLogger(callSomeAPIService)(params, meta);

/*
    currently async/await is needed for the logger to work correctly, update coming soon
 */

/*-- middleware/controller.js --*/
import { enhancedCallSomeAPIService } from '../api-service';

const someOperationFunction = async (req, res, next) => {
    const meta = {
        /* some fields for headers */
        transactionId: req.transactionId,
        /* extra fields for loggers */
        operation: 'someOperation',
        userId: req.userId,
    };

    try{
        await enhancedCallSomeAPIService(params, meta);
    } catch (e) {
        next(e);
    }
}

info: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, action: callSomeAPIService

info: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, action: callSomeAPIService, status: success


depends on the error status code, it would log as warn for 4XX, and error for 5XX

warn: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, action: callSomeAPIService, status: failure, message: some error message

error: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, action: callSomeAPIService, status: failure, message: some error message

enhance a whole series of API service call

/*-- api-service.js --*/
import { withServiceLogger } from '@financial-times/n-event-logger';

export const apiServiceCallA = (params, meta) => {}
export const apiServiceCallB = (params, meta) => {}

// helper to enhance all API service call functions as object methods
export default withServiceLogger{
    apiServiceCallA,
    apiServiceCallB
};

/*-- middleware/controller.js --*/
import SomeAPIService from '../some-api-service';

const someOperationFunction = async (req, res, next) => {
    const meta = {
        transactionId: req.transactionId,
        userId: req.userId,
        operation: 'someOperation',
    };

    try{
        await someAPIService.apiServiceCallA(params, meta);
        await someAPIService.apiServiceCallB(params, meta);
    } catch (e) {
        next(e);
    }
}

log your operation in structure with loggerEvent

/*-- middleware/controller.js --*/
import { loggerEvent } from '@financial-times/n-event-logger';
import SomeAPIService from '../some-api-service';

const someOperationFunction = async (req, res, next) => {
    const meta = {
        transactionId: req.transactionId,
        userId: req.userId,
        operation: 'someOperation',
    };
    const event = loggerEvent(meta);

    try{
        const a = await someAPIService.apiServiceCallA(params, meta);
        const b = await someAPIService.apiServiceCallB(params, meta);
        /* some other code... */
        const c = someFunction(a, b);
        event.success({ c });
        /* some other code... */
    } catch (e) {
        event.failure(e);
        next(e);
    }
}

info: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation

... some more process info log from various actions

info: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, status: success, data: { "c": 'values are stringified JSON' }


info: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation

... some more process info log from various actions

error: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, action: apiServiceCallB, result: failure, message: "some message"

error: transactionId: xxxx-xxx, userId: xxxx-xxx, operatoin: someOperation, status: failure, message: "error message"

logs help you track down exactly which function call leads to the operation failure with what params in call in what context


auto log non-api-service function with withLogger enhancer

import { loggerEvent, withLogger } from '@financial-times/n-event-logger';

const someFunction = (a, b) => {
    try {
        /* some code... */
        return c;
    } catch(e) {
        /* some error handling... */
        // function needs to throw error or return Promise.reject() for failure status to be logged
        throw e;
    }
}

const someOperationFunction = async (req, res, next) => {
    const meta = {
        transactionId: req.transactionId,
        userId: req.userId,
        operation: 'someOperation',
    };
    const event = loggerEvent(meta);

    try{
        const a = await someAPIService.apiServiceCallA(params, meta);
        const b = await someAPIService.apiServiceCallB(params, meta);
        /* some other code... */
        // await is needed for the result status logger to work correctly
        const c = await withLogger(meta)(someFunction)(a, b);
        event.success({ c });
        /* some other code... */
    } catch (e) {
        event.failure(e);
        next(e);
    }
}

track some non-api-service function on the fly

/*-- middleware/controller.js --*/
const someOperationFunction = async (req, res, next) => {
    const meta = {
        transactionId: req.transactionId,
        userId: req.userId,
        operation: 'someOperation',
    };
    const event = loggerEvent(meta);

    try{
        const a = await someAPIService.apiServiceCallA(params, meta);
        const b = await someAPIService.apiServiceCallB(params, meta);
        /* some other code... */
        if(someCondition && someCheck){
            event.action('someAction').success();
        } else {
            event.action('someAction').failure();
            throw ;
        }
        /* some other code... */
        event.success();
        /* some other code... */
    } catch (e) {
        event.failure(e);
        next(e);
    }
}

test stub

import * as nEventLogger from '@financial-times/n-event-logger';

//example using sinon sandbox, will look into provide testStub as a module based on sinon/jest
const stubLoggerEvent = meta => ({
    // add more stubs to methods if you want
    start: () => null,
    success: () => null,
    failure: () => null,
    action: () => stubLoggerEvent(meta)
});
sandbox.stub(nEventLogger, 'loggerEvent').callsFake(stubLoggerEvent);
sandbox.stub(nEventLogger, 'withLogger').callsFake(
    callFunction => (params, meta) => callFunction(params, meta)
);
sandbox.stub(nEventLogger, 'withServiceLogger').callsFake(service => service);

development

  • make install
  • yarn test --watch to automatically run test on changing src
  • yarn watch to automatically correct code format on saving src

todos

  • middleware/controller one-line enhancer
  • consider integrating .addContext() from n-logger