1.1.6 • Published 5 years ago

tag-logger v1.1.6

Weekly downloads
-
License
ISC
Repository
-
Last release
5 years ago

tag-logger

A tag-supporting logger for client-side javascript and typescript which lets you easily turn some or all logs on and off at runtime. Multiple interfaces are also supported.

tag-logger demo video

Contents

Installation

To install run this command:

npm i tag-logger --save

If you want to save logs to file with LoggerCordovaFileInterface, you will need to install cordova-plugin-file plugin in your app.

NOTE: --save option is actually optional in latest versions of npm. Before you had to specify it, to add package to your package.json file. Now this happens by default. If you still use older npm version, you might still need it, but a better idea would be to upgrade npm with npm i -g npm

Quick Start

Before using logger, you should initialize it:

import { Log } from "tag-logger";

Log.initialize();

The initialize method returns a promise which resolves once logger is initialized, so you can await it or use then on it:

async function start() {
    await Log.initialize();
    Log.info("Logger initialized");
}
function start() {
    Log.initialize().then(() => {
        Log.info("Logger initialized");
    });
}

You can also use a generic log method to log to any tag. In this case tag will be automatically created, if it does not exist:

Log.log("info", "hello");

You can also import this log method directly:

import { log } from "tag-logger";

// you still need to call Log.initialize sometime before this
log("info", "Logger initialized");

When initializing, you can also specify whether this is a debug build or not (depending on this, default tags will be set):

Log.initialize({ debug: true/false });

Tags

You need to prefix each log with a tag. Default tags: 'error', 'important', 'verbose', 'info', 'warn', 'ws_request', 'ws_response', 'ws_callback_response', 'http_req', 'http_resp'. You should log errors with tag 'error'. All websocket requests sent to the server should be logged with 'ws_request' tag. All websocket responses received from the server should be logged to 'ws_response' for normal responses and 'ws_callback_response' for callback responses to ws requests. To log http messages use 'http_req' and 'http_resp' logs. These are just recommendations, and you can create and use any tags you want.

Example:

Log.info("hello");                  // this logs with tag 'info'
Log.error("an error has occured");  // this logs with tag 'error'
Log.log("info", "Hello 2");         // this also logs with tag 'info'

Logger uses node's util.format to log data. This means you can use all the same format specifiers to replace parts of your text. Most important of them are %s (gets replaced with a string value) and %j (gets replacesd with json-strigified object). Example:

const name = "Andrei";
const age = 31;
// `My name is Andrei, I am 31 years old` will be logged
Log.info("My name is %s, I am %s years old", name, age);

const me = {
    name: "Andrei",
    age: 31
}

// `me object: {"name":"Andrei","age":31}` will be logged
Log.info("me object: %j", me); // object `me` will only be stringified if "info" tag is turned on!

// Note that using above option is preferential to the option below
// Because in this case `JSON.stringify` will be run even if
// This tag is turned off.
Log.info("me object: "+JSON.stringify(me)); // this will stringify object even log is turned off!

Enabling Tags

Note that for logs to display you need to enable some tags. Some are enabled by default, but which ones, depends on interface:

  • For LoggerBrowserConsoleInterface default types are "error" and "important", "http_req", "http_resp" or only "error" if this is not a debug build.
  • For LoggerEmitLogsInterface which is used to show logs on console-like screens, like debug window on mobile, default tags are: "error", "important", "init", "info.*" (meaning, "anything starting with info") and "http_.*", or only "error" if this is not a debug build.
  • For LoggerCordovaFileInterface these are "error", "important", "init", "ws_.*", "info.*", "table_.*", "http_.*" (for both build types).
  • For LoggerSaveLogsInterface these are "error", "important", "init", "ws_.*", "info.*", "table_.*", "http_.*" (for both build types).

To enable additional tags, you need to pass a comma-separated string containing tags which you want to enable. You can also include symbols .* to show parts which may be substituted with any characters. E.g. Passing a string ".*" will enable all tags. Passing a string "ws_.*" will enable all tags starting with ws_ (i.e. "ws_request", "ws_response", "ws_callback_response").

Enabling Tags From Console

Easiest way to enable tags in browser console is to call "_enableLogs" function with a comma-separated string of tags which you want to enable:

_enableLogs("error,info.*,ws_.*")

Above code will enable the following tags: "error", all tags starting with "info" and all tags starting with "ws" (which should log websocket requests/responses).

Enabling Tags Programmatically

You can either pass this string programmatically to setEnabledLogs method of an interface:

const fileInterface = Log.getInterface("LoggerCordovaFileInterface");
fileInterface.setEnabledLogs("error,info.*,ws_.*");

Enabling Tags with Local Storage

OR you can use localStorage, which is handy when using LoggerBrowserConsoleInterface. You can type the following in browser console to enable logs in browser:

localStorage.__printLogs = "ws_.*,error,info.*"

Then you need to reload your app.

This also works for LoggerEmitLogsInterface:

localStorage.__emitLogs = "ws_.*,error,info";

Don't forget you need to reload your app after that.

Creating New Tags

You can create new tags with Log.newLogger method:

Log.newLogger("my");

Then you log to your tag same way you log to other tags:

Log.my("my log");

If, however, you use generic Log.log method or if you imported log method directly, tags will be created automatically, if they don't exist:

