From 89db0b40da7e9445df13ecd60dda4743347acace Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Moreau?= <cem.moreau@gmail.com>
Date: Thu, 7 Jun 2018 12:14:16 +0200
Subject: [PATCH] [enh] Use annotations to monitor DB accesses + add --notrim

---
 app/ProcessCpuProfiler.ts                     |  9 ----
 app/cli.ts                                    |  1 +
 app/lib/blockchain/DuniterBlockchain.ts       |  5 +-
 app/lib/common-libs/programOptions.ts         | 28 ++++++++++
 app/lib/computation/QuickSync.ts              | 30 ++++++-----
 app/lib/dal/fileDAL.ts                        | 32 +++++++++---
 app/lib/dal/indexDAL/loki/LokiBIndex.ts       |  2 +
 app/lib/dal/indexDAL/loki/LokiBlockchain.ts   | 11 ++--
 app/lib/dal/indexDAL/loki/LokiCIndex.ts       |  2 +
 app/lib/dal/indexDAL/loki/LokiIIndex.ts       |  9 ++--
 app/lib/dal/indexDAL/loki/LokiIndex.ts        | 30 +++--------
 .../indexDAL/loki/LokiPubkeySharingIndex.ts   |  2 +
 app/lib/dal/indexDAL/loki/LokiSIndex.ts       |  2 +
 app/lib/dal/sqliteDAL/AbstractSQLite.ts       | 28 ++--------
 app/lib/debug/MonitorFlushedIndex.ts          | 52 +++++++++++++++++++
 app/lib/debug/MonitorLokiExecutionTime.ts     | 38 ++++++++++++++
 app/lib/debug/MonitorSQLExecutionTime.ts      | 36 +++++++++++++
 17 files changed, 226 insertions(+), 91 deletions(-)
 create mode 100644 app/lib/common-libs/programOptions.ts
 create mode 100644 app/lib/debug/MonitorFlushedIndex.ts
 create mode 100644 app/lib/debug/MonitorLokiExecutionTime.ts
 create mode 100644 app/lib/debug/MonitorSQLExecutionTime.ts

diff --git a/app/ProcessCpuProfiler.ts b/app/ProcessCpuProfiler.ts
index 44ad6294f..42b999926 100644
--- a/app/ProcessCpuProfiler.ts
+++ b/app/ProcessCpuProfiler.ts
@@ -11,8 +11,6 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
-import {NewLogger} from "./lib/logger"
-
 const SAMPLING_PERIOD = 150 // milliseconds
 const MAX_SAMPLES_DISTANCE = 20 * 1000000 // seconds
 
@@ -30,13 +28,6 @@ export function getDurationInMicroSeconds(before:number) {
   return parseInt(String(getMicrosecondsTime() - before))
 }
 
