log4js-cloudwatch-appender

log4js aws cloudwatch appender

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
log4js-cloudwatch-appender
1.1.05 years ago5 years agoMinified + gzip package size for log4js-cloudwatch-appender in KB

Readme

Build Status Coverage Status bitHound Overall Score Known Vulnerabilities dependencies Status devDependencies Status npm HitCount https://nodei.co/npm/log4js-cloudwatch-appender.png?downloads=true&downloadRank=true&stars=true
log4js-cloudwatch-appender
Simple appender for log4js to submit logs to AWS cloudwatch based on the lawgs module.

Installation

This module is installed via npm: ``` npm install --save log4js-cloudwatch-appender ```

Usage

Add aws appender to the log4js config file: ```js const config = {
appenders: {
aws: {
type: "log4js-cloudwatch-appender",
accessKeyId: '<accessKeyId>',
secretAccessKey: '<secretAccessKey>',
region: 'eu-central-1',
logGroup: 'prod',
logStream: 'apps',
layout: '<custom layout object>',
lawgsConfig: '<optional alwgs config object>'
}
},
categories: {
default: {appenders: ['aws'], level: 'info'}
}
} ``` This will cause logs to be sent to AWS CloudWatch with the specified group and stream.

Configuration

If you are using roles, you will need the following roles:
  • logs:DescribeLogGroups
  • logs:DescribeLogStreams
  • logs:CreateLogGroup
  • logs:CreateLogStream
  • logs:PutLogEvents

mandatory

  • region - The CloudWatch region
  • logGroup - The log group to send the metrics to
  • logStream - The log stream of the group to send the metrics to

optional

  • accessKeyId - Optional if credentials are set in ~/.aws/credentials
  • secretAccessKey - Optional if credentials are set in ~/.aws/credentials
  • lawgsConfig - Optional vonfig object for lawgs:
- `showDebugLogs` - Show debug logs. Default: false.
- `uploadMaxTimer` - After this ms timeout, flush to server. Default: 5000.
- `uploadBatchSize` - After this amount of logs, flush to server. Default: 500.

Suggested json layout

Logs are easier to query whn they are formatted as json. Following is a suggested json layout to set for this appender. The logging style should be: ```js const uuid = require('node-uuid'); const corr = uuid.v4(); const logger = logFactory.getLogger('category'); logger.info(corr, 'methodName()','part1','part2'); ``` Which will output: ```json { "timestamp": "2017-06-10T11:55:38.251Z", "corr": "2e2c99aa-7eee-4fd2-ae36-cd9dc9533816", "app": "", "host": "", "pid": 24532, "level": "INFO", "category": "category", "method": "methodName()", "message": "part1 part2" } ``` The layout: ```js const util = require('util'); const = require('underscore'); let processName = path.basename(process.argv1); processName = processName.substring(0, processName.length - 3); const publicIp = require('public-ip').v4; let ip = ''; publicIp() .then(function (ip) {
ip = _ip;
}) .catch(function (e) {
console.log(e);
ip = 'unknown';
}); const jsonLayout = { "type": "pattern", "pattern": '{"timestamp": "%d{yyyy-MM-ddThh:mm:ss.SSSZ}", "app": "' + processName + '", "ip": "%x{my
ip}", "host": "%h", "pid": %z, "level": "%p", "category": "%c"%x{corr}%x{method}, "message": "%x{message}"}', "tokens": {
"my_ip": function () {
return ip;
},
"corr": function (logEvent) {
logEvent.__data__ = _.map(logEvent.data, _.clone);
if (logEvent.__data__) {
let corr = logEvent.__data__[0];
if (Array.isArray(corr) && corr.length === 2) {
corr = corr[0];
if (typeof corr === 'string' && corr.length === 36 && corr.split("-").length === 5) {
logEvent.__data__[0] = logEvent.__data__[0][1];
return ', "corr": "' + corr + '"';
}
}
if (logEvent.__data__.length > 1 && corr && typeof corr === 'string' && corr.length === 36 && corr.split("-").length === 5) {
logEvent.__data__.shift();
return ', "corr": "' + corr + '"';
}
}
return '';
},
"method": function (logEvent) {
if (logEvent.__data__) {
const method = logEvent.__data__[0];
if (logEvent.__data__.length > 1 && method && typeof method === 'string' && method.indexOf("()", method.length - 2) !== -1) {
logEvent.__data__.shift();
return ', "method": "' + method + '"';
}
}
return '';
},
"message": function (logEvent) {
if (logEvent.__data__) {
let data = logEvent.__data__;
data = util.format.apply(util, wrapErrorsWithInspect(data));
data = escapedStringify(data);
logEvent.__data__ = undefined;
return data;
}
return '';
}
} }; function wrapErrorsWithInspect(items) { return items.map(function (item) {
if ((item instanceof Error) && item.stack) {
return {
inspect: function () {
return util.format(item) + '\n' + item.stack;
}
};
} else {
return item;
}
}); } function escapedStringify(json) { return json
.replace(/[\\]/g, '\\\\')
.replace(/[\"]/g, '\\\"')
.replace(/[\/]/g, '\\/')
.replace(/[\b]/g, '\\b')
.replace(/[\f]/g, '\\f')
.replace(/[\n]/g, '\\n')
.replace(/[\r]/g, '\\r')
.replace(/[\t]/g, '\\t');
} ```

Contributing

Please make all pull requests to the master branch and ensure tests pass locally.