UNPKG

cwlogs

Version:

Node.js stream-based access to CloudWatch Logs

96 lines (81 loc) 3.69 kB
var AWS = require('aws-sdk'); var stream = require('stream'); module.exports = readable; function invalid() { throw new Error('options must include: region, group, and optionally, start, end, pattern, retry, messages'); } /** * Provide a readable stream of log events for a particular log group * * @memberof cwlogs * @param {object} options - default Node.js [ReadableStream options](https://nodejs.org/api/stream.html#stream_class_stream_readable_1) * with extensions detailed below. * @param {string} options.group - the name of the LogGroup to read * @param {string} options.region - the AWS region in which the LogGroup resides * @param {string} [options.pattern] - a search string to use to filter log events * @param {number} [options.start=15 minutes ago] - read log events after the provided time (in ms since since Jan 01 1970) * @param {number} [options.end=now] - read log events until the provided time (in ms since since Jan 01 1970) * @param {boolean} [options.messages=false] - if set to true, the stream will be in objectMode: false and will provide only log event messages * @param {function} [options.retry] - a function to handle retry events from AWS requests * @returns {object} a Node.js [ReadableStream](https://nodejs.org/api/stream.html#stream_class_stream_readable_1) * @example * var readable = cwlogs.readable({ * group: '/aws/lambda/my-lambda-function-name', * region: 'us-east-1', * messages: true, * start: 1464984431610, * end: 1464985321508, * pattern: 'error' * }); * readable.pipe(process.stdout); */ function readable(options) { options = options || {}; if (!options.region || typeof options.region !== 'string') return invalid(); if (!options.group || typeof options.group !== 'string') return invalid(); if (options.start && typeof options.start !== 'number') return invalid(); if (options.end && typeof options.end !== 'number') return invalid(); if (options.pattern && typeof options.pattern !== 'string') return invalid(); if (options.retry && typeof options.retry !== 'function') return invalid(); if (options.messages && typeof options.messages !== 'boolean') return invalid(); options.objectMode = !options.messages; options.start = options.start || Date.now() - 15 * 60 * 1000; options.end = options.end || Date.now(); options.retry = options.retry || function() {}; var logs = new AWS.CloudWatchLogs({ region: options.region }); var params = { logGroupName: options.group, endTime: options.end, filterPattern: options.pattern ? '"' + options.pattern + '"' : undefined, interleaved: true, startTime: options.start }; var logStream = new stream.Readable(options); var nextRequest = logs.filterLogEvents(params); var pending = false; var events = []; function makeRequest(request) { pending = true; request .on('error', function(err) { logStream.emit('error', err); }) .on('retry', options.retry) .on('success', function(response) { pending = false; nextRequest = response.hasNextPage() ? response.nextPage() : false; for (var i = 0; i < response.data.events.length; i++) { var item = options.messages ? response.data.events[i].message.trim() + '\n' : response.data.events[i]; events.push(item); } logStream._read(); }).send(); } logStream._read = function() { var status = true; while (status && events.length) status = logStream.push(events.shift()); if (events.length) return; if (!nextRequest) return logStream.push(null); if (status && !pending) makeRequest(nextRequest); }; return logStream; }