diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
index 9a84f2666dae976bf37c40bb69b0bad572b45f68..5e3c6f3e38d636260b08f225d57e41bf69504fbd 100644
--- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
+++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
@@ -1642,6 +1642,15 @@
            <arg type="t" name="dataTransferId" direction="in"/>
        </method>
 
+       <method name="monitor" tp:name-for-bindings="monitor">
+           <tp:added version="10.0.0"/>
+           <tp:docstring>
+               Monitor
+           </tp:docstring>
+           <arg type="b" name="continuous" direction="in">
+           </arg>
+       </method>
+
        <method name="startConversation" tp:name-for-bindings="startConversation">
            <tp:added version="10.0.0"/>
            <tp:docstring>
@@ -1650,7 +1659,6 @@
            <arg type="s" name="conversationId" direction="out"/>
            <arg type="s" name="accountId" direction="in"/>
        </method>
-
        <method name="acceptConversationRequest" tp:name-for-bindings="acceptConversationRequest">
            <tp:added version="10.0.0"/>
            <tp:docstring>
@@ -1996,5 +2004,14 @@
            <arg type="s" name="accountID" direction="in"/>
            <arg type="b" name="allModerators" direction="out"/>
        </method>
+
+        <signal name="messageSend" tp:name-for-bindings="messageSend">
+           <arg type="s" name="message">
+               <tp:docstring>
+                   Message from daemon
+               </tp:docstring>
+           </arg>
+           <tp:docstring>Signal triggered when a log is done in the daemon.</tp:docstring>
+        </signal>
    </interface>
 </node>
diff --git a/bin/dbus/dbusclient.cpp b/bin/dbus/dbusclient.cpp
index adb3b3d81e3432c04724a715e93289f3dc38664c..0881232c84e1a5baeb873b9079fb7112302f56b9 100644
--- a/bin/dbus/dbusclient.cpp
+++ b/bin/dbus/dbusclient.cpp
@@ -261,6 +261,8 @@ DBusClient::initLibrary(int flags)
             bind(&DBusConfigurationManager::hardwareDecodingChanged, confM, _1)),
         exportable_callback<ConfigurationSignal::HardwareEncodingChanged>(
             bind(&DBusConfigurationManager::hardwareEncodingChanged, confM, _1)),
+        exportable_callback<ConfigurationSignal::MessageSend>(
+            bind(&DBusConfigurationManager::messageSend, confM, _1)),
     };
 
     // Presence event handlers
diff --git a/bin/dbus/dbusconfigurationmanager.cpp b/bin/dbus/dbusconfigurationmanager.cpp
index aeeadb13114059b1b9dfa884cda141daefe31be4..1dd4e1c1d4100e8d079b7bbf9310831e93c3991d 100644
--- a/bin/dbus/dbusconfigurationmanager.cpp
+++ b/bin/dbus/dbusconfigurationmanager.cpp
@@ -75,6 +75,12 @@ DBusConfigurationManager::addAccount(const std::map<std::string, std::string>& d
     return DRing::addAccount(details);
 }
 
+auto
+DBusConfigurationManager::monitor(const bool& continuous) -> decltype(DRing::monitor(continuous))
+{
+    return DRing::monitor(continuous);
+}
+
 auto
 DBusConfigurationManager::exportOnRing(const std::string& accountID, const std::string& password)
     -> decltype(DRing::exportOnRing(accountID, password))
@@ -905,14 +911,15 @@ DBusConfigurationManager::setAudioMeterState(const std::string& id, const bool&
 
 void
 DBusConfigurationManager::setDefaultModerator(const std::string& accountID,
-                                                const std::string& peerURI,
-                                                const bool& state)
+                                              const std::string& peerURI,
+                                              const bool& state)
 {
     DRing::setDefaultModerator(accountID, peerURI, state);
 }
 
 auto
-DBusConfigurationManager::getDefaultModerators(const std::string& accountID) -> decltype(DRing::getDefaultModerators(accountID))
+DBusConfigurationManager::getDefaultModerators(const std::string& accountID)
+    -> decltype(DRing::getDefaultModerators(accountID))
 {
     return DRing::getDefaultModerators(accountID);
 }
