Log HandlerChoose where your logs are written.
By default, log messages are written using the various methods available in the Console API. LambdaLog gives you the ability to use your own custom handler for writing log messages to any place you wish including a third-party service. To create your own log handler, you only need to create an object or class in which implements the various methods used by LambdaLog in the console API.
There are a couple of different ways to do this, but most commonly:
- Create a new Console class.
- Create a class or object that implements the methods of
console
.
Either way you go, the class or object must, at minimum, implement the following methods:
- log
- debug
- info
- warn
- error
Note: Due to the nature of console
, all methods must be synchronous. If you need asynchronous functionality, you may either use streams or understand the risk of logs not making it to their destination if the process was to end prior to all asynchronous code executing.
Console Class
The first method is by creating a new instance of the Console class. One example would be to write logs to a file versus the terminal.
1const { LambdaLog } = require('lambda-log'); 2const fs = require('fs'); 3const { Console } = require('console'); 4 5// Create write streams for standard log messages and error messages. 6const logFile = fs.createWriteStream('./out.log'); 7const errorLogFile = fs.createWriteStream('./errors.log'); 8 9// Set logHandler to a new instance of the Console class.10const log = new LambdaLog({11 logHandler: new Console({ stdout: logFile, stderr: errorLogFile })12});
With this example, your logs will now be written to a file instead of the terminal.
Custom Class or Object
The second method is by creating a custom class or object that implements some of the functions as console
. If you want a more complete custom log handler, you may also extend the Console class and only override the methods you need to. Let's look at some examples.
Custom log handler object
1const myConsole = { 2 log(message) { 3 // write a file, send to a third-party service, etc. 4 // and you can still log the message to the terminal: 5 console.log(message); 6 }, 7 debug(message) { 8 // ... 9 },10 info(message) {11 // ...12 },13 warn(message) {14 // ...15 },16 error(message) {17 // ...18 }19};20 21// Set logHandler to custom console22log.options.logHandler = myConsole;
Custom log handler class
1class MyConsole { 2 log(message) { 3 // write a file, send to a third-party service, etc. 4 // and you can still log the message to the terminal: 5 console.log(message); 6 } 7 8 debug(message) { 9 // ...10 }11 12 info(message) {13 // ...14 }15 16 warn(message) {17 // ...18 }19 20 error(message) {21 // ...22 }23};24 25// Set logHandler to custom console26log.options.logHandler = new MyConsole();
Extend Console class with custom functionality
1const { Console } = require('console'); 2const ddEvents = require('datadog-events'); 3 4class MyConsole extends Console { 5 constructor() { 6 // Call parent constructor 7 super({ stdout: process.stdout, stderr: process.stderr }); 8 } 9 10 // Override error to send logs to a third-party, such as DataDog11 async error(message) {12 // Call the parent method so it's still logged to the terminal:13 super(message);14 15 // Parse message back into an object:16 const data = JSON.parse(message);17 18 // Send error event to DataDog:19 await ddEvents.error(data.msg, data.stack, {20 tags: data._tags21 });22 }23};24 25// Set logHandler to custom console26log.options.logHandler = new MyConsole();
While this is a viable way of sending data to a third-party, it's recommended to use the log
event instead:
1const log = require('lambda-log'); 2const ddEvents = require('datadog-events'); 3 4log.on('log', async msg => { 5 if(msg.level === 'error') { 6 await ddEvents.error(msg.msg, JSON.stringify(msg.meta, null, 4), { 7 tags: msg.tags 8 }); 9 }10});