diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index 346b816ae4938aaba046d6aeb74eb05d386ebfa4..62caf441c2d14d1007d874242a1c09faa3d1b0fd 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -59,194 +59,202 @@ void print_node_info(const DhtRunner& dht, const dht_params& params) {
 int
 main(int argc, char **argv)
 {
-    auto params = parseArgs(argc, argv);
-    if (params.help) {
-        print_usage();
-        return 0;
-    }
-
-    // TODO: remove with GnuTLS >= 3.3
-    int rc = gnutls_global_init();
-    if (rc != GNUTLS_E_SUCCESS)
-        throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
-
-    dht::crypto::Identity crt {};
-    if (params.generate_identity) {
-        auto ca_tmp = dht::crypto::generateIdentity("DHT Node CA");
-        crt = dht::crypto::generateIdentity("DHT Node", ca_tmp);
-    }
-
     DhtRunner dht;
-    dht.run(params.port, crt, true, params.is_bootstrap_node);
+    try {
+        auto params = parseArgs(argc, argv);
+        if (params.help) {
+            print_usage();
+            return 0;
+        }
 
-    if (not params.bootstrap.empty()) {
-        std::cout << "Bootstrap: " << params.bootstrap[0] << ":" << params.bootstrap[1] << std::endl;
-        dht.bootstrap(params.bootstrap[0].c_str(), params.bootstrap[1].c_str());
-    }
+        // TODO: remove with GnuTLS >= 3.3
+        int rc = gnutls_global_init();
+        if (rc != GNUTLS_E_SUCCESS)
+            throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
 
-    print_node_info(dht, params);
-    std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl;
-
-    bool do_log {false};
-    while (true)
-    {
-        std::cout << ">> ";
-        std::string line;
-        std::getline(std::cin, line);
-        std::istringstream iss(line);
-        std::string op, idstr, value;
-        iss >> op >> idstr;
-
-        if (std::cin.eof() || op == "x" || op == "q" || op == "exit" || op == "quit") {
-            break;
-        } else if (op == "h" || op == "help") {
-            std::cout << "OpenDht command line interface (CLI)" << std::endl;
-            std::cout << "Possible commands:" << std::endl;
-            std::cout << "  h, help    Print this help message." << std::endl;
-            std::cout << "  q, quit    Quit the program." << std::endl;
-            std::cout << "  log        Print the full DHT log." << std::endl;
-
-            std::cout << std::endl << "Node information:" << std::endl;
-            std::cout << "  ll         Print basic information and stats about the current node." << std::endl;
-            std::cout << "  ls         Print basic information about current searches." << std::endl;
-            std::cout << "  ld         Print basic information about currenty stored values on this node." << std::endl;
-            std::cout << "  lr         Print the full current routing table of this node" << std::endl;
-
-            std::cout << std::endl << "Operations on the DHT:" << std::endl;
-            std::cout << "  g [key]               Get values at [key]." << std::endl;
-            std::cout << "  l [key]               Listen for value changes at [key]." << std::endl;
-            std::cout << "  p [key] [str]         Put string value at [key]." << std::endl;
-            std::cout << "  s [key] [str]         Put string value at [key], signed with our generated private key." << std::endl;
-            std::cout << "  e [key] [dest] [str]  Put string value at [key], encrypted for [dest] with its public key (if found)." << std::endl;
-            std::cout << std::endl;
-            continue;
-        } else if (op == "ll") {
-            print_node_info(dht, params);
-            unsigned good4, dubious4, cached4, incoming4;
-            unsigned good6, dubious6, cached6, incoming6;
-            dht.getNodesStats(AF_INET, &good4, &dubious4, &cached4, &incoming4);
-            dht.getNodesStats(AF_INET6, &good6, &dubious6, &cached6, &incoming6);
-            std::cout << "IPv4 nodes : " << good4 << " good, " << dubious4 << " dubious, " << incoming4 << " incoming." << std::endl;
-            std::cout << "IPv6 nodes : " << good6 << " good, " << dubious6 << " dubious, " << incoming6 << " incoming." << std::endl;
-            continue;
-        } else if (op == "lr") {
-            std::cout << "IPv4 routing table:" << std::endl;
-            std::cout << dht.getRoutingTablesLog(AF_INET) << std::endl;
-            std::cout << "IPv6 routing table:" << std::endl;
-            std::cout << dht.getRoutingTablesLog(AF_INET6) << std::endl;
-            continue;
-        } else if (op == "ld") {
-            std::cout << dht.getStorageLog() << std::endl;
-            continue;
-        } else if (op == "ls") {
-            std::cout << "Searches:" << std::endl;
-            std::cout << dht.getSearchesLog() << std::endl;
-            continue;
-        } else if (op == "la")  {
-            std::cout << "Reported public addresses:" << std::endl;
-            auto addrs = dht.getPublicAddressStr();
-            for (const auto& addr : addrs)
-                std::cout << addr << std::endl;
-            continue;
-        } else if (op == "log") {
-            do_log = !do_log;
-            if (do_log)
-                enableLogging(dht);
-            else
-                disableLogging(dht);
-            continue;
+        dht::crypto::Identity crt {};
+        if (params.generate_identity) {
+            auto ca_tmp = dht::crypto::generateIdentity("DHT Node CA");
+            crt = dht::crypto::generateIdentity("DHT Node", ca_tmp);
         }
+    
+        dht.run(params.port, crt, true, params.is_bootstrap_node);
 
-        if (op.empty())
-            continue;
+        if (params.log)
+            enableLogging(dht);
 
-        dht::InfoHash id {idstr};
-        static const std::set<std::string> VALID_OPS {"g", "l", "p", "s", "e", "a"};
-        if (VALID_OPS.find(op) == VALID_OPS.cend()) {
-            std::cout << "Unknown command: " << op << std::endl;
-            std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl;
-            continue;
-        }
-        static constexpr dht::InfoHash INVALID_ID {};
-        if (id == INVALID_ID) {
-            std::cout << "Syntax error: invalid InfoHash." << std::endl;
-            continue;
+        if (not params.bootstrap.empty()) {
+            std::cout << "Bootstrap: " << params.bootstrap[0] << ":" << params.bootstrap[1] << std::endl;
+            dht.bootstrap(params.bootstrap[0].c_str(), params.bootstrap[1].c_str());
         }
 
-        auto start = std::chrono::high_resolution_clock::now();
-        if (op == "g") {
-            dht.get(id, [start](std::shared_ptr<Value> value) {
-                auto now = std::chrono::high_resolution_clock::now();
-                std::cout << "Get: found value (after " << print_dt(now-start) << "s)" << std::endl;
-                std::cout << "\t" << *value << std::endl;
-                return true;
-            }, [start](bool ok) {
-                auto end = std::chrono::high_resolution_clock::now();
-                std::cout << "Get: " << (ok ? "completed" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            });
-        }
-        else if (op == "l") {
-            std::cout << id << std::endl;
-            dht.listen(id, [](std::shared_ptr<Value> value) {
-                std::cout << "Listen: found value:" << std::endl;
-                std::cout << "\t" << *value << std::endl;
-                return true;
-            });
-        }
-        else if (op == "p") {
-            std::string v;
-            iss >> v;
-            dht.put(id, dht::Value {
-                dht::ValueType::USER_DATA.id,
-                std::vector<uint8_t> {v.begin(), v.end()}
-            }, [start](bool ok) {
-                auto end = std::chrono::high_resolution_clock::now();
-                std::cout << "Put: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            });
-        }
-        else if (op == "s") {
-            if (not params.generate_identity) {
-                print_id_req();
+        print_node_info(dht, params);
+        std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl << std::endl;
+
+        while (true)
+        {
+            std::cout << ">> ";
+            std::string line;
+            std::getline(std::cin, line);
+            std::istringstream iss(line);
+            std::string op, idstr, value;
+            iss >> op >> idstr;
+
+            if (std::cin.eof() || op == "x" || op == "q" || op == "exit" || op == "quit") {
+                break;
+            } else if (op == "h" || op == "help") {
+                std::cout << "OpenDht command line interface (CLI)" << std::endl;
+                std::cout << "Possible commands:" << std::endl;
+                std::cout << "  h, help    Print this help message." << std::endl;
+                std::cout << "  q, quit    Quit the program." << std::endl;
+                std::cout << "  log        Print the full DHT log." << std::endl;
+
+                std::cout << std::endl << "Node information:" << std::endl;
+                std::cout << "  ll         Print basic information and stats about the current node." << std::endl;
+                std::cout << "  ls         Print basic information about current searches." << std::endl;
+                std::cout << "  ld         Print basic information about currenty stored values on this node." << std::endl;
+                std::cout << "  lr         Print the full current routing table of this node" << std::endl;
+
+                std::cout << std::endl << "Operations on the DHT:" << std::endl;
+                std::cout << "  g [key]               Get values at [key]." << std::endl;
+                std::cout << "  l [key]               Listen for value changes at [key]." << std::endl;
+                std::cout << "  p [key] [str]         Put string value at [key]." << std::endl;
+                std::cout << "  s [key] [str]         Put string value at [key], signed with our generated private key." << std::endl;
+                std::cout << "  e [key] [dest] [str]  Put string value at [key], encrypted for [dest] with its public key (if found)." << std::endl;
+                std::cout << std::endl;
+                continue;
+            } else if (op == "ll") {
+                print_node_info(dht, params);
+                unsigned good4, dubious4, cached4, incoming4;
+                unsigned good6, dubious6, cached6, incoming6;
+                dht.getNodesStats(AF_INET, &good4, &dubious4, &cached4, &incoming4);
+                dht.getNodesStats(AF_INET6, &good6, &dubious6, &cached6, &incoming6);
+                std::cout << "IPv4 nodes : " << good4 << " good, " << dubious4 << " dubious, " << incoming4 << " incoming." << std::endl;
+                std::cout << "IPv6 nodes : " << good6 << " good, " << dubious6 << " dubious, " << incoming6 << " incoming." << std::endl;
+                continue;
+            } else if (op == "lr") {
+                std::cout << "IPv4 routing table:" << std::endl;
+                std::cout << dht.getRoutingTablesLog(AF_INET) << std::endl;
+                std::cout << "IPv6 routing table:" << std::endl;
+                std::cout << dht.getRoutingTablesLog(AF_INET6) << std::endl;
+                continue;
+            } else if (op == "ld") {
+                std::cout << dht.getStorageLog() << std::endl;
+                continue;
+            } else if (op == "ls") {
+                std::cout << "Searches:" << std::endl;
+                std::cout << dht.getSearchesLog() << std::endl;
+                continue;
+            } else if (op == "la")  {
+                std::cout << "Reported public addresses:" << std::endl;
+                auto addrs = dht.getPublicAddressStr();
+                for (const auto& addr : addrs)
+                    std::cout << addr << std::endl;
+                continue;
+            } else if (op == "log") {
+                params.log = !params.log;
+                if (params.log)
+                    enableLogging(dht);
+                else
+                    disableLogging(dht);
                 continue;
             }
-            std::string v;
-            iss >> v;
-            dht.putSigned(id, dht::Value {
-                dht::ValueType::USER_DATA.id,
-                std::vector<uint8_t> {v.begin(), v.end()}
-            }, [start](bool ok) {
-                auto end = std::chrono::high_resolution_clock::now();
-                std::cout << "Put signed: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            });
-        }
-        else if (op == "e") {
-            if (not params.generate_identity) {
-                print_id_req();
+
+            if (op.empty())
+                continue;
+
+            dht::InfoHash id {idstr};
+            static const std::set<std::string> VALID_OPS {"g", "l", "p", "s", "e", "a"};
+            if (VALID_OPS.find(op) == VALID_OPS.cend()) {
+                std::cout << "Unknown command: " << op << std::endl;
+                std::cout << " (type 'h' or 'help' for a list of possible commands)" << std::endl;
                 continue;
             }
-            std::string tostr;
-            std::string v;
-            iss >> tostr >> v;
-            dht.putEncrypted(id, InfoHash(tostr), dht::Value {
-                dht::ValueType::USER_DATA.id,
-                std::vector<uint8_t> {v.begin(), v.end()}
-            }, [start](bool ok) {
-                auto end = std::chrono::high_resolution_clock::now();
-                std::cout << "Put encrypted: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            });
-        }
-        else if (op == "a") {
-            in_port_t port;
-            iss >> port;
-            dht.put(id, dht::Value {dht::IpServiceAnnouncement::TYPE.id, dht::IpServiceAnnouncement(port)}, [start](bool ok) {
-                auto end = std::chrono::high_resolution_clock::now();
-                std::cout << "Announce: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
-            });
+            static constexpr dht::InfoHash INVALID_ID {};
+            if (id == INVALID_ID) {
+                std::cout << "Syntax error: invalid InfoHash." << std::endl;
+                continue;
+            }
+
+            auto start = std::chrono::high_resolution_clock::now();
+            if (op == "g") {
+                dht.get(id, [start](std::shared_ptr<Value> value) {
+                    auto now = std::chrono::high_resolution_clock::now();
+                    std::cout << "Get: found value (after " << print_dt(now-start) << "s)" << std::endl;
+                    std::cout << "\t" << *value << std::endl;
+                    return true;
+                }, [start](bool ok) {
+                    auto end = std::chrono::high_resolution_clock::now();
+                    std::cout << "Get: " << (ok ? "completed" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
+                });
+            }
+            else if (op == "l") {
+                std::cout << id << std::endl;
+                dht.listen(id, [](std::shared_ptr<Value> value) {
+                    std::cout << "Listen: found value:" << std::endl;
+                    std::cout << "\t" << *value << std::endl;
+                    return true;
+                });
+            }
+            else if (op == "p") {
+                std::string v;
+                iss >> v;
+                dht.put(id, dht::Value {
+                    dht::ValueType::USER_DATA.id,
+                    std::vector<uint8_t> {v.begin(), v.end()}
+                }, [start](bool ok) {
+                    auto end = std::chrono::high_resolution_clock::now();
+                    std::cout << "Put: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
+                });
+            }
+            else if (op == "s") {
+                if (not params.generate_identity) {
+                    print_id_req();
+                    continue;
+                }
+                std::string v;
+                iss >> v;
+                dht.putSigned(id, dht::Value {
+                    dht::ValueType::USER_DATA.id,
+                    std::vector<uint8_t> {v.begin(), v.end()}
+                }, [start](bool ok) {
+                    auto end = std::chrono::high_resolution_clock::now();
+                    std::cout << "Put signed: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
+                });
+            }
+            else if (op == "e") {
+                if (not params.generate_identity) {
+                    print_id_req();
+                    continue;
+                }
+                std::string tostr;
+                std::string v;
+                iss >> tostr >> v;
+                dht.putEncrypted(id, InfoHash(tostr), dht::Value {
+                    dht::ValueType::USER_DATA.id,
+                    std::vector<uint8_t> {v.begin(), v.end()}
+                }, [start](bool ok) {
+                    auto end = std::chrono::high_resolution_clock::now();
+                    std::cout << "Put encrypted: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
+                });
+            }
+            else if (op == "a") {
+                in_port_t port;
+                iss >> port;
+                dht.put(id, dht::Value {dht::IpServiceAnnouncement::TYPE.id, dht::IpServiceAnnouncement(port)}, [start](bool ok) {
+                    auto end = std::chrono::high_resolution_clock::now();
+                    std::cout << "Announce: " << (ok ? "success" : "failure") << " (took " << print_dt(end-start) << "s)" << std::endl;
+                });
+            }
         }
+
+        std::cout << std::endl <<  "Stopping node..." << std::endl;
+    } catch(const std::exception&e) {
+        std::cout << std::endl <<  e.what() << std::endl;
     }
 
-    std::cout << std::endl <<  "Stopping node..." << std::endl;
     dht.join();
     gnutls_global_deinit();
+
     return 0;
 }
diff --git a/tools/tools_common.h b/tools/tools_common.h
index 83cb8b8e0ede2b3c1a2f2eeb885f3f514348a3df..e107188a918764cf509101bac4916c4547891684 100644
--- a/tools/tools_common.h
+++ b/tools/tools_common.h
@@ -128,6 +128,7 @@ static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
 
 struct dht_params {
     bool help {false}; // print help and exit
+    bool log {false};
     in_port_t port {DHT_DEFAULT_PORT};
     bool is_bootstrap_node {false};
     bool generate_identity {false};
@@ -139,6 +140,7 @@ static const struct option long_options[] = {
    {"port",       required_argument, nullptr, 'p'},
    {"bootstrap",  optional_argument, nullptr, 'b'},
    {"identity",   no_argument      , nullptr, 'i'},
+   {"verbose",    no_argument      , nullptr, 'v'},
    {nullptr,      0,                 nullptr,  0}
 };
 
@@ -146,7 +148,7 @@ dht_params
 parseArgs(int argc, char **argv) {
     dht_params params;
     int opt;
-    while ((opt = getopt_long(argc, argv, ":hip:b:", long_options, nullptr)) != -1) {
+    while ((opt = getopt_long(argc, argv, ":hivp:b:", long_options, nullptr)) != -1) {
         switch (opt) {
         case 'p': {
                 int port_arg = atoi(optarg);
@@ -168,6 +170,9 @@ parseArgs(int argc, char **argv) {
         case 'h':
             params.help = true;
             break;
+        case 'v':
+            params.log = true;
+            break;
         case 'i':
             params.generate_identity = true;
             break;