diff --git a/include/opendht.h b/include/opendht.h
index 911d0dbd019b666e2a7ece4fd798675123c035de..dd34d5516a4fa2627644da0c4adb5a5e4f656986 100644
--- a/include/opendht.h
+++ b/include/opendht.h
@@ -22,7 +22,6 @@
 #ifdef OPENDHT_PROXY_SERVER
 #include "opendht/dht_proxy_server.h"
 #endif
-#include "opendht/log.h"
 #include "opendht/default_types.h"
 #ifdef OPENDHT_INDEXATION
 #include "opendht/indexation/pht.h"
diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index 435f0f8fecd56f7a40f871e714d3b09cd637209d..266ff0a22cd693e289375e66d069b9186b47451d 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -68,7 +68,7 @@ public:
      * Initialise the Dht with two open sockets (for IPv4 and IP6)
      * and an ID for the node.
      */
-    Dht(const int& s, const int& s6, const Config& config);
+    Dht(const int& s, const int& s6, const Config& config, const Logger& l = {});
     virtual ~Dht();
 
     /**
diff --git a/include/opendht/dht_interface.h b/include/opendht/dht_interface.h
index 7d1694bee7987abd9ca00ea96f9fbc2bea79f607..9dbc871111959c589af2d2dcc980f5a6604b99a2 100644
--- a/include/opendht/dht_interface.h
+++ b/include/opendht/dht_interface.h
@@ -26,6 +26,7 @@ namespace dht {
 class OPENDHT_PUBLIC DhtInterface {
 public:
     DhtInterface() = default;
+    DhtInterface(const Logger& l) : DHT_LOG(l) {};
     virtual ~DhtInterface() = default;
 
     // [[deprecated]]
@@ -221,6 +222,10 @@ public:
         DHT_LOG.ERR = error;
     }
 
+    virtual void setLogger(const Logger& l) {
+        DHT_LOG = l;
+    }
+
     /**
      * Only print logs related to the given InfoHash (if given), or disable filter (if zeroes).
      */
diff --git a/include/opendht/dht_proxy_client.h b/include/opendht/dht_proxy_client.h
index f7a3b47c300fc4bc83a75daa491621a82307171e..39ae912ca37a55c26ff5d646f86b8c11950e143f 100644
--- a/include/opendht/dht_proxy_client.h
+++ b/include/opendht/dht_proxy_client.h
@@ -44,7 +44,7 @@ public:
 
     DhtProxyClient();
 
