Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

ts-logs

4lessandrodev149MIT0.3.0TypeScript support: included

This package provide a skd for audit and manager logs in nodejs and express

Logs, Logging, Audit Log, Log File, Debug, Persist Log, Express Logs, Publish Log, Log to AWS, Log to S3, Axios Log

readme

ts-logs

Understand what happens in your application. Manage your logs and audit the steps of each request.

checks stars commits last commit license dependabot tags issues issues

About the lib

This package provide a sdk to manage logs.


Installation

install using yarn or npm


$ npm install ts-logs

# OR

$ yarn add ts-logs

Documentation

Example

import { Log, Step } from 'ts-logs';

// create a global log
const log = Log.init({ name: 'First Log', origin: 'https://global.com' });

// create steps
const info = Step.info({ message: 'Fetching api...', name: 'Request Login', method: 'POST' });
const error = Step.error({ message: 'Timeout', name: 'Login', stack: 'Error stack' });

// add steps to global log
log.addSteps([ info, error ]);

// print or save logs
log.print();
await log.writeLocal();
await log.publish(config);

Use a Singleton Instance Globally

You can use a global log to publish once on finish all process


import { GlobalLog, Config } from 'ts-logs';

const global = GlobalLog.singleton();

// ...

global.addStep(step);

// ...

await global.publish(Config.Mongo({ url: 'mongodb://localhost:27017' }));

// remember when using global log as singleton clear steps
global.clear();

Create step from catch block

Create a step instance from error. This method get many important information from axios error.


class DoSomething {
    async execute(data: Data): Promise<void> {
        try {

            // try do something ...
            await axios.post(url, data);

        } catch(error) {

            // create step instance from error
            global.addStep(Step.catch(error));
        }
    }
}

Log object

Example generated log. The log is a json object with array of step object


{
  "uid": "1c7e5aca-c9f4-4e33-a5e7-d8a9cfe94053",
  "name": "Log Example",
  "ip": "127.0.0.1",
  "origin": "http://127.0.0.1:3000",
  "createdAt": "2023-02-05T23:00:40.481Z",
  "stateType": "stateful",
  "steps": [
    {
      "name": "Find Item",
      "category": "none",
      "tags": ["item", "product", "card"],
      "url": "https://my-app.com/products/1",
      "stack": "none",
      "data": "none",
      "statusCode": 200,
      "message": "Fetching api...",
      "type": "info",
      "method": "GET",
      "createdAt": "2023-02-05T23:00:40.481Z",
      "uid": "673e17fb-55aa-4ea9-8668-e34b94bfd22c",
      "additionalInfo": "a complementary information"
    }
  ]
}

Use as middleware

Express middleware to capture app errors.


import express from 'express';
import { stackLog } from 'ts-logs';

const app = express();
app.use(express.json());

// ...
app.use(routes);

// last middleware to handle errors using `stackLog` all errors will be intercepted.
app.use(stackLog({ writeLocal: true })); // <------ middleware

app.liste(3000);

Bind

You also may use bind middleware to apply a log instance to request


import express from 'express';
import { bindLog, Config } from 'ts-logs';

const app = express();
app.use(express.json());

// on top of routes you can bind a log instance to request
app.use(bindLog()); // <------ middleware

app.get("/log", async (req: Request, res: Response) => {

    // you can do anything with log instance from request.
    req.log.addStep( /* any step */ );
    req.log.print(); // show steps on terminal
    await req.log.publish(Config.S3(/* ... */)) // publish to s3

    res.status(200).json(req.log);
});

// ...

app.use(routes);

Use as middleware step

if you use many steps as middleware you can use global log


import express from 'express';
import { bindLog, Config } from 'ts-logs';

const app = express();
app.use(express.json());

// on top of routes you can bind a log instance to request
app.use(bindLog()); // <------ middleware