@@ -941,5 +948,4 @@ bool
 DBusConfigurationManager::isAllModerators(const std::string& accountID)
 {
     return DRing::isAllModerators(accountID);
-}
-
+}
\ No newline at end of file
diff --git a/bin/dbus/dbusconfigurationmanager.h b/bin/dbus/dbusconfigurationmanager.h
index e0b56ce8835423d9c2a914d7535e87ef2a504ccf..e40620fa606f0853bd56c3c0dc1939cc7e6b177f 100644
--- a/bin/dbus/dbusconfigurationmanager.h
+++ b/bin/dbus/dbusconfigurationmanager.h
@@ -76,6 +76,7 @@ public:
         std::map<std::string, std::string> testAccountICEInitialization(const std::string& accountID);
         void setAccountActive(const std::string& accountID, const bool& active);
         std::map<std::string, std::string> getAccountTemplate(const std::string& accountType);
+        void monitor(const bool& continuous);
         std::string addAccount(const std::map<std::string, std::string>& details);
         bool exportOnRing(const std::string& accountID, const std::string& password);
         bool exportToFile(const std::string& accountID, const std::string& destinationPath, const std::string& password = {});
diff --git a/bin/jni/configurationmanager.i b/bin/jni/configurationmanager.i
index 66c4916ad6a4f24de843127e8792dedec0a71aec..e8eb2feaa8c815b4aa858ff23794bbb4a7e8fa41 100644
--- a/bin/jni/configurationmanager.i
+++ b/bin/jni/configurationmanager.i
@@ -66,6 +66,7 @@ public:
     virtual void hardwareEncodingChanged(bool /*state*/){}
 
     virtual void audioMeter(const std::string& /*id*/, float /*level*/){}
+    virtual void messageSend(const std::string& /*message*/){}
 };
 %}
 
@@ -86,6 +87,7 @@ std::map<std::string, std::string> getVolatileAccountDetails(const std::string&
 void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details);
 void setAccountActive(const std::string& accountID, bool active);
 std::map<std::string, std::string> getAccountTemplate(const std::string& accountType);
+void monitor(bool continuous);
 std::string addAccount(const std::map<std::string, std::string>& details);
 void removeAccount(const std::string& accountID);
 std::vector<std::string> getAccountList();
@@ -279,4 +281,5 @@ public:
     virtual void hardwareEncodingChanged(bool /*state*/){}
 
     virtual void audioMeter(const std::string& /*id*/, float /*level*/){}
+    virtual void messageSend(const std::string& /*message*/){}
 };
diff --git a/bin/jni/jni_interface.i b/bin/jni/jni_interface.i
index 10953578e6c31e25355bf6d8f466dd6d7ec66970..34030f34251f3ade5f8e20cb36beefdf91d6eefd 100644
--- a/bin/jni/jni_interface.i
+++ b/bin/jni/jni_interface.i
@@ -286,7 +286,8 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM
         exportable_callback<ConfigurationSignal::UserSearchEnded>(bind(&ConfigurationCallback::userSearchEnded, confM, _1, _2, _3, _4 )),
         exportable_callback<ConfigurationSignal::MigrationEnded>(bind(&ConfigurationCallback::migrationEnded, confM, _1, _2)),
         exportable_callback<ConfigurationSignal::DeviceRevocationEnded>(bind(&ConfigurationCallback::deviceRevocationEnded, confM, _1, _2, _3)),
-        exportable_callback<ConfigurationSignal::AccountProfileReceived>(bind(&ConfigurationCallback::accountProfileReceived, confM, _1, _2, _3))
+        exportable_callback<ConfigurationSignal::AccountProfileReceived>(bind(&ConfigurationCallback::accountProfileReceived, confM, _1, _2, _3)),
+        exportable_callback<ConfigurationSignal::MessageSend>(bind(&ConfigurationCallback::messageSend, confM, _1))
     };
 
     // Presence event handlers
