From 5b7341c0e9fb5392d839cd9f61b6794cf48561e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Mon, 29 Jun 2020 21:01:48 +0200 Subject: [PATCH] Fix: TypeError: Cannot read property 'level' of undefined Feature: dump unfinished log into a file while exiting --- metro/index.js | 28 ++++++++++++++++++---- metro/log-collector.js | 54 ++++++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/metro/index.js b/metro/index.js index 972f628a..c655a214 100644 --- a/metro/index.js +++ b/metro/index.js @@ -4,8 +4,26 @@ const split = require('split2'); const logCollector = require('./log-collector'); const metricsCollector = require('./metrics-collector'); -process.stdin - .pipe(split()) - .pipe(logCollector()) - .pipe(metricsCollector()) - .pipe(process.stdout); +const streams = [process.stdin, split(), logCollector(), metricsCollector(), process.stdout] + +pipeline('pipe', streams); + +process.on('SIGINT', exitProcess(0)); +process.on('SIGTERM', exitProcess(0)); +process.on('uncaughtException', exitProcess(1)); +process.on('unhandledRejection', exitProcess(1)); + +function pipeline (action, streams) { + for (let index = 0; index < streams.length - 1; index++) { + const source = streams[index]; + const destination = streams[index + 1]; + source[action](destination); + } +} + +function exitProcess (code = 0) { + return function exitProcess (signal) { + pipeline('unpipe', streams); + process.exit(code); + }; +} diff --git a/metro/log-collector.js b/metro/log-collector.js index bbb3c7b5..62e9e221 100644 --- a/metro/log-collector.js +++ b/metro/log-collector.js @@ -1,10 +1,13 @@ 'use strict' +const fs = require('fs'); const split = require('split2'); const assingDeep = require('assign-deep'); const { Transform } = require('stream'); const DEV_ENVS = ['test', 'development']; -const logs = new Map(); +const dumpPath = `${__dirname}/dump.json`; + +let logs; const LEVELS = { 10: 'trace', @@ -16,7 +19,7 @@ const LEVELS = { } module.exports = function logCollector () { - return new Transform({ + const stream = new Transform({ transform (chunk, enc, callback) { let entry; @@ -34,7 +37,7 @@ module.exports = function logCollector () { return callback(); } - const { id, end } = entry; + const { id } = entry; if (id === undefined) { entry.level = LEVELS[entry.level]; @@ -42,17 +45,17 @@ module.exports = function logCollector () { return callback(); } - if (end === true) { - const accEntry = logs.get(id); - accEntry.level = LEVELS[accEntry.level]; - accEntry.time = entry.time; - this.push(`${JSON.stringify(accEntry)}\n`); - logs.delete(id); - return callback(); - } - if (logs.has(id)) { const accEntry = logs.get(id); + const { end } = entry; + + if (end === true) { + accEntry.level = LEVELS[accEntry.level]; + accEntry.time = entry.time; + this.push(`${JSON.stringify(accEntry)}\n`); + logs.delete(id); + return callback(); + } if (accEntry.level > entry.level) { delete entry.level @@ -70,7 +73,32 @@ module.exports = function logCollector () { callback(); } - }) + }); + + stream.on('pipe', () => { + if (!fs.existsSync(dumpPath)) { + logs = new Map(); + return; + } + + try { + const dump = require(dumpPath); + logs = new Map(dump); + } catch (err) { + console.error(`Cannot read the dump for unfinished logs: ${err}`); + logs = new Map(); + } + }); + + stream.on('unpipe', () => { + try { + fs.writeFileSync(dumpPath, JSON.stringify([...logs])); + } catch (err) { + console.error(`Cannot create a dump for unfinished logs: ${err}`); + } + }); + + return stream; } function hasProperty(obj, prop) {