Log.log("my", "my log");

or

import { log } from "tag-logger";

log("my", "my log");

Interfaces

There are 4 interfaces available:

  • LoggerBrowserConsoleInterface which logs data to browser console,
  • LoggerEmitLogsInterface which uses node's EventEmitter to emit logs and can be used for anything,
  • LoggerSaveLogsInterface which saves data in memory to send later to a debug server, and
  • LoggerCordovaFileInterface which saves data to files (only availble in cordova cordova app, and only works if it is built with cordova-plugin-file plugin).

By default, 3 of 4 interfaces are enabled: LoggerBrowserConsoleInterface, LoggerEmitLogsInterface and LoggerSaveLogsInterface. If you want to enable a different set of interfaces, you will need to modify initialize method call:

Log.initialize({
    debug: true/false, // depending on whether this set to true or false, default logs will differ
    interfaces: [
        { type: "LoggerBrowserConsoleInterface" },
        { type: "LoggerEmitLogsInterface" },
        { type: "LoggerSaveLogsInterface" },
        { type: "LoggerCordovaFileInterface", options: {
            maxLogsLength: 5000,
            maxLogFiles: 2
        } },
    ]
});

This initializes all four interfaces. Moreover we set some parameters for LoggerCordovaFileInterface.

To get interface you can use getInterface method of the Log object by passing interface's name:

const browserInterface = Log.getInterface("LoggerBrowserConsoleInterface");

Usually you should only get interface this if you want to enable tags programmatically. However, for LoggerCordovaFileInterface, there are several methods which you might need to use.

LoggerCordovaFileInterface

Logging Process

The LoggerCordovaFileInterface is used to save logs to files. It works the following way:

  1. When anything is logged, it is saved in memory until there are maxLogsLength entries (5000 by default).
  2. Once there are maxLogsLength entries, this data is flushed to file.
  3. A new file is created every day for logs. If there is no file for today, it is created, and, if there are more than maxLogFiles (2 by default) files, oldest file is removed.

These variables, maxLogsLength and maxLogFiles, have default values (5000 and 2 respectively), but you can set them when initializing logger:

// keep maximum 3 files and flush data to file from memory every 1000 entries
Log.initialize({
    debug: true/false,
    interfaces: [
        { type: "LoggerCordovaFileInterface", options: {
            maxLogsLength: 1000,
            maxLogFiles: 3
        } },
    ]
});

Getting Logged Data

To get logged data, you first need to get interface:

let fileInterface = Log.getInterface("LoggerCordovaFileInterface");

Now we need to first get a list of log files, and then read these files:

async function getLogs() {
    // getLogsList returns a promise, so we can await result, if we are in async function
    const result = await fileInterface.getLogsList();
    // if this is an error, then format is: {type:"error",error:object}
    if (result.type === "error") {
        console.log("error getting logs: ", result.error);
    } else {
        // if this is not an error, we get an object with a list
        // which is an array of strings - filenames,
        // e.g. { list: ["Oct_14_2018","Oct_15_2018"] }
        const filesList = result.list;
        // note that there may be no files yet, if we never saved logs yet
        if (filesList.length > 0) {
            // now we can use these fileNames to get fileData.
            // `readFileByFilename` also returns a promise, which
            // resolves with fileData or an error
            const readFileResult = await fileInterface.readFileByFilename(filesList[0]);
            // if this is an error, then format is: {type:"error",error:object}
            if (readFileResult.type !== "error") {
                // fileData is an object of the following structure: `{contents:string,metadata:object}`
                // where `contents` field contains our logs, and metadata contains information
                // about the file, like size of the file, date it modified
                const fileData = readFileResult;
                console.log("file metadata is: ", fileData.metaData);
                console.log("file size: "+fileData.metaData.size);
                console.log("file last modified: "+fileData.metaData.modificationTime);
                // contents is a json-like array, but without starting "[" and ending "]",
                // of objects with the followings structure: {x:string,t:string,d:number}, where
                // x is log text, t is tag, and d is log date (unix timestamp)
                console.log("logs: "+fileData.contents);
                // optionally, you can also use formatLogs method to format logs fileData
                // returns a formatted string
                console.log("formatted logs: "+fileInterface.formatLogs(fileData));
            }
        }
    }
}

You can also flush logs which are currently in memory to file with:

// returns a promise
fileInterface.flushLogs();

You can delete all log files like this:

// returns a promise
fileInterface.clearAllLogs();

typescript support

This repository contains typescript typings, so it can be used in typescript. However, one thing should be noted. Since typescript requires a method to be defined to be used, you won't be able to do this:

import { Log } from "tag-logger";

Log.info("logging info");

Because info is a dynamically created method. Instead you can either use a generic Log.log method, or import this log method directly. This option also has an advantage in that it automatically creates a tag if it doesn't exist:

Log.log("info","typescript info log");
import { Log, log } from "tag-logger";

Log.initialize().then(() => {
    log("info", "typescript info log");
});

Another way would be to import it using require:

const Log = require("tag-logger").Log;

Log.initialize().then(() => {
    Log.info("typescript info log");
});
1.1.6

5 years ago

1.1.5

5 years ago

1.1.4

5 years ago

1.1.3

5 years ago

1.1.2

5 years ago

1.1.1

5 years ago

1.1.0

5 years ago