Node.js Logging Service

JS
R
JavaScript

Simple logger for Node.js. This is one of the implementation points that users often do wrong. I always recommend people to do not attempt to create their own loggers, or log routers (unless of course there is a strong reason for it). In this example service no log files are written on the disk mount, we stream to stdout locally (via Winston) and remotely to LogEntries SaaS. All levels are being reported to logEntries, stdout levels (for Docker) are controlled with: `LOG_LEVEL=x` environment variable. LogEntries SaaS accessible via: https://insight.rapid7.com/login To start: `"serve-debug": "LOG_LEVEL=info DEBUG=app* node debug ./dist/app.js"` Security recommendation: never, ever log credentials, passwords or any sensitive information.

1import * as os from 'os';
2import * as moment from 'moment';
3import * as LogEntries from 'r7insight_node';
4import * as winston from 'winston';
5import * as uuid from 'uuid';
6
7// https://www.npmjs.com/package/winston
8
9const hostName = os.hostname();
10const customLevels = {
11  levels: {
12    emerg: 0,
13    alert: 1,
14    crit: 2,
15    error: 3,
16    warning: 4,
17    notice: 5,
18    info: 6,
19    debug: 7
20  },
21  colors: {
22    emerg: 'red',
23    alert: 'red',
24    crit: 'red',
25    error: 'red',
26    warning: 'yellow',
27    notice: 'green',
28    info: 'blue',
29    debug: 'white'
30  }
31};
32
33class LogService {
34  private logEntries: any;
35  private localLogEntries: any;
36  private correlationId: string = uuid.v1();
37
38  constructor() {
39    // Remote logs
40    this.logEntries = new LogEntries({
41      token: process.env.LOG_ENTRIES,
42      minLevel: process.env.LOG_LEVEL || 'info',
43      region: 'eu',
44      levels: customLevels.levels,
45      withStack: true
46    });
47    // The client is an EventEmitter
48    this.logEntries.on('error', (err: any) => {
49      console.log('something went wrong with remote logs via logentries', err);
50    });
51
52    // Local logs
53    this.localLogEntries = winston.createLogger({
54      level: process.env.LOG_LEVEL || 'info',
55      levels: customLevels.levels,
56      format: winston.format.combine(
57        winston.format.timestamp(),
58        winston.format.colorize(),
59        winston.format.prettyPrint()
60        ),
61      transports: [
62        new winston.transports.Console({
63          format: winston.format.simple()
64        })
65      ]
66    });
67    winston.addColors(customLevels.colors);
68  }
69
70  public log(level = 'info', message = 'Log', obj = {}): void {
71    if (Object.keys(obj).length > 0) {
72      this.localLogEntries.log({level, message, obj});
73      this.sendToLogEntries(level, message, obj);
74    } else {
75      this.localLogEntries.log({level, message});
76      this.sendToLogEntries(level, message);
77    }
78  }
79
80  public sendToLogEntries(level: string, message: string, obj?: any) {
81    let objStringified = '';
82    if (obj) {
83      objStringified = JSON.stringify(obj);
84    }
85    const printableMsg = `${moment().toDate()} ${hostName} ${message} ${objStringified}`;
86    console.log(level);
87    this.logEntries.log(level, printableMsg);
88  }
89}
90export default new LogService();

Created on 2/2/2018