diff --git a/bin/nodejs/configurationmanager.i b/bin/nodejs/configurationmanager.i
index 7f2f019c4b26faf3dcdfcf7de7eccb5df345be29..066a1f6fe6c3e53be37083ff1d3c52116dd80c90 100644
--- a/bin/nodejs/configurationmanager.i
+++ b/bin/nodejs/configurationmanager.i
@@ -79,6 +79,7 @@ std::map<std::string, std::string> getVolatileAccountDetails(const std::string&
 void setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details);
 void setAccountActive(const std::string& accountID, bool active);
 std::map<std::string, std::string> getAccountTemplate(const std::string& accountType);
+void monitor(bool continuous);
 std::string addAccount(const std::map<std::string, std::string>& details);
 void removeAccount(const std::string& accountID);
 std::vector<std::string> getAccountList();
@@ -256,4 +257,5 @@ public:
     virtual void hardwareEncodingChanged(bool /*state*/){}
 
     virtual void audioMeter(const std::string& /*id*/, float /*level*/){}
+    virtual void messageSend(const std::string& /*message*/){}
 };
diff --git a/src/account.h b/src/account.h
index efb68b723c88ca923a79bac0b6c23f305e0775ca..99c960e49e1d74e843e18a080a11623c87e71f88 100644
--- a/src/account.h
+++ b/src/account.h
@@ -324,7 +324,7 @@ public:
                                 const std::string& /*commitId*/) {};
 
     // Invites
-    virtual void onConversationRequest(const std::string& from, const Json::Value&) {};
+    virtual void onConversationRequest(const std::string& /* from */, const Json::Value&) {};
 
     /**
      * Helper function used to load the default codec order from the codec factory
diff --git a/src/call.cpp b/src/call.cpp
index da9f76528333fd9013cef698ba06430ac8fafdda..006a8f155cc84bc72c4faeda2bda7676a75a491a 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -126,7 +126,7 @@ Call::Call(const std::shared_ptr<Account>& account,
             if (!isSubcall() && getCallType() == CallType::OUTGOING) {
                 if (cnx_state == ConnectionState::CONNECTED && duration_start_ == time_point::min())
                     duration_start_ = clock::now();
-                else if (cnx_state == ConnectionState::DISCONNECTED) {
+                else if (cnx_state == ConnectionState::DISCONNECTED && call_state == CallState::OVER) {
                     if (auto jamiAccount = std::dynamic_pointer_cast<JamiAccount>(
                             getAccount().lock())) {
                         auto duration = duration_start_ == time_point::min()
@@ -135,6 +135,8 @@ Call::Call(const std::shared_ptr<Account>& account,
                                                   clock::now() - duration_start_)
                                                   .count();
                         jamiAccount->addCallHistoryMessage(getPeerNumber(), duration);
+
+                        monitor();
                     }
                 }
             }
diff --git a/src/call.h b/src/call.h
index 24a86e270da7e5990d0195e3b19c8aceb64d4107..e54632a070998ea487c7e41dbe1f2abd11effb8d 100644
--- a/src/call.h
+++ b/src/call.h
@@ -358,7 +358,11 @@ public: // media management
     void sendConfInfo(const std::string& json);
     void resetConfInfo();
 
+    virtual void monitor() const = 0;
+
 protected:
+    using clock = std::chrono::steady_clock;
+    using time_point = clock::time_point;
     virtual void merge(Call& scall);
 
     /**
@@ -394,10 +398,9 @@ protected:
 
     mutable std::mutex confInfoMutex_ {};
     mutable ConfInfo confInfo_ {};
+    time_point duration_start_ {time_point::min()};
 
 private:
-    using clock = std::chrono::steady_clock;
-    using time_point = clock::time_point;
 
     bool validStateTransition(CallState newState);
 
@@ -436,7 +439,6 @@ private:
     std::string peerDisplayName_ {};
 
     time_t timestamp_start_ {0};
-    time_point duration_start_ {time_point::min()};
 
     ///< MultiDevice: message received by subcall to merged yet
     MsgList pendingInMessages_;
diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp
index d86f9367dc10fc315440e1f90026aa54e0c68045..bb4fdef1e7c76d62f3dba47b74e8283280430f19 100644
--- a/src/client/configurationmanager.cpp
+++ b/src/client/configurationmanager.cpp
@@ -441,6 +441,12 @@ addAccount(const std::map<std::string, std::string>& details)
     return jami::Manager::instance().addAccount(details);
 }
 
+void
+monitor(bool continuous)
+{
+    return jami::Manager::instance().monitor(continuous);
+}
+
 void
 removeAccount(const std::string& accountID)
 {
diff --git a/src/client/ring_signal.cpp b/src/client/ring_signal.cpp
index 5d612b01dc76f4228b50923224f4003a2fb400a5..fe6d35cd5ae83c9ac166649e1eff219423c2ce91 100644
--- a/src/client/ring_signal.cpp
+++ b/src/client/ring_signal.cpp
@@ -89,9 +89,7 @@ getSignalHandlers()
 #endif
         exported_callback<DRing::ConfigurationSignal::HardwareDecodingChanged>(),
         exported_callback<DRing::ConfigurationSignal::HardwareEncodingChanged>(),
-
-        /* Debug */
-        exported_callback<DRing::DebugSignal::MessageSend>(),
+        exported_callback<DRing::ConfigurationSignal::MessageSend>(),
 
         /* Presence */
         exported_callback<DRing::PresenceSignal::NewServerSubscriptionRequest>(),