-    explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "");
+    explicit DhtProxyClient(std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "", const Logger& = {});
 
     virtual void setPushNotificationToken(const std::string& token) {
 #ifdef OPENDHT_PUSH_NOTIFICATIONS
diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index aa638c5bc49615ebbddf63071b9109edef33bb14..cbf636979a7f81ae449f9c124919751955be9bc7 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -322,6 +322,7 @@ public:
 
     std::vector<ValuesExport> exportValues() const;
 
+    void setLogger(const Logger& logger = {});
     void setLoggers(LogMethod err = NOLOG, LogMethod warn = NOLOG, LogMethod debug = NOLOG);
 
     /**
diff --git a/include/opendht/log.h b/include/opendht/log.h
index a856e1d470e80dfc334ba010cb8e6166dc3c528b..524d01b7d40c669783dd5d3906eb9d42470f38f0 100644
--- a/include/opendht/log.h
+++ b/include/opendht/log.h
@@ -66,6 +66,15 @@ constexpr const Color::Modifier yellow(Color::FG_YELLOW);
 OPENDHT_PUBLIC void
 printLog(std::ostream &s, char const *m, va_list args);
 
+OPENDHT_PUBLIC
+std::unique_ptr<Logger> getStdLogger();
+
+OPENDHT_PUBLIC
+std::unique_ptr<Logger> getFileLogger(const std::string &path);
+
+OPENDHT_PUBLIC
+std::unique_ptr<Logger> getSyslogLogger(const char* name);
+
 OPENDHT_PUBLIC void
 enableLogging(dht::DhtRunner &dht);
 
diff --git a/include/opendht/log_enable.h b/include/opendht/log_enable.h
index 7ce7ffd9c7f278a7ba123b610665f1edbec0d2bf..6f53364c5b2e137eadcd4b7656259fda13671eb3 100644
--- a/include/opendht/log_enable.h
+++ b/include/opendht/log_enable.h
@@ -88,6 +88,9 @@ struct Logger {
     LogMethod DBG = NOLOG;
     LogMethod WARN = NOLOG;
     LogMethod ERR = NOLOG;
+    Logger() = default;
+    Logger(LogMethod&& err, LogMethod&& warn, LogMethod&& dbg)
+        : DBG(std::move(dbg)), WARN(std::move(warn)), ERR(std::move(err)) {}
     void setFilter(const InfoHash& f) {
         filter_ = f;
         filterEnable_ = static_cast<bool>(filter_);
diff --git a/src/dht.cpp b/src/dht.cpp
index 87d0544b65d5dc2b4d8c4b2d2af5139d457babd3..faa4645c1e7e398942ad265621e2fea13105266c 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -1691,8 +1691,8 @@ Dht::~Dht()
 
 Dht::Dht() : store(), network_engine(DHT_LOG, scheduler) {}
 
-Dht::Dht(const int& s, const int& s6, const Config& config)
-    : myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(),
+Dht::Dht(const int& s, const int& s6, const Config& config, const Logger& l)
+    : DhtInterface(l), myid(config.node_id ? config.node_id : InfoHash::getRandom()), store(), store_quota(),
     network_engine(myid, config.network, s, s6, DHT_LOG, scheduler,
             std::bind(&Dht::onError, this, _1, _2),
             std::bind(&Dht::onNewNode, this, _1, _2),
diff --git a/src/dht_proxy_client.cpp b/src/dht_proxy_client.cpp
index 5e40e94b5b608bed3938e058dabcf0a63de11679..963201d471f03ccd4b04656586af573828ff936c 100644
--- a/src/dht_proxy_client.cpp
+++ b/src/dht_proxy_client.cpp
@@ -72,8 +72,8 @@ struct DhtProxyClient::ProxySearch {
 
 DhtProxyClient::DhtProxyClient() {}
 
-DhtProxyClient::DhtProxyClient(std::function<void()> signal, const std::string& serverHost, const std::string& pushClientId)
-: serverHost_(serverHost), pushClientId_(pushClientId), loopSignal_(signal)
+DhtProxyClient::DhtProxyClient(std::function<void()> signal, const std::string& serverHost, const std::string& pushClientId, const Logger& l)
+: DhtInterface(l), serverHost_(serverHost), pushClientId_(pushClientId), loopSignal_(signal)
 {
     if (serverHost_.find("://") == std::string::npos)
         serverHost_ = proxy::HTTP_PROTO + serverHost_;
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index fb96d0f8bda29fa4b883eac2cae8e130b9f07d95..d75273890ced476e126b679ee86132d7a0b37990 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -105,19 +105,15 @@ DhtRunner::run(const SockAddr& local4, const SockAddr& local6, const DhtRunner::
         return;
     startNetwork(local4, local6);
 
-    auto dht = std::unique_ptr<DhtInterface>(new Dht(s4, s6, SecureDht::getConfig(config.dht_config)));
+    auto dht = std::unique_ptr<DhtInterface>(new Dht(s4, s6, SecureDht::getConfig(config.dht_config), context.logger ? *context.logger : Logger{}));
     dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
 
 #ifdef OPENDHT_PROXY_CLIENT
     config_ = config;
 #endif
     enableProxy(not config.proxy_server.empty());
-
-    if (context.logger) {
-        if (dht_)
-            dht_->setLoggers(context.logger->ERR, context.logger->WARN, context.logger->DBG);
-        if (dht_via_proxy_)
-            dht_via_proxy_->setLoggers(context.logger->ERR, context.logger->WARN, context.logger->DBG);
+    if (context.logger and dht_via_proxy_) {
+        dht_via_proxy_->setLogger(*context.logger);
     }
 
     running = true;
@@ -297,16 +293,22 @@ DhtRunner::exportValues() const {
 }
 
 void
-DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
+DhtRunner::setLogger(const Logger& logger) {
     std::lock_guard<std::mutex> lck(dht_mtx);
     if (dht_)
-        dht_->setLoggers(error, warn, debug);
+        dht_->setLogger(logger);
 #ifdef OPENDHT_PROXY_CLIENT
     if (dht_via_proxy_)
-        dht_via_proxy_->setLoggers(error, warn, debug);
+        dht_via_proxy_->setLogger(logger);
 #endif
 }
 
+void
+DhtRunner::setLoggers(LogMethod error, LogMethod warn, LogMethod debug) {
+    Logger logger {std::move(error), std::move(warn), std::move(debug)};
+    setLogger(logger);
+}
+
 void
 DhtRunner::setLogFilter(const InfoHash& f) {
     std::lock_guard<std::mutex> lck(dht_mtx);
diff --git a/src/log.cpp b/src/log.cpp
index 93a36788d7d1135450ec2e06be8c6b52d3190a1e..0f7a9ee552cc7c3db260e59d2bfe19d8464baaac 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -55,9 +55,9 @@ printLog(std::ostream& s, char const *m, va_list args) {
     s << std::endl;
 }
 
-void
-enableLogging(dht::DhtRunner &dht) {
-    dht.setLoggers(
+std::unique_ptr<Logger>
+getStdLogger() {
+    return std::unique_ptr<Logger>(new Logger(
         [](char const *m, va_list args) {
             std::cerr << red;
             printLog(std::cerr, m, args);
@@ -69,23 +69,23 @@ enableLogging(dht::DhtRunner &dht) {
             std::cout << def;
         },
         [](char const *m, va_list args) { printLog(std::cout, m, args); }
-    );
+    ));
 }
 
-void
-enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
+std::unique_ptr<Logger>
+getFileLogger(const std::string &path) {
     auto logfile = std::make_shared<std::ofstream>();
     logfile->open(path, std::ios::out);
 
-    dht.setLoggers(
+    return std::unique_ptr<Logger>(new Logger(
         [=](char const *m, va_list args) { printLog(*logfile, m, args); },
         [=](char const *m, va_list args) { printLog(*logfile, m, args); },
         [=](char const *m, va_list args) { printLog(*logfile, m, args); }
-    );
+    ));
 }
 
-OPENDHT_PUBLIC void
-enableSyslog(dht::DhtRunner &dht, const char* name) {
+std::unique_ptr<Logger>
+getSyslogLogger(const char* name) {
 #ifndef _WIN32
     struct Syslog {
         Syslog(const char* n) {
@@ -102,14 +102,31 @@ enableSyslog(dht::DhtRunner &dht, const char* name) {
         logfile = std::make_shared<Syslog>(name);
         opened_logfile = logfile;
     }
-    dht.setLoggers(
+    return std::unique_ptr<Logger>(new Logger(
         [logfile](char const *m, va_list args) { vsyslog(LOG_ERR, m, args); },
         [logfile](char const *m, va_list args) { vsyslog(LOG_WARNING, m, args); },
         [logfile](char const *m, va_list args) { vsyslog(LOG_INFO, m, args); }
-    );
+    ));
+#else
+    return std::unique_ptr<Logger>(new Logger());
 #endif
 }
 
+void
+enableLogging(dht::DhtRunner &dht) {
+    dht.setLogger(*getStdLogger());
+}
+
+void
+enableFileLogging(dht::DhtRunner &dht, const std::string &path) {
+    dht.setLogger(*getFileLogger(path));
+}
+
+OPENDHT_PUBLIC void
+enableSyslog(dht::DhtRunner &dht, const char* name) {
+    dht.setLogger(*getSyslogLogger(name));
+}
+
 void
 disableLogging(dht::DhtRunner &dht) {
     dht.setLoggers(dht::NOLOG, dht::NOLOG, dht::NOLOG);
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index 18d89080997fe6e8cd5ff2505cfe1f6b4bbd59de..05b235dc7a240a550431dcf5b4e52f65d856f92f 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -529,17 +529,18 @@ main(int argc, char **argv)
         if (not params.proxyclient.empty())
             node->setPushNotificationToken(params.devicekey);
 
-        node->run(params.port, config);
-
+        dht::DhtRunner::Context context {};
         if (params.log) {
             if (params.syslog or (params.daemonize and params.logfile.empty()))
-                log::enableSyslog(*node, "dhtnode");
+                context.logger = log::getSyslogLogger("dhtnode");
             else if (not params.logfile.empty())
-                log::enableFileLogging(*node, params.logfile);
+                context.logger = log::getFileLogger(params.logfile);
             else
-                log::enableLogging(*node);
+                context.logger = log::getStdLogger();
         }
 
+        node->run(params.port, config, std::move(context));
+
         if (not params.bootstrap.first.empty()) {
             //std::cout << "Bootstrap: " << params.bootstrap.first << ":" << params.bootstrap.second << std::endl;
             node->bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str());
diff --git a/tools/tools_common.h b/tools/tools_common.h
index 49bacea5c81b5d309504e474067cd463547376e3..de16bd3946803a924ae167327b9bf63c4a4c801e 100644
--- a/tools/tools_common.h
+++ b/tools/tools_common.h
@@ -22,6 +22,7 @@
 #pragma once
 
 #include <opendht.h>
+#include <opendht/log.h>
 #ifndef WIN32_NATIVE
 #include <getopt.h>
 #include <readline/readline.h>