From 8af356f09bc24ef84a076b2016dad2d8b599656e Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Thu, 6 Apr 2017 13:22:34 +0200
Subject: [PATCH] [fix] #865 #938 `logs` is now a module command and has a
 `--loglevel` option

---
 app/lib/constants.js    |  3 ++
 app/lib/logger/index.js | 37 ++++++++++++------------
 app/modules/daemon.js   | 63 +++++++++++++++++++++++++++++++++++++++--
 bin/duniter             |  2 +-
 index.js                |  6 +++-
 package.json            |  1 +
 6 files changed, 89 insertions(+), 23 deletions(-)

diff --git a/app/lib/constants.js b/app/lib/constants.js
index 58a53c465..4418b4da7 100644
--- a/app/lib/constants.js
+++ b/app/lib/constants.js
@@ -327,6 +327,9 @@ module.exports = {
 
   ACCOUNT_MINIMUM_CURRENT_BASED_AMOUNT: 100,
 
+  // With `logs` command, the number of tail lines to show
+  NB_INITIAL_LINES_TO_SHOW: 100,
+
   // INDEXES
   M_INDEX: 'MINDEX',
   I_INDEX: 'IINDEX',
diff --git a/app/lib/logger/index.js b/app/lib/logger/index.js
index 81f9e37da..320f1117f 100644
--- a/app/lib/logger/index.js
+++ b/app/lib/logger/index.js
@@ -63,25 +63,26 @@ logger.addCallbackLogs = (callbackForLog) => {
 
 // Singletons
 let loggerHomeAttached = false;
-logger.addHomeLogs = (home) => {
-  if (!loggerHomeAttached) {
-    loggerHomeAttached = true;
-    logger.add(winston.transports.File, {
-      level: 'info',
-      levels: customLevels.levels,
-      handleExceptions: false,
-      colorize: true,
-      tailable: true,
-      maxsize: 50 * 1024 * 1024, // 50 MB
-      maxFiles: 3,
-      //zippedArchive: true,
-      json: false,
-      filename: path.join(home, 'duniter.log'),
-      timestamp: function () {
-        return moment().format();
-      }
-    });
+logger.addHomeLogs = (home, level) => {
+  if (loggerHomeAttached) {
+    logger.remove(winston.transports.File);
   }
+  loggerHomeAttached = true;
+  logger.add(winston.transports.File, {
+    level: level || 'info',
+    levels: customLevels.levels,
+    handleExceptions: false,
+    colorize: true,
+    tailable: true,
+    maxsize: 50 * 1024 * 1024, // 50 MB
+    maxFiles: 3,
+    //zippedArchive: true,
+    json: false,
+    filename: path.join(home, 'duniter.log'),
+    timestamp: function () {
+      return moment().format();
+    }
+  });
 };
 
 let muted = false;
diff --git a/app/modules/daemon.js b/app/modules/daemon.js
index d70ede03f..5b059b443 100644
--- a/app/modules/daemon.js
+++ b/app/modules/daemon.js
@@ -1,12 +1,27 @@
 "use strict";
 
-const co = require('co');
+const co        = require('co');
+const qfs       = require('q-io/fs');
+const directory = require('../lib/system/directory');
+const constants = require('../lib/constants');
+const path      = require('path');
+const Tail      = require("tail").Tail
 
 module.exports = {
   duniter: {
 
-    service: {
-      process: (server) => ServerService(server)
+    cliOptions: [
+      { value: '--loglevel <level>', desc: 'Logs level, either [error,warning,info,debug,trace]. default to `info`.' }
+    ],
+
+    config: {
+
+      /*****
+       * Tries to load a specific parameter `conf.loglevel`
+       */
+      onLoading: (conf, program) => co(function*(){
+        conf.loglevel = program.loglevel || conf.loglevel || 'trace'
+      })
     },
 
     cli: [{
@@ -54,6 +69,15 @@ module.exports = {
         }
       })
     }, {
+
+      name: 'logs',
+      desc: 'Follow duniter logs.',
+      logs: false,
+      onConfiguredExecute: (server, conf, program, params) => co(function*() {
+        printTailAndWatchFile(directory.INSTANCE_HOMELOG_FILE, constants.NB_INITIAL_LINES_TO_SHOW)
+        // Never ending command
+        return new Promise(res => null)
+      })
     }, {
 
       name: 'direct_start',
@@ -93,4 +117,37 @@ function stopDaemon(daemon) {
     resolve()
   }))
 }
+
+function printTailAndWatchFile(file, tailSize) {
+  return co(function*() {
+    if (yield qfs.exists(file)) {
+      const content = yield qfs.read(file)
+      const lines = content.split('\n')
+      const from = Math.max(0, lines.length - tailSize)
+      const lastLines = lines.slice(from).join('\n')
+      console.log(lastLines)
+    }
+    watchFile(file)
+  })
+}
+
+function watchFile(file) {
+  const tail = new Tail(file);
+
+  // Specific errors handling
+  process.on('uncaughtException', (err) => {
+    if (err.code === "ENOENT") {
+      console.error('EXCEPTION: ', err.message);
+      setTimeout(() => watchFile(file), 1000) // Wait a second
+    }
+  });
+
+  // On new line
+  tail.on("line", function(data) {
+    console.log(data);
+  });
+
+  tail.on("error", function(error) {
+    console.error('ERROR: ', error);
+  });
 }
diff --git a/bin/duniter b/bin/duniter
index 153524c40..639437438 100755
--- a/bin/duniter
+++ b/bin/duniter
@@ -10,7 +10,7 @@ return co(function*() {
   // Specific errors handling
   process.on('uncaughtException', (err) => {
     // Dunno why this specific exception is not caught
-    if (err.code !== "EADDRNOTAVAIL" && err.code !== "EINVAL") {
+    if (err.code !== "EADDRNOTAVAIL" && err.code !== "EINVAL" && err.code !== "ENOENT") {
       duniter.statics.logger.error(err);
       process.exit(2);
     }
diff --git a/index.js b/index.js
index e82aa0f80..5837f1bc9 100644
--- a/index.js
+++ b/index.js
@@ -164,7 +164,7 @@ function Stack(dependencies) {
     }
 
     // Add log files for this instance
-    logger.addHomeLogs(home);
+    logger.addHomeLogs(home, program.loglevel);
 
     const server = new Server(home, program.memory === true, commandLineConf(program));
 
@@ -208,6 +208,10 @@ function Stack(dependencies) {
       });
 
       const conf = yield server.loadConf();
+
+      // Eventually change the log level
+      logger.addHomeLogs(home, conf.loglevel);
+
       // Auto-configuration default
       yield configure(program, server, server.conf || {});
       // Autosave conf
diff --git a/package.json b/package.json
index 1e98372bf..91278d03b 100644
--- a/package.json
+++ b/package.json
@@ -59,6 +59,7 @@
     "sha1": "1.1.1",
     "sqlite3": "3.1.4",
     "superagent": "3.5.2",
+    "tail": "^1.2.1",
     "underscore": "1.8.3",
     "unzip": "0.1.11",
     "unzip2": "0.2.5",
-- 
GitLab