-export async function profileFunc<T>(name:string, f: () => Promise<T>): Promise<T> {
-  const now = getMicrosecondsTime()
-  const res = await f()
-  NewLogger().trace('%s %sµs', name, getDurationInMicroSeconds(now))
-  return res
-}
-
 interface CpuUsage {
   user: number
   system:number
diff --git a/app/cli.ts b/app/cli.ts
index 0060f3718..33472bb2a 100644
--- a/app/cli.ts
+++ b/app/cli.ts
@@ -74,6 +74,7 @@ export const ExecuteCommand = () => {
         .option('--nohttplogs', 'Disable HTTP logs')
         .option('--isolate', 'Avoid the node to send peering or status informations to the network')
         .option('--forksize <size>', 'Maximum size of fork window', parseInt)
+        .option('--notrim', 'Disable the INDEX trimming.')
         .option('--memory', 'Memory mode')
       ;
 
diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts
index 7298bdcb6..9b2c004ab 100644
--- a/app/lib/blockchain/DuniterBlockchain.ts
+++ b/app/lib/blockchain/DuniterBlockchain.ts
@@ -218,10 +218,7 @@ export class DuniterBlockchain {
 
     // Save indexes
     await dal.bindexDAL.insert(indexes.HEAD);
-    await dal.mindexDAL.insertBatch(indexes.mindex);
-    await dal.iindexDAL.insertBatch(indexes.iindex);
-    await dal.sindexDAL.insertBatch(indexes.sindex);
-    await dal.cindexDAL.insertBatch(indexes.cindex);
+    await dal.flushIndexes(indexes)
 
     // Create/Update nodes in wotb
     await this.updateMembers(block, dal);
diff --git a/app/lib/common-libs/programOptions.ts b/app/lib/common-libs/programOptions.ts
new file mode 100644
index 000000000..0274130de
--- /dev/null
+++ b/app/lib/common-libs/programOptions.ts
@@ -0,0 +1,28 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+const opts = require('optimist').argv
+
+export interface ProgramOptions {
+  mdb?: string
+  home?: string
+  notrim?: boolean
+  syncTrace?: string
+}
+
+export const cliprogram: ProgramOptions = {
+  mdb: opts.mdb,
+  home: opts.home,
+  notrim: opts.notrim,
+  syncTrace: opts['sync-trace'],
+}
diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts
index aa1e4791e..4993cbbe4 100644
--- a/app/lib/computation/QuickSync.ts
+++ b/app/lib/computation/QuickSync.ts
@@ -174,10 +174,12 @@ export class QuickSynchronizer {
           }))
 
           // Flush the INDEX (not bindex, which is particular)
-          await this.dal.mindexDAL.insertBatch(sync_mindex);
-          await this.dal.iindexDAL.insertBatch(sync_iindex);
-          await this.dal.sindexDAL.insertBatch(sync_sindex);
-          await this.dal.cindexDAL.insertBatch(sync_cindex);
+          await this.dal.flushIndexes({
+            mindex: sync_mindex,
+            iindex: sync_iindex,
+            sindex: sync_sindex,
+            cindex: sync_cindex,
+          })
           sync_iindex = local_iindex
           sync_cindex = local_cindex
           sync_mindex = local_mindex
@@ -196,10 +198,12 @@ export class QuickSynchronizer {
           await DuniterBlockchain.updateWallets(sync_sindex, sync_memoryDAL)
 
           // Flush the INDEX again (needs to be done *before* the update of wotb links because of block#0)
-          await this.dal.iindexDAL.insertBatch(sync_iindex);
-          await this.dal.mindexDAL.insertBatch(sync_mindex);
-          await this.dal.sindexDAL.insertBatch(sync_sindex);
-          await this.dal.cindexDAL.insertBatch(sync_cindex);
+          await this.dal.flushIndexes({
+            mindex: sync_mindex,
+            iindex: sync_iindex,
+            sindex: sync_sindex,
+            cindex: sync_cindex,
+          })
 
           // --> Update links
           await this.dal.updateWotbLinks(local_cindex.concat(sync_cindex));
@@ -240,10 +244,12 @@ export class QuickSynchronizer {
 
         // Save the INDEX
         await this.dal.bindexDAL.insertBatch(sync_bindex);
-        await this.dal.mindexDAL.insertBatch(sync_mindex);
-        await this.dal.iindexDAL.insertBatch(sync_iindex);
-        await this.dal.sindexDAL.insertBatch(sync_sindex);
-        await this.dal.cindexDAL.insertBatch(sync_cindex);
+        await this.dal.flushIndexes({
+          mindex: sync_mindex,
+          iindex: sync_iindex,
+          sindex: sync_sindex,
+          cindex: sync_cindex,
+        })
 
         // Save the intermediary table of wallets
         const conditions = Underscore.keys(sync_memoryWallets)
diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index b9e1cc9ef..256d93cbf 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -28,6 +28,7 @@ import {
   FullSindexEntry,
   IindexEntry,
   IndexEntry,
+  MindexEntry,
   SindexEntry
 } from "../indexer"
 import {TransactionDTO} from "../dto/TransactionDTO"
@@ -58,7 +59,6 @@ import {NewLogger} from "../logger"
 import {LokiBlockchain} from "./indexDAL/loki/LokiBlockchain"
 import {BlockchainDAO} from "./indexDAL/abstract/BlockchainDAO"
 import {LokiTransactions} from "./indexDAL/loki/LokiTransactions"
-import {profileFunc} from "../../ProcessCpuProfiler"
 import {TxsDAO} from "./indexDAL/abstract/TxsDAO"
 import {LokiJsDriver} from "./drivers/LokiJsDriver"
 import {WalletDAO} from "./indexDAL/abstract/WalletDAO"
@@ -73,6 +73,8 @@ import {CFSCore} from "./fileDALs/CFSCore"
 import {BlockchainArchiveDAO} from "./indexDAL/abstract/BlockchainArchiveDAO"
 import {Underscore} from "../common-libs/underscore"
 import {DBPeer} from "../db/DBPeer"
+import {MonitorFlushedIndex} from "../debug/MonitorFlushedIndex"
+import {cliprogram} from "../common-libs/programOptions"
 
 const readline = require('readline')
 const indexer = require('../indexer').Indexer
@@ -87,6 +89,13 @@ export interface FileDALParams {
   wotb:WoTBInstance
 }
 
+export interface IndexBatch {
+  mindex: MindexEntry[]
+  iindex: IindexEntry[]
+  sindex: SindexEntry[]
+  cindex: CindexEntry[]
+}
+
 export class FileDAL {
 
   rootPath:string
@@ -987,12 +996,13 @@ export class FileDAL {
   }
 
   async trimIndexes(maxNumber:number) {
-    await profileFunc('[loki][bindex][trim]', () => this.bindexDAL.trimBlocks(maxNumber))
-    await profileFunc('[loki][iindex][trim]', () => this.iindexDAL.trimRecords(maxNumber))
-    await profileFunc('[loki][mindex][trim]', () => this.mindexDAL.trimRecords(maxNumber))
-    await profileFunc('[loki][cindex][trim]', () => this.cindexDAL.trimExpiredCerts(maxNumber))
-    await profileFunc('[loki][sindex][trim]', () => this.sindexDAL.trimConsumedSource(maxNumber))
-    return true;
+    if (!cliprogram.notrim) {
+      await this.bindexDAL.trimBlocks(maxNumber)
+      await this.iindexDAL.trimRecords(maxNumber)
+      await this.mindexDAL.trimRecords(maxNumber)
+      await this.cindexDAL.trimExpiredCerts(maxNumber)
+      await this.sindexDAL.trimConsumedSource(maxNumber)
+    }
   }
 
   async trimSandboxes(block:{ medianTime: number }) {
@@ -1261,4 +1271,12 @@ export class FileDAL {
     }
     return members
   }
+
+  @MonitorFlushedIndex()
+  async flushIndexes(indexes: IndexBatch) {
+    await this.mindexDAL.insertBatch(indexes.mindex)
+    await this.iindexDAL.insertBatch(indexes.iindex)
+    await this.sindexDAL.insertBatch(indexes.sindex)
+    await this.cindexDAL.insertBatch(indexes.cindex)
+  }
 }
diff --git a/app/lib/dal/indexDAL/loki/LokiBIndex.ts b/app/lib/dal/indexDAL/loki/LokiBIndex.ts
index 59aa3c87d..912cf11bc 100644
--- a/app/lib/dal/indexDAL/loki/LokiBIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiBIndex.ts
@@ -3,6 +3,7 @@ import {DBHead} from "../../../db/DBHead"
 import {BIndexDAO} from "../abstract/BIndexDAO"
 import {NewLogger} from "../../../logger"
 import {getDurationInMicroSeconds, getMicrosecondsTime} from "../../../../ProcessCpuProfiler"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 const logger = NewLogger()
 
@@ -75,6 +76,7 @@ export class LokiBIndex extends LokiIndex<DBHead> implements BIndexDAO {
       .find({ number: HEAD.number - nbHEADs + 1 })[0]
   }
 
+  @MonitorLokiExecutionTime(true)
   async trimBlocks(maxnumber: number): Promise<void> {
     this.collection
       .chain()
diff --git a/app/lib/dal/indexDAL/loki/LokiBlockchain.ts b/app/lib/dal/indexDAL/loki/LokiBlockchain.ts
index 245b42ec0..4a1536355 100644
--- a/app/lib/dal/indexDAL/loki/LokiBlockchain.ts
+++ b/app/lib/dal/indexDAL/loki/LokiBlockchain.ts
@@ -1,10 +1,7 @@
 import {LokiIndex} from "./LokiIndex"
-import {NewLogger} from "../../../logger"
 import {BlockchainDAO} from "../abstract/BlockchainDAO"
 import {DBBlock} from "../../../db/DBBlock"
-import {getMicrosecondsTime} from "../../../../ProcessCpuProfiler"
-
-const logger = NewLogger()
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 export class LokiBlockchain extends LokiIndex<DBBlock> implements BlockchainDAO {
 
@@ -35,17 +32,15 @@ export class LokiBlockchain extends LokiIndex<DBBlock> implements BlockchainDAO
     }
   }
 
+  @MonitorLokiExecutionTime(true)
   async getBlock(number:string | number) {
-    const now = getMicrosecondsTime()
-    const b = this.collection
+    return this.collection
       .chain()
       .find({
         number: parseInt(String(number)),
         fork: false
       })
       .data()[0]
-    logger.trace('[loki][%s][getBlock] %sµs', this.collectionName, (getMicrosecondsTime() - now), number)
-    return b
   }
 
   async getPotentialRoots() {
diff --git a/app/lib/dal/indexDAL/loki/LokiCIndex.ts b/app/lib/dal/indexDAL/loki/LokiCIndex.ts
index 789ac77df..81cc750b2 100644
--- a/app/lib/dal/indexDAL/loki/LokiCIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiCIndex.ts
@@ -2,6 +2,7 @@ import {CIndexDAO} from "../abstract/CIndexDAO"
 import {LokiIndex} from "./LokiIndex"
 import {CindexEntry, FullCindexEntry, Indexer} from "../../../indexer"
 import {CommonConstants} from "../../../common-libs/constants"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 export class LokiCIndex extends LokiIndex<CindexEntry> implements CIndexDAO {
 
@@ -118,6 +119,7 @@ export class LokiCIndex extends LokiIndex<CindexEntry> implements CIndexDAO {
       .filter(r => this.collection.find({ issuer: r.issuer, receiver: r.receiver, created_on: r.created_on, expired_on: { $gt: 0 } }).length === 0)
   }
 
+  @MonitorLokiExecutionTime(true)
   async trimExpiredCerts(belowNumber: number): Promise<void> {
     const expired = this.collection.find({
       $and: [
diff --git a/app/lib/dal/indexDAL/loki/LokiIIndex.ts b/app/lib/dal/indexDAL/loki/LokiIIndex.ts
index 8124c1bdb..d0fc9cfdc 100644
--- a/app/lib/dal/indexDAL/loki/LokiIIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiIIndex.ts
@@ -1,9 +1,8 @@
 import {FullIindexEntry, IindexEntry, Indexer} from "../../../indexer"
 import {IIndexDAO} from "../abstract/IIndexDAO"
 import {LokiPubkeySharingIndex} from "./LokiPubkeySharingIndex"
-import {getDurationInMicroSeconds, getMicrosecondsTime} from "../../../../ProcessCpuProfiler"
-import {NewLogger} from "../../../logger"
 import {OldIindexEntry} from "../../../db/OldIindexEntry"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 export class LokiIIndex extends LokiPubkeySharingIndex<IindexEntry> implements IIndexDAO {
 
@@ -130,11 +129,9 @@ export class LokiIIndex extends LokiPubkeySharingIndex<IindexEntry> implements I
     ) as Promise<FullIindexEntry|null>
   }
 
+  @MonitorLokiExecutionTime()
   async getMembersPubkeys(): Promise<{ pub: string }[]> {
-    const now = getMicrosecondsTime()
-    const res = (await this.getMembers()).map(m => ({ pub: m.pubkey }))
-    NewLogger().trace('[getMembersPubkeys] %sµs', getDurationInMicroSeconds(now))
-    return res
+    return (await this.getMembers()).map(m => ({ pub: m.pubkey }))
   }
 
   async getToBeKickedPubkeys(): Promise<string[]> {
diff --git a/app/lib/dal/indexDAL/loki/LokiIndex.ts b/app/lib/dal/indexDAL/loki/LokiIndex.ts
index 6283a8312..e4551fb26 100644
--- a/app/lib/dal/indexDAL/loki/LokiIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiIndex.ts
@@ -1,9 +1,6 @@
 import {GenericDAO} from "../abstract/GenericDAO"
-import {NewLogger} from "../../../logger"
-import {getMicrosecondsTime} from "../../../../ProcessCpuProfiler"
 import {LokiCollectionManager} from "./LokiCollectionManager"
-
-const logger = NewLogger()
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 export interface IndexData {
   written_on: string
@@ -16,48 +13,37 @@ export abstract class LokiIndex<T extends IndexData> extends LokiCollectionManag
   }
 
   async insert(record: T): Promise<void> {
-    const now = getMicrosecondsTime()
     this.collection.insert(record)
-    // logger.trace('[loki][%s][insert] %sµs', this.collectionName, (getMicrosecondsTime() - now))
   }
 
+  @MonitorLokiExecutionTime(true)
   async findRaw(criterion?:any) {
-    const now = getMicrosecondsTime()
-    const res = this.collection.find(criterion)
-    logger.trace('[loki][%s][findRaw] => %sµs', this.collectionName, (getMicrosecondsTime() - now), criterion)
-    return res
+    return this.collection.find(criterion)
   }
 
+  @MonitorLokiExecutionTime(true)
   async findRawWithOrder(criterion:any, sort:((string|((string|boolean)[]))[])) {
-    const now = getMicrosecondsTime()
     const res = this.collection
       .chain()
       .find(criterion)
       .compoundsort(sort)
-    logger.trace('[loki][%s][findRaw] => %sµs', this.collectionName, (getMicrosecondsTime() - now), criterion)
     return res.data()
   }
 
+  @MonitorLokiExecutionTime()
   async insertBatch(records: T[]): Promise<void> {
-    const now = getMicrosecondsTime()
     records.map(r => this.insert(r))
-    if (records.length) {
-      logger.trace('[loki][%s][insertBatch] %s record(s) in %sµs', this.collectionName, records.length, getMicrosecondsTime() - now)
-    }
   }
 
+  @MonitorLokiExecutionTime(true)
   async getWrittenOn(blockstamp: string): Promise<T[]> {
-    const now = getMicrosecondsTime()
     const criterion:any = { writtenOn: parseInt(blockstamp) }
-    const res = this.collection.find(criterion)
-    logger.trace('[loki][%s][getWrittenOn] %sµs', this.collectionName, (getMicrosecondsTime() - now), blockstamp)
-    return res
+    return this.collection.find(criterion)
   }
 
+  @MonitorLokiExecutionTime(true)
   async removeBlock(blockstamp: string): Promise<void> {
-    const now = getMicrosecondsTime()
     const data = await this.getWrittenOn(blockstamp)
     data.map(d => this.collection.remove(d))
-    logger.trace('[loki][%s][removeBlock] %sµs', this.collectionName, (getMicrosecondsTime() - now), blockstamp)
   }
 }
diff --git a/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts b/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts
index 36236c07f..e44ee62f2 100644
--- a/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiPubkeySharingIndex.ts
@@ -1,8 +1,10 @@
 import {Indexer} from "../../../indexer"
 import {LokiIndex} from "./LokiIndex"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 export class LokiPubkeySharingIndex<T extends { written_on:string, writtenOn:number, pub:string }> extends LokiIndex<T> {
 
+  @MonitorLokiExecutionTime(true)
   async trimRecords(belowNumber: number): Promise<void> {
     // TODO: may be optimized by only selecting new offseted records
     const criterion:any = {
diff --git a/app/lib/dal/indexDAL/loki/LokiSIndex.ts b/app/lib/dal/indexDAL/loki/LokiSIndex.ts
index 575d529a4..deb8d693d 100644
--- a/app/lib/dal/indexDAL/loki/LokiSIndex.ts
+++ b/app/lib/dal/indexDAL/loki/LokiSIndex.ts
@@ -2,6 +2,7 @@ import {LokiIndex} from "./LokiIndex"
 import {FullSindexEntry, Indexer, SindexEntry} from "../../../indexer"
 import {SIndexDAO} from "../abstract/SIndexDAO"
 import {Underscore} from "../../../common-libs/underscore"
+import {MonitorLokiExecutionTime} from "../../../debug/MonitorLokiExecutionTime"
 
 export class LokiSIndex extends LokiIndex<SindexEntry> implements SIndexDAO {
 
@@ -82,6 +83,7 @@ export class LokiSIndex extends LokiIndex<SindexEntry> implements SIndexDAO {
     return Indexer.DUP_HELPERS.reduceBy(reducables, ['identifier', 'pos'])
   }
 
+  @MonitorLokiExecutionTime(true)
   async trimConsumedSource(belowNumber: number): Promise<void> {
     const consumed = this.collection
       .find({ writtenOn: { $lt: belowNumber }})
diff --git a/app/lib/dal/sqliteDAL/AbstractSQLite.ts b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
index 7e3c42b70..4a2d0ec59 100644
--- a/app/lib/dal/sqliteDAL/AbstractSQLite.ts
+++ b/app/lib/dal/sqliteDAL/AbstractSQLite.ts
@@ -15,13 +15,10 @@ import {SQLiteDriver} from "../drivers/SQLiteDriver"
 import {Initiable} from "./Initiable"
 import {getDurationInMicroSeconds, getMicrosecondsTime} from "../../../ProcessCpuProfiler"
 import {Underscore} from "../../common-libs/underscore"
+import {NewLogger} from "../../logger"
+import {MonitorSQLExecutionTime} from "../../debug/MonitorSQLExecutionTime"
 
-/**
- * Created by cgeek on 22/08/15.
- */
-
-const colors = require('colors');
-const logger = require('../../logger').NewLogger('sqlite');
+const logger = NewLogger('sqlite')
 
 export interface BeforeSaveHook<T> {
   (t:T): void
@@ -43,26 +40,11 @@ export abstract class AbstractSQLite<T> extends Initiable {
     super()
   }
 
+  @MonitorSQLExecutionTime()
   async query(sql:string, params: any[] = []): Promise<T[]> {
     try {
-      const start = getMicrosecondsTime()
       const res = await this.driver.executeAll(sql, params || []);
-      const duration = getDurationInMicroSeconds(start)
-      logger.trace('[sqlite][query] %s %s %sµs', sql, JSON.stringify(params || []), duration)
-      const entities = res.map((t:T) => this.toEntity(t))
-      // Display result
-      let msg = sql + ' | %s\t==> %s rows in %s ms';
-      if (duration <= 2) {
-        msg = colors.green(msg);
-      } else if(duration <= 5) {
-        msg = colors.yellow(msg);
-      } else if (duration <= 10) {
-        msg = colors.magenta(msg);
-      } else if (duration <= 100) {
-        msg = colors.red(msg);
-      }
-      logger.query(msg, JSON.stringify(params || []), entities.length, duration);
-      return entities;
+      return res.map((t:T) => this.toEntity(t))
     } catch (e) {
       logger.error('ERROR >> %s', sql, JSON.stringify(params || []), e.stack || e.message || e);
       throw e;
diff --git a/app/lib/debug/MonitorFlushedIndex.ts b/app/lib/debug/MonitorFlushedIndex.ts
new file mode 100644
index 000000000..f2d083cce
--- /dev/null
+++ b/app/lib/debug/MonitorFlushedIndex.ts
@@ -0,0 +1,52 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {cliprogram} from "../common-libs/programOptions"
+import {IndexBatch} from "../dal/fileDAL"
+
+export const MonitorFlushedIndex = function () {
+  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+    const original = descriptor.value
+    if (original.__proto__.constructor.name === "AsyncFunction") {
+      descriptor.value = async function (...args:any[]) {
+        const pub = cliprogram.syncTrace
+        if (pub) {
+          const batch: IndexBatch = args[0]
+          batch.iindex.forEach(e => {
+            if (e.pub === pub) {
+              console.log(JSON.stringify(e))
+            }
+          })
+          batch.mindex.forEach(e => {
+            if (e.pub === pub) {
+              console.log(JSON.stringify(e))
+            }
+          })
+          batch.cindex.forEach(e => {
+            if (e.issuer === pub || e.receiver === pub) {
+              console.log(JSON.stringify(e))
+            }
+          })
+          batch.sindex.forEach(e => {
+            if (e.conditions.indexOf(pub || '') !== -1) {
+              console.log(JSON.stringify(e))
+            }
+          })
+        }
+        return await original.apply(this, args)
+      }
+    } else {
+      throw Error("Monitoring a synchronous function is not allowed.")
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/lib/debug/MonitorLokiExecutionTime.ts b/app/lib/debug/MonitorLokiExecutionTime.ts
new file mode 100644
index 000000000..ca4f15412
--- /dev/null
+++ b/app/lib/debug/MonitorLokiExecutionTime.ts
@@ -0,0 +1,38 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {NewLogger} from "../logger"
+import {getMicrosecondsTime} from "../../ProcessCpuProfiler"
+
+const theLogger = NewLogger()
+
+export const MonitorLokiExecutionTime = function (dumpFirstParam = false) {
+  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+    const original = descriptor.value
+    if (original.__proto__.constructor.name === "AsyncFunction") {
+      descriptor.value = async function (...args:any[]) {
+        const that :any = this
+        const now = getMicrosecondsTime()
+        const result = await original.apply(this, args)
+        if (dumpFirstParam) {
+          theLogger.trace('[loki][%s][%s] => %sµs', that.collectionName, propertyKey, (getMicrosecondsTime() - now), args && args[0])
+        } else {
+          theLogger.trace('[loki][%s][%s] => %sµs', that.collectionName, propertyKey, (getMicrosecondsTime() - now))
+        }
+        return result
+      }
+    } else {
+      throw Error("Monitoring a Loki synchronous function is not allowed.")
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/lib/debug/MonitorSQLExecutionTime.ts b/app/lib/debug/MonitorSQLExecutionTime.ts
new file mode 100644
index 000000000..3f2dff366
--- /dev/null
+++ b/app/lib/debug/MonitorSQLExecutionTime.ts
@@ -0,0 +1,36 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {getDurationInMicroSeconds, getMicrosecondsTime} from "../../ProcessCpuProfiler"
+import {NewLogger} from "../logger"
+
+const theLogger = NewLogger()
+
+export const MonitorSQLExecutionTime = function () {
+  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+    const original = descriptor.value
+    if (original.__proto__.constructor.name === "AsyncFunction") {
+      descriptor.value = async function (...args:any[]) {
+        const start = getMicrosecondsTime()
+        const sql: string = args[0]
+        const params: any[] = args[1]
+        const entities: any[] = await original.apply(this, args)
+        const duration = getDurationInMicroSeconds(start)
+        theLogger.trace('[sqlite][query] %s %s %sµs', sql, JSON.stringify(params || []), duration)
+        return entities
+      }
+    } else {
+      throw Error("Monitoring an SQL synchronous function is not allowed.")
+    }
+  }
+}
\ No newline at end of file
-- 
GitLab