diff --git a/src/dring/configurationmanager_interface.h b/src/dring/configurationmanager_interface.h
index e528e504c39760930a0be369940a5bd60bf0f494..ffde8589ce7b67ecf301e59b8bc1e553f0a5dc41 100644
--- a/src/dring/configurationmanager_interface.h
+++ b/src/dring/configurationmanager_interface.h
@@ -63,6 +63,7 @@ DRING_PUBLIC std::map<std::string, std::string> testAccountICEInitialization(
 DRING_PUBLIC void setAccountActive(const std::string& accountID, bool active);
 DRING_PUBLIC std::map<std::string, std::string> getAccountTemplate(const std::string& accountType);
 DRING_PUBLIC std::string addAccount(const std::map<std::string, std::string>& details);
+DRING_PUBLIC void monitor(bool continuous);
 DRING_PUBLIC bool exportOnRing(const std::string& accountID, const std::string& password);
 DRING_PUBLIC bool exportToFile(const std::string& accountID,
                                const std::string& destinationPath,
@@ -282,8 +283,8 @@ DRING_PUBLIC void setAudioMeterState(const std::string& id, bool state);
  * Add/remove default moderator for conferences
  */
 DRING_PUBLIC void setDefaultModerator(const std::string& accountID,
-                                        const std::string& peerURI,
-                                        bool state);
+                                      const std::string& peerURI,
+                                      bool state);
 
 /**
  * Get default moderators for an account
@@ -293,8 +294,7 @@ DRING_PUBLIC std::vector<std::string> getDefaultModerators(const std::string& ac
 /**
  * Enable/disable local moderators for conferences
  */
-DRING_PUBLIC void enableLocalModerators(const std::string& accountID,
-                                        bool isModEnabled);
+DRING_PUBLIC void enableLocalModerators(const std::string& accountID, bool isModEnabled);
 
 /**
  * Get local moderators state
@@ -536,11 +536,6 @@ struct DRING_PUBLIC ConfigurationSignal
         constexpr static const char* name = "HardwareEncodingChanged";
         using cb_type = void(bool /* state */);
     };