app.get("/process", (req: Request, res: Response, next: NextFunction) => {

    // you can do anything with log instance
    req.log.addStep( /* info step */ ); // <------ add step to global log state.

    // call next step
    next();
}, (req: Request, res: Response, next: NextFunction) => {

    // you can do anything with log instance
    req.log.addStep( /* error step */ ); // <------ add step to global log state.

    // call next step
    next();
}, async (req: Request, res: Response, next: NextFunction) => {

    // you can do anything with log instance
    req.log.addStep( /* stack step */ ); // <------ add step to global log state.

    // publish log with steps to aws s3
    await req.log.publish(Config.S3(/* ... */));

    // send log to client
    res.status(200).json(req.log);
});

// ...

app.use(routes);

Publish log automatically

you can use in conjunction with binding middleware other middleware to automatically publish logs to your preferred provider.


import express from 'express';
import { bindLog, autoPublishLog, Config } from 'ts-logs';

const app = express();
app.use(express.json());

// on top of routes you can bind a log instance to request
app.use(bindLog()); // <------ middleware

// after `bindLog` add `autoPublishLog` to automatically publish logs
app.use(autoPublishLog(Config.S3())); // <------ middleware

app.get("/log", async (req: Request, res: Response) => {

    // you can do anything with log instance from request.
    req.log.addStep( /* any step */ ); // <------ add step to publish

    res.status(200).json(req.log);
});

// ...

app.use(routes);

Secure logs

It is possible to remove any key from body (data) or encrypt some sensitive information

Removing data


const name = "Step Test";
const data = JSON.stringify({ password: "123456", name: "Jane" });

const step = Step.create({ name, data });

const updated = step.remove(["password"]);

console.log(updated.data);

> "{ \"name\": \"Jane\" }"

// or encrypt attribute

step.encrypt({ attributes: ["password"], secretKey: "my-secret-key" });

Hidden Value - Mask

you can mask any key value in step data. provide the key name you want or the path. example user.password for specific key in user object or password for any key called password


const name = 'sample';

const data = { 
  info: 'secret-text', 
  user: { 
    name: 'Jane',
    password: '12345'
  }
};

const step = Step.create({ name, data });

const updated = step.mask([ { key: 'password' } ]);

console.log(updated);
{
  info: 'secret-text', 
  user: { 
    name: 'Jane',
    password: '*****'
  } 
}

Encrypt data

Encryption is also available for stackLog and as cypher.


app.use(
  stackLog({ 
    writeLocal: true, 
    encrypt: true, 
    encryptOption: { 
      level: "cypher",
      secretKey: "my-secret-key"
    } 
  })
);

Flows

Flows using middleware

Using bindLog combined with autoPublishLog middleware

flow

Using bindLog combined with stackLog middleware

flow

changelog

Changelog

All notable changes to this project will be documented in this file.

Unreleased


Released


[0.3.0] - 2024-10-22

Fix

  • Support for nodejs v23
  • Update deps

[0.2.0] - 2024-10-22

Feat

  • feat: use toJSON method from axios instance
  • fix: ensure delete logs files for 0 days

[0.1.5] - 2023-12-15

Fix

  • fix: update deps

[0.1.4] - 2023-04-27

Fix

  • fix: ensure publish method create all index on unique command.
  • fix: ensure on publishdo not replace steps on existing log,

[0.1.3] - 2023-04-26

Fix

  • fix: ensure reset createdAt attribute for a new date on clear GlobalLog

[0.1.2] - 2023-04-24

Feat

  • feat: added ttl option to expire log
  • feat: added ignore empty step on publish
  • feat: added clear step after publish

log.publish(
    Config.Mongo({
        url: 'mongodb://mongo:mongo@localhost:27017',
        clearAfterPublish: true,
        expireAfterDays: 7, // default 30 days
        ignoreEmpty: true
    })
);

[0.1.1] - 2023-04-17

Fix

  • fix: added mongo config type to autoPublish middleware

[0.1.0] - 2023-04-16

Feat

  • feat: added support to mongodb provider
  • added global log as singleton
  • added category atribute to step
  • added mask option to stackLog middleware

Now Its possible create an unique instance of log globally using


