diff --git a/.github/workflows/test_on_pr.yml b/.github/workflows/test_on_pr.yml index 1078d85..2b518bc 100644 --- a/.github/workflows/test_on_pr.yml +++ b/.github/workflows/test_on_pr.yml @@ -3,7 +3,7 @@ name: Test Pull Request into master branch on: pull_request: branches: - - master + - master jobs: test: @@ -27,6 +27,7 @@ jobs: restore-keys: | ${{ runner.OS }}-${{ matrix.node-version }}-node- ${{ runner.OS }}-${{ matrix.node-version }}- + - run: npm ci env: diff --git a/__mocks__/udp-server.js b/__mocks__/udp-server.js index a345c3c..d4327ae 100644 --- a/__mocks__/udp-server.js +++ b/__mocks__/udp-server.js @@ -14,9 +14,11 @@ function start () { return server } -function stop () { - server.close() - onMessage.mockReset() +function stop (cb) { + server.close(function () { + onMessage.mockReset() + cb && cb() + }) } module.exports = { diff --git a/bench/bench.sh b/bench/bench.sh index ffebcc6..0e2c765 100755 --- a/bench/bench.sh +++ b/bench/bench.sh @@ -1,2 +1,2 @@ #!/bin/bash -time node producer.js 1000000 | node --trace-uncaught ../index.js log -c ../__mocks__/custom-schema.json -v \ No newline at end of file +time node producer.js 1000000 | node --trace-uncaught ../index.js log -c ../__mocks__/custom-schema.json -v > /dev/null \ No newline at end of file diff --git a/bench/producer.js b/bench/producer.js index 21f8ad2..fe56ae6 100644 --- a/bench/producer.js +++ b/bench/producer.js @@ -1,4 +1,4 @@ -'strict' +'use strict' for (let i = 0; i < process.argv.slice(2)[0]; i++) { process.stdout.write('{"level":30,"time":1531171074631,"msg":"hello world","nested":{"mock":666},"test2":"red","pid":657,"hostname":"box","name":"app","v":1}' + '\n') diff --git a/lib/schema/gelf.json b/lib/schema/gelf.json index 2bfafc7..a6e003b 100644 --- a/lib/schema/gelf.json +++ b/lib/schema/gelf.json @@ -6,7 +6,7 @@ "host": { "type": "string" }, "short_message": { "type": "string" }, "full_message": { "type": "string" }, - "timestamp": { "type": "integer" }, + "timestamp": { "type": "number" }, "level": { "type": "integer" }, "facility": { "type": "string" } } diff --git a/lib/stream-logs.js b/lib/stream-logs.js index b5bcfab..1f03379 100644 --- a/lib/stream-logs.js +++ b/lib/stream-logs.js @@ -24,7 +24,6 @@ function getVerbose () { } function getTransport (opts) { - console.log('transport is prepared') const transport = new Transport(opts) return new Transform({ writableObjectMode: true, diff --git a/lib/transformer/index.js b/lib/transformer/index.js index 18a7e9a..78becd8 100644 --- a/lib/transformer/index.js +++ b/lib/transformer/index.js @@ -13,7 +13,7 @@ module.exports = function (opts) { function setMessageField (opts) { const _field = opts.messageField return function (data) { - data.msg = data[_field] !== undefined ? data[_field] : 'No msg property found or msg is empty' + data.msg = data[_field] || 'No msg property found or msg is empty' return data } } diff --git a/lib/transformer/standard-gelf.js b/lib/transformer/standard-gelf.js index 889b6a8..2c020ea 100644 --- a/lib/transformer/standard-gelf.js +++ b/lib/transformer/standard-gelf.js @@ -3,10 +3,10 @@ const utils = require('./../utils') module.exports = function (data) { return { version: '1.1', - host: data.hostname, + host: data.host, short_message: data.msg.substring(0, 65), full_message: data.msg, - timestamp: data.time / 1000, + timestamp: data.timestamp, level: utils.pinoLevelToSyslogLevel(data.level), facility: data.name // deprecated } diff --git a/lib/transport.js b/lib/transport.js index fceb3df..54849b0 100644 --- a/lib/transport.js +++ b/lib/transport.js @@ -4,13 +4,16 @@ const crypto = require('crypto') const deflate = require('zlib').deflate const dgram = require('dgram') const EventEmitter = require('events').EventEmitter -const pick = require('lodash.pick') const utils = require('./utils') const Transport = function (opts) { const self = this - self.config = pick(opts, ['host', 'port', 'maxChunkSize']) + self.config = { + host: opts.host, + port: opts.port, + maxChunkSize: opts.maxChunkSize + } self.stringify = utils.stringify(opts) self.on('log', function (msg) { diff --git a/package-lock.json b/package-lock.json index 0b8f654..6d0e1a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3217,12 +3217,13 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-json-stringify": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.4.2.tgz", - "integrity": "sha512-hXNC8Hj5ZYf0PRt67JyLwrw72XOIUSOj8IYXk8w8kotBox02L08Dvz6c8IMpCUXof1H+dLlBz1aszGqP9xmrBw==", + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.6.tgz", + "integrity": "sha512-ezem8qpAgpad6tXeUhK0aSCS8Fi2vjxTorI9i5M+xrq6UUbTl7/bBTxL1SjRI2zy+qpPkdD4+UblUCQdxRpvIg==", "requires": { "ajv": "^6.11.0", "deepmerge": "^4.2.2", + "rfdc": "^1.2.0", "string-similarity": "^4.0.1" }, "dependencies": { @@ -5591,11 +5592,6 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -6820,6 +6816,11 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", diff --git a/package.json b/package.json index b5c09b4..a719d16 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "scripts": { "pretest": "standard", "test": "jest", - "semantic-release": "semantic-release" + "semantic-release": "semantic-release", + "lint": "standard", + "jest": "jest" }, "repository": { "type": "git", @@ -35,9 +37,8 @@ "dependencies": { "commander": "^3.0.1", "fast-json-parse": "^1.0.3", - "fast-json-stringify": "^2.4.2", + "fast-json-stringify": "2.7.6", "lodash.get": "^4.4.2", - "lodash.pick": "^4.4.0", "readable-stream": "^3.6.0", "split2": "^3.2.2" }, @@ -46,6 +47,6 @@ "standard": "^16.0.3" }, "engines": { - "node": ">=10" + "node": ">=12" } } diff --git a/test/gel-transformer-verbose.spec.js b/test/gel-transformer-verbose.spec.js index a0828b1..6761c03 100644 --- a/test/gel-transformer-verbose.spec.js +++ b/test/gel-transformer-verbose.spec.js @@ -7,7 +7,7 @@ jest.mock('dgram') const pgPath = path.join(__dirname, '..', 'index.js') const consoleOutput = function (msg, level) { - return `{"level":${level},"time":1531171074631,"msg":"${msg}","pid":657,"hostname":"box","name":"app","v":1}` + return `{"level":${level},"timestamp":1531171074,"msg":"${msg}","pid":657,"hostname":"box","name":"app","v":1}` } describe('gelf-transform in verbose mode', function () { @@ -37,7 +37,7 @@ describe('gelf-transform in verbose mode', function () { pg.stdin.end('this is not json\n') }) - test('logger output output is transformed to gelf output', done => { + test.only('logger output is transformed to gelf output', done => { const pg = cp.spawn('node', [pgPath, 'log', '-v']) pg.stdout.on('data', dataSpy) @@ -49,7 +49,7 @@ describe('gelf-transform in verbose mode', function () { done() }) - pg.stdin.end(consoleOutput('hello world', 30) + '\n') + pg.stdin.end(consoleOutput('hello world 666', 30) + '\n') }) test('short message is trimmed down', done => { @@ -71,7 +71,7 @@ describe('gelf-transform in verbose mode', function () { test('logger output with custom fields (also nested) is transformed to gelf output', done => { const pg = cp.spawn('node', [pgPath, 'log', '-c', '__mocks__/custom-schema.json', '-v']) - const consoleCustomOutput = '{"level":30,"time":1531171074631,"msg":"hello world","nested":{"mock":666},"test2":"red","pid":657,"hostname":"box","name":"app","v":1}' + const consoleCustomOutput = '{"level":30,"time":1531171074.631,"msg":"hello world","nested":{"mock":666},"test2":"red","pid":657,"hostname":"box","name":"app","v":1}' pg.stdout.on('data', dataSpy) @@ -87,7 +87,7 @@ describe('gelf-transform in verbose mode', function () { test('logger output with custom fields should ignore mismatched type fields', done => { const pg = cp.spawn('node', [pgPath, 'log', '-c', '__mocks__/custom-schema.json', '-v']) - const consoleCustomOutput = '{"level":30,"time":1531171074631,"msg":"hello world","nested":{"mock":"this_should_be_a_number"},"test2":222,"pid":657,"hostname":"box","name":"app","v":1}' + const consoleCustomOutput = '{"level":30,"time":1531171074.631,"msg":"hello world","nested":{"mock":"this_should_be_a_number"},"test2":222,"pid":657,"hostname":"box","name":"app","v":1}' pg.stdout.on('data', dataSpy) @@ -148,7 +148,7 @@ describe('gelf-transform in verbose mode', function () { done() }) - pg.stdin.end('{"level":30,"time":1531171074631,"pid":657,"hostname":"box","name":"app","v":1}\n') + pg.stdin.end('{"level":30,"time":1531171074.631,"pid":657,"hostname":"box","name":"app","v":1}\n') }) describe('log levels transformations', () => { diff --git a/test/gelf-transformer-transport.spec.js b/test/gelf-transformer-transport.spec.js index e763dfe..ab4bba8 100644 --- a/test/gelf-transformer-transport.spec.js +++ b/test/gelf-transformer-transport.spec.js @@ -1,4 +1,4 @@ -/* globals describe, test, expect, afterEach, beforeEach */ +/* globals describe, it, expect, afterEach, beforeEach */ const cp = require('child_process') const path = require('path') const { unzip } = require('zlib') @@ -6,64 +6,42 @@ const mockServer = require(path.resolve('__mocks__/udp-server.js')) const gtPath = path.join(__dirname, '..', 'index.js') -function logsOutput (msg, level) { - return `{"level":${level},"time":1531171074631,"msg":"${msg}","pid":657,"hostname":"box","name":"app","v":1}` -} - describe('gelf-transform in transport mode', function () { let server + let gelfTransformer beforeEach(() => { + gelfTransformer = cp.spawn('node', [gtPath, 'log', '-t']) server = mockServer.start() }) - afterEach(() => { - mockServer.stop() + afterEach((done) => { + mockServer.stop(function () { + gelfTransformer.kill() + done() + }) }) - test('should send logs to the graylog server when transport is enabled', done => { - const gt = cp.spawn('node', [gtPath, 'log', '-t']) - + it('should send logs to the graylog server when transport is enabled', done => { + const result = [] + let callsCounter = 0 server.on('message', (msg, remote) => { unzip(msg, function (err, buffer) { if (err) { - gt.kill() return done(err) } - const result = buffer.toString() - expect(mockServer.onMessage).toBeCalledTimes(1) - expect(result).toEqual('{"version":"1.1","host":"box","short_message":"log","full_message":"log","timestamp":1531171074.631,"level":6,"facility":"app"}') - - gt.kill() - done() - }) - }) - - gt.stdin.write(logsOutput('log', '30') + '\n') - }) + result.push(buffer.toString()) + callsCounter++ - test('should not send logs to graylog', done => { - const gt = cp.spawn('node', [gtPath, 'log']) - const gtLog = cp.spawn('node', [gtPath, 'log', '-t']) - - server.on('message', (msg, remote) => { - unzip(msg, function (err, buffer) { - if (err) { - gt.kill() - gtLog.kill() - return done(err) + if (callsCounter === 2) { + expect(result[0]).toEqual('{"version":"1.1","host":"box","short_message":"log1","full_message":"log1","timestamp":1531171074,"level":6,"facility":"app"}') + expect(result[1]).toEqual('{"version":"1.1","host":"box","short_message":"log2","full_message":"log2","timestamp":1531171074,"level":6,"facility":"app"}') + done() } - - const result = buffer.toString() - expect(mockServer.onMessage).toBeCalledTimes(1) - expect(result).toEqual('{"version":"1.1","host":"box","short_message":"available","full_message":"available","timestamp":1531171074.631,"level":6,"facility":"app"}') - gt.kill() - gtLog.kill() - done() }) }) - gt.stdin.write(logsOutput('not_available', '30') + '\n') - gtLog.stdin.write(logsOutput('available', '30') + '\n') - }) + gelfTransformer.stdin.write('{"level":30,"time":1531171074,"msg":"log1","pid":657,"hostname":"box","name":"app","v":1}' + '\n') + gelfTransformer.stdin.write('{"level":30,"time":1531171074,"msg":"log2","pid":657,"hostname":"box","name":"app","v":1}' + '\n') + }, 10000) })