-};
-
-// Can be used when a client's stdout is not available
-struct DRING_PUBLIC DebugSignal
-{
     struct DRING_PUBLIC MessageSend
     {
         constexpr static const char* name = "MessageSend";
diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp
index e3e963e6ca6354fc13016f9827231adaf2fef26f..3497579e62a81b08d32b716b255edf73509370e5 100644
--- a/src/ice_transport.cpp
+++ b/src/ice_transport.cpp
@@ -108,6 +108,8 @@ public:
 
     void getDefaultCandidates();
 
+    std::string link() const;
+
     // Non-mutex protected of public versions
     bool _isInitialized() const;
     bool _isStarted() const;
@@ -619,6 +621,28 @@ IceTransport::Impl::onComplete(pj_ice_strans* ice_st, pj_ice_strans_op op, pj_st
     iceCV_.notify_all();
 }
 
+std::string
+IceTransport::Impl::link() const
+{
+    std::ostringstream out;
+    for (unsigned i = 0; i < component_count_; ++i) {
+        auto laddr = getLocalAddress(i);
+        auto raddr = getRemoteAddress(i);
+
+        if (laddr and raddr) {
+            out << " [" << i + 1 << "] " << laddr.toString(true, true) << " ["
+                << getCandidateType(getSelectedCandidate(i, false)) << "] "
+                << " <-> " << raddr.toString(true, true) << " ["
+                << getCandidateType(getSelectedCandidate(i, true)) << "] ";
+        } else {
+            out << " [" << i + 1 << "] disabled";
+        }
+        if (i + 1 != component_count_)
+            out << "\n";
+    }
+    return out.str();
+}
+
 bool
 IceTransport::Impl::setInitiatorSession()
 {
@@ -1612,6 +1636,12 @@ IceTransport::setDefaultRemoteAddress(int comp_id, const IpAddr& addr)
     pimpl_->setDefaultRemoteAddress(comp_id, addr);
 }
 
+std::string
+IceTransport::link() const
+{
+    return pimpl_->link();
+}
+
 //==============================================================================
 
 IceTransportFactory::IceTransportFactory()
diff --git a/src/ice_transport.h b/src/ice_transport.h
index 453d7dc77a3768225bd454fd434a4477531db35c..2ee7c86cca5a81f711311e73e236f068456df38d 100644
--- a/src/ice_transport.h
+++ b/src/ice_transport.h
@@ -257,6 +257,8 @@ public:
 
     void setDefaultRemoteAddress(int comp_id, const IpAddr& addr);
 
+    std::string link() const;
+
 private:
     class Impl;
     std::unique_ptr<Impl> pimpl_;
diff --git a/src/jamidht/connectionmanager.cpp b/src/jamidht/connectionmanager.cpp
index 9d6b542ca752cff8752510b246c5ad86ea3a70d6..1ad0ff66c00b53e31967c3a772eb23d57e668c7f 100644
--- a/src/jamidht/connectionmanager.cpp
+++ b/src/jamidht/connectionmanager.cpp
@@ -1036,4 +1036,16 @@ ConnectionManager::activeSockets() const
     return pimpl_->infos_.size();
 }
 
+void
+ConnectionManager::monitor() const
+{
+    std::lock_guard<std::mutex> lk(pimpl_->infosMtx_);
+    JAMI_DBG("ConnectionManager for account %s (%s), current status:", pimpl_->account.getAccountID().c_str(), pimpl_->account.getUserUri().c_str());
+    for (const auto& [_, ci] : pimpl_->infos_) {
+        if (ci->socket_)
+            ci->socket_->monitor();
+    }
+    JAMI_DBG("ConnectionManager for account %s (%s), end status.", pimpl_->account.getAccountID().c_str(), pimpl_->account.getUserUri().c_str());
+}
+
 } // namespace jami
diff --git a/src/jamidht/connectionmanager.h b/src/jamidht/connectionmanager.h
index 81732d5f8ac9ccc11106efcc5b78bbe08fb40e65..43b80c58eb5a33bf3122d8223ba950bad474c659 100644
--- a/src/jamidht/connectionmanager.h
+++ b/src/jamidht/connectionmanager.h
@@ -133,6 +133,7 @@ public:
      * @return the number of active sockets
      */
     std::size_t activeSockets() const;
+    void monitor() const;
 
 private:
     ConnectionManager() = delete;
diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp
index 72b0782684d2daf7246bb1294f2808c2a89c0d4d..dae2f8a50f66784ac9ae907dc18c406c53256296 100644
--- a/src/jamidht/conversation.cpp
+++ b/src/jamidht/conversation.cpp
@@ -351,7 +351,7 @@ Conversation::sendMessage(const std::string& message,
 }
 
 std::string