import { GlobalLog } from 'ts-logs';

const global = GlobalLog.singleton();

// ...
// remember clear steps after publish or write local
global.clear();

Now Its possible publish log to mongodb

The operation is updateOne with upsert=true based on log.uid and log.name. If already exists some log them update else insert


await log.publish(Config.Mongo({ url: 'mongodb://localhost:27017' }));

Now you can categorize the step

Based on your business rule Its possible define a category to a step


Step.info({ name: 'some', message: 'info', category: 'financial' });

Now Its possible add mask to stackLog

The middleware stackLog accept mask config


stackLog({
    writeLocal: true,
    mask: [ { key: 'password' } ]
})

[0.0.18] - 2023-04-13

Feat

  • feat: added deleteExpiredFile method to remove expired files from local log folder.

[0.0.17] - 2023-04-12

Fix

  • fix: update mask regex to replace any char instead only alphanumeric one

[0.0.16] - 2023-04-12

Docs

  • doc: added README.md as doc file

[0.0.15] - 2023-04-12

Feat

  • step: feat added mask method to step instance. Now Its possible to hidden values with * char.

[0.0.14] - 2023-03-31

Feat

  • step: feat added support to data as object

[0.0.13] - 2023-02-11

Fix

  • fix: fix GetFileName to add 0 when day number is less than 10.
  • fix: fix getStepDataFromRequest to ignore tag keys when body data is array.
  • fix: ensure get tags from data as attribute key if do not provide tag value.
  • fix: ensure encrypt and decrypt sub object key

[0.0.12] - 2023-02-10

Feat

  • feat: added "encrypt" function to step.

[0.0.11] - 2023-02-07

Fix

  • fix: use "index" as default when stackLog from main route.
  • fix: changing any log state if it is set as "stateful" stateType.

Feat

  • feat: added "additionalInfo" attribute to step.

Change

  • change: rename attribute "addBehavior" to "stateType" on log.

[0.0.10] - 2023-02-05

Feat

  • feat: added remove method to remove keys from body on step instance

Fix

  • fix: ensure get id from body if exists and apply to step instance

[0.0.9] - 2023-02-05

Feat

  • feat: added autoPublishLog middleware

[0.0.8] - 2023-02-04

Feat

  • feat: added provider to publish to aws S3
  • feat: added provider to publish to an endpoint by http request.

[0.0.7] - 2023-02-03

Fix

  • fix: get caller class name from error.

[0.0.6] - 2023-02-03

Fix

  • fix: get tags from catch error and format data on error.

[0.0.5] - 2023-02-03

Added

  • added: implement Step.catch(err) to create a step from Error.

Fix

  • fix: write local file
  • fix: remove keys from sub object in body or data using remove: [] option

[0.0.4] - 2023-02-01

Added

  • added: implement bindLog to bind a log instance to request.

[0.0.3] - 2023-01-31

Fix

  • fix: added step on write local log
  • fix: change step from info to stack

Changed

Breaking change

  • rename: from LOGMiddleware to stackLog

[0.0.2-beta.0] - 2023-01-31

Changed

  • log: change generated file name to .log

Added

  • log: added middleware builder
  • log: added "method" attribute to step as "GET", "POST" ... option

[0.0.1-beta.2] - 2023-01-29

Added

  • log: format messages for each category
  • [ ERROR ]: Step.error(props)
  • [ DEBUG ]: Step.debug(props)
  • [ INFO ]: Step.info(props)
  • [ FATAL ]: Step.fatal(props)
  • [ WARN ]: Step.warn(props)
  • [ STACK ]: Step.stack(props)
  • [ UNDEF ]: When create step with invalid type
  • [ LOG ]: When create a global log - Log.ini()

Change

  • log: remove console.log and use process.stdout

[0.0.1-beta.1] - 2023-01-29

Added

  • log: added global log
  • log: added step log
  • log: added print function
  • log: added save local log on txt file

[0.0.1-beta.0] - 2023-01-27

Added

  • log: create base lib