-Conversation::sendMessage(const Json::Value& value, const std::string& parent)
+Conversation::sendMessage(const Json::Value& value, const std::string& /*parent*/)
 {
     Json::StreamWriterBuilder wbuilder;
     wbuilder["commentStyle"] = "None";
diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp
index 6b44af555539846501086bfb8cd5797efb77d20a..9b56f404345c9a456af4fc17c6226c5d52a453f4 100644
--- a/src/jamidht/jamiaccount.cpp
+++ b/src/jamidht/jamiaccount.cpp
@@ -2332,8 +2332,8 @@ JamiAccount::doRegister_()
                 auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
                                std::chrono::steady_clock::now().time_since_epoch())
                                .count();
-                jami::emitSignal<DRing::DebugSignal::MessageSend>(std::to_string(now) + " "
-                                                                  + std::string(tmp));
+                jami::emitSignal<DRing::ConfigurationSignal::MessageSend>(std::to_string(now) + " "
+                                                                          + std::string(tmp));
             };
             context.logger = std::make_shared<dht::Logger>(log_all, log_all, silent);
 #else
@@ -5252,4 +5252,11 @@ JamiAccount::addCallHistoryMessage(const std::string& uri, uint64_t duration_ms)
     }
 }
 
+void
+JamiAccount::monitor() const
+{
+    if (connectionManager_)
+        connectionManager_->monitor();
+}
+
 } // namespace jami
diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h
index b136cc5ca52de2a19e40c277c1106d615bebc0b8..7d425839b5111eef8fca90c3329900cbcf70e765 100644
--- a/src/jamidht/jamiaccount.h
+++ b/src/jamidht/jamiaccount.h
@@ -561,6 +561,8 @@ public:
     // Invites
     void onConversationRequest(const std::string& from, const Json::Value&) override;
 
+    void monitor() const;
+
 private:
     NON_COPYABLE(JamiAccount);
 
diff --git a/src/jamidht/multiplexed_socket.cpp b/src/jamidht/multiplexed_socket.cpp
index 37b888c2b6b2625d4c19b0e526397fa35832eca1..0eacdff5dadea1c864bbec66637517fcc50999de 100644
--- a/src/jamidht/multiplexed_socket.cpp
+++ b/src/jamidht/multiplexed_socket.cpp
@@ -21,6 +21,7 @@
 #include "multiplexed_socket.h"
 #include "peer_connection.h"
 #include "ice_transport.h"
+#include "security/certstore.h"
 
 #include <deque>
 #include <opendht/thread_pool.h>
@@ -29,6 +30,9 @@ namespace jami {
 
 static constexpr std::size_t IO_BUFFER_SIZE {8192}; ///< Size of char buffer used by IO operations
 
+using clock = std::chrono::steady_clock;
+using time_point = clock::time_point;
+
 struct ChannelInfo
 {
     std::deque<uint8_t> buf {};
@@ -149,6 +153,8 @@ public:
     std::atomic_bool isShutdown_ {false};
 
     std::mutex writeMtx {};
+
+    time_point start_ {clock::now()};
 };
 
 void
@@ -544,6 +550,27 @@ MultiplexedSocket::underlyingICE() const
     return pimpl_->endpoint->underlyingICE();
 }
 
+void
+MultiplexedSocket::monitor() const
+{
+    auto cert = tls::CertificateStore::instance().getCertificate(deviceId().toString());
+    if (!cert)
+        return;
+    auto userUri = cert->getIssuerUID();
+    JAMI_DBG("- Socket with device: %s - account: %s", deviceId().to_c_str(), userUri.c_str());
+    auto now = clock::now();
+    JAMI_DBG("- Duration: %lu",
+             std::chrono::duration_cast<std::chrono::milliseconds>(now - pimpl_->start_).count());
+    const auto& ice = underlyingICE();
+    if (ice)
+        JAMI_DBG("\t- Ice connection: %s", ice->link().c_str());
+    std::lock_guard<std::mutex> lk(pimpl_->socketsMutex);
+    for (const auto& [_, channel] : pimpl_->sockets) {
+        if (channel)
+            JAMI_DBG("\t\t- Channel with name %s", channel->name().c_str());
+    }
+}
+
 ////////////////////////////////////////////////////////////////
 
 class ChannelSocket::Impl
diff --git a/src/jamidht/multiplexed_socket.h b/src/jamidht/multiplexed_socket.h
index 52bf70fe053fe6e7133b666750697dee2b149475..ab69b88dd78154b2f277789306667799f5a07b25 100644
--- a/src/jamidht/multiplexed_socket.h
+++ b/src/jamidht/multiplexed_socket.h
@@ -129,6 +129,8 @@ public:
 
     std::shared_ptr<IceTransport> underlyingICE() const;
 
+    void monitor() const;
+
 private:
     class Impl;
     std::unique_ptr<Impl> pimpl_;
diff --git a/src/logger.cpp b/src/logger.cpp
index 53615b3e0774db7c16af26116610d6792bb881ab..11a308e50f6d429d4bcf16a76d4e9d738d1f402f 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -91,6 +91,7 @@ static constexpr auto ENDL = "\n";
 #endif
 
 static int consoleLog;
+static bool monitorLog;
 static int debugMode;
 static std::mutex logMutex;
 
@@ -168,12 +169,24 @@ setDebugMode(int d)
     debugMode = d;
 }
 
+void
+setMonitorLog(bool m)
+{
+    monitorLog = m;
+}
+
 int
 getDebugMode(void)
 {
     return debugMode;
 }
 
+bool
+getMonitorLog(void)
+{
+    return monitorLog;
+}
+
 static const char*
 check_error(int result, char* buffer)
 {
@@ -212,19 +225,29 @@ void
 Logger::log(int level, const char* file, int line, bool linefeed, const char* const format, ...)
 {
 #if defined(TARGET_OS_IOS) && TARGET_OS_IOS
-    if (!debugMode)
+    if (!debugMode && !monitorLog)
         return;
 #endif
-    if (!debugMode && level == LOG_DEBUG)
+    if (!debugMode && !monitorLog && level == LOG_DEBUG)
         return;
 
     va_list ap;
     va_start(ap, format);
+    va_list cp;
+    if (monitorLog)
+        va_copy(cp, ap);
 #ifdef __ANDROID__
     __android_log_vprint(level, APP_NAME, format, ap);
 #else
     Logger::vlog(level, file, line, linefeed, format, ap);
 #endif
+
+    if (monitorLog) {
+        std::array<char, 4096> tmp;
+        vsnprintf(tmp.data(), tmp.size(), format, cp);
+        jami::emitSignal<DRing::ConfigurationSignal::MessageSend>(contextHeader(file, line)
+                                                                  + tmp.data());
+    }
     va_end(ap);
 }
 
@@ -243,7 +266,7 @@ Logger::vlog(
     // follow strictly POSIX rules... so we lock our mutex in any cases.
     std::lock_guard<std::mutex> lk {logMutex};
 
-    if (consoleLog) {
+    if (consoleLog or monitorLog) {
 #ifndef _WIN32
         const char* color_header = CYAN;
         const char* color_prefix = "";
@@ -278,7 +301,8 @@ Logger::vlog(
 #ifdef _MSC_VER
         std::array<char, 4096> tmp;
         vsnprintf(tmp.data(), tmp.size(), format, ap);
-        jami::emitSignal<DRing::DebugSignal::MessageSend>(contextHeader(file, line) + tmp.data());
+        jami::emitSignal<DRing::ConfigurationSignal::MessageSend>(contextHeader(file, line)
+                                                                  + tmp.data());
 #endif
 #ifndef _WIN32
         fputs(END_COLOR, stderr);
diff --git a/src/logger.h b/src/logger.h
index e7d8de05e5fa5b557991b9181e2435e084c747d2..0c4e93093636403dc734e137a27c0c5535fd464c 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -48,6 +48,9 @@ void setDebugMode(int d);
  */
 int getDebugMode(void);
 
+void setMonitorLog(bool m);
+bool getMonitorLog(void);
+
 /**
  * Thread-safe function to print the stringified contents of errno
  */
diff --git a/src/manager.cpp b/src/manager.cpp
index caee34f38291b27bf6e8d8353dc3839a6b6eb63f..a085b45eff1b37dd364b95cb00ab4e7054f59549 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -924,6 +924,32 @@ Manager::finish() noexcept
     }
 }
 
+void
+Manager::monitor(bool continuous)
+{
+    setMonitorLog(true);
+    JAMI_DBG("############## START MONITORING ##############");
+    JAMI_DBG("Using PJSIP version %s for %s", pj_get_version(), PJ_OS_NAME);
+    JAMI_DBG("Using GnuTLS version %s", gnutls_check_version(nullptr));
+    JAMI_DBG("Using OpenDHT version %s", dht::version());
+
+#ifdef __linux__
+#if defined(__ANDROID__)
+#else
+    auto opened_files = fileutils::readDirectory("/proc/" + std::to_string(getpid()) + "/fd").size();
+    JAMI_DBG("Opened files: %lu", opened_files);
+#endif
+#endif
+
+    for (const auto& call : callFactory.getAllCalls())
+        call->monitor();
+    for (const auto& account : getAllAccounts())
+        if (auto acc = std::dynamic_pointer_cast<JamiAccount>(account))
+            acc->monitor();
+    JAMI_DBG("############## END MONITORING ##############");
+    setMonitorLog(continuous);
+}
+
 bool
 Manager::isCurrentCall(const Call& call) const
 {
diff --git a/src/manager.h b/src/manager.h
index 3103f72a8c94f2f1befc52048be017cf90fafd05..98ec4686334a3b11c74e11f595d7689821cbbee4 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -126,6 +126,8 @@ public:
      */
     void finish() noexcept;
 
+    void monitor(bool continuous);
+
     /**
      * Accessor to audiodriver.
      * it's multi-thread and use mutex internally
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index 008724b987c5a814a0af858fc74e03f03bdb33e5..1f4c420c369455c3c4d3eacd59002ffed663ed51 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -54,6 +54,7 @@
 #include <chrono>
 #include <libavutil/display.h>
 #endif
+#include "jamidht/channeled_transport.h"
 
 #include "errno.h"
 
@@ -2006,6 +2007,36 @@ SIPCall::getVideoRtp() const
 }
 #endif
 
+void
+SIPCall::monitor() const
+{
+    if (isSubcall())
+        return;
+    auto acc = getSIPAccount();
+    if (!acc) {
+        JAMI_ERR("No account detected");
+        return;
+    }
+    JAMI_DBG("- Call %s with %s:", getCallId().c_str(), getPeerNumber().c_str());
+    // TODO move in getCallDuration
+    auto duration = duration_start_ == time_point::min()
+                        ? 0
+                        : std::chrono::duration_cast<std::chrono::milliseconds>(clock::now()
+                                                                                - duration_start_)
+                              .count();
+    JAMI_DBG("\t- Duration: %lu", duration);
+    for (auto& mediaAttr : getMediaAttributeList())
+        JAMI_DBG("\t- Media: %s", mediaAttr.toString(true).c_str());
+#ifdef ENABLE_VIDEO
+    if (auto codec = getVideoCodec())
+        JAMI_DBG("\t- Video codec: %s", codec->systemCodecInfo.name.c_str());
+#endif
+    auto media_tr = getIceMediaTransport();
+    if (media_tr) {
+        JAMI_DBG("\t- Medias: %s", media_tr->link().c_str());
+    }
+}
+
 bool
 SIPCall::toggleRecording()
 {
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index 8c4c537ccb2580d87c7bd83faf2aafe16b25e519..5dc0de5e06d30c21fcbd3030a2c84d93d599a91d 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -164,6 +164,8 @@ public:
     void peerMuted(bool state) override;
     // End of override of Recordable class
 
+    void monitor() const override;
+
     /**
      * Return the SDP's manager of this call
      */