diff --git a/src/logger.cpp b/src/logger.cpp
index 6167a903f251fe34743a6db64f3818399bdeda0d..d33265a612651bf878344a51ae26fa4bb5720074 100644
--- a/src/logger.cpp
+++ b/src/logger.cpp
@@ -163,48 +163,48 @@ contextHeader(const char* const file, int line)
     }
 }
 
-struct BufDeleter
+std::string
+formatPrintfArgs(const char* format, va_list ap)
 {
-    void operator()(char* ptr)
-    {
-        if (ptr) {
-            free(ptr);
-        }
+    std::string ret;
+    /* A good guess of what we might encounter. */
+    static constexpr size_t default_buf_size = 80;
+
+    ret.resize(default_buf_size);
+
+    /* Necessary if we don't have enough space in buf. */
+    va_list cp;
+    va_copy(cp, ap);
+
+    int size = vsnprintf(ret.data(), ret.size(), format, ap);
+
+    /* Not enough space?  Well try again. */
+    if (size >= ret.size()) {
+        ret.resize(size + 1);
+        vsnprintf((char*) ret.data(), ret.size(), format, cp);
     }
-};
+
+    va_end(cp);
+    return ret;
+}
 
 struct Logger::Msg
 {
     Msg() = delete;
 
-    Msg(int level, const char* file, int line, bool linefeed, const char* fmt, va_list ap)
+    Msg(int level, const char* file, int line, bool linefeed, std::string&& message)
         : header_(contextHeader(file, line))
         , level_(level)
         , linefeed_(linefeed)
-    {
-        /* A good guess of what we might encounter. */
-        static constexpr size_t default_buf_size = 80;
-
-        char* buf = (char*) malloc(default_buf_size);
-        int buf_size = default_buf_size;
-        va_list cp;
-
-        /* Necessary if we don't have enough space in buf. */
-        va_copy(cp, ap);
-
-        int size = vsnprintf(buf, buf_size, fmt, ap);
-
-        /* Not enough space?  Well try again. */
-        if (size >= buf_size) {
-            buf_size = size + 1;
-            buf = (char*) realloc(buf, buf_size);
-            vsnprintf(buf, buf_size, fmt, cp);
-        }
+        , payload_(std::move(message))
+    {}
 
-        payload_.reset(buf);
-
-        va_end(cp);
-    }
+    Msg(int level, const char* file, int line, bool linefeed, const char* fmt, va_list ap)
+        : header_(contextHeader(file, line))
+        , level_(level)
+        , linefeed_(linefeed)
+        , payload_(formatPrintfArgs(fmt, ap))
+    {}
 
     Msg(Msg&& other)
     {
@@ -214,7 +214,7 @@ struct Logger::Msg
         linefeed_ = other.linefeed_;
     }
 
-    std::unique_ptr<char, BufDeleter> payload_;
+    std::string payload_;
     std::string header_;
     int level_;
     bool linefeed_;
@@ -277,7 +277,7 @@ public:
             fputs(msg.header_.c_str(), stderr);
         }
 
-        fputs(msg.payload_.get(), stderr);
+        fputs(msg.payload_.c_str(), stderr);
 
         if (msg.linefeed_) {
             putc(ENDL, stderr);
@@ -312,7 +312,7 @@ public:
             fputs(msg.header_.c_str(), stderr);
         }
 
-        fputs(msg.payload_.get(), stderr);
+        fputs(msg.payload_.c_str(), stderr);
 
         if (msg.linefeed_) {
             putc(ENDL, stderr);
@@ -385,9 +385,9 @@ public:
     virtual void consume(Logger::Msg& msg) override
     {
 #ifdef __ANDROID__
-        __android_log_print(msg.level_, APP_NAME, "%s%s", msg.header_.c_str(), msg.payload_.get());
+        __android_log_print(msg.level_, APP_NAME, "%s%s", msg.header_.c_str(), msg.payload_.c_str());
 #else
-        ::syslog(msg.level_, "%s", msg.payload_.get());
+        ::syslog(msg.level_, "%s", msg.payload_.c_str());
 #endif
     }
 };
@@ -415,7 +415,7 @@ public:
          * TODO - Maybe change the MessageSend sigature to avoid copying
          * of message payload?
          */
-        auto tmp = msg.header_ + std::string(msg.payload_.get());
+        auto tmp = msg.header_ + msg.payload_;
 
         jami::emitSignal<DRing::ConfigurationSignal::MessageSend>(tmp);
     }
@@ -496,7 +496,7 @@ private:
     void do_consume(std::ofstream& file, const std::vector<Logger::Msg>& messages)
     {
         for (const auto& msg : messages) {
-            file << msg.header_ << msg.payload_.get();
+            file << msg.header_ << msg.payload_;
 
             if (msg.linefeed_)
                 file << ENDL;
@@ -572,6 +572,17 @@ Logger::vlog(int level, const char* file, int line, bool linefeed, const char* f
     log_to_if_enabled(FileLog::instance(), msg); // Takes ownership of msg if enabled
 }
 
+void
+Logger::write(int level, const char* file, int line, std::string&& message) {
+    /* Timestamp is generated here. */
+    Msg msg(level, file, line, true, std::move(message));
+
+    log_to_if_enabled(ConsoleLog::instance(), msg);
+    log_to_if_enabled(SysLog::instance(), msg);
+    log_to_if_enabled(MonitorLog::instance(), msg);
+    log_to_if_enabled(FileLog::instance(), msg); // Takes ownership of msg if enabled
+}
+
 void
 Logger::fini()
 {
diff --git a/src/logger.h b/src/logger.h
index ae75fe8e206bd18c146b113e8f6867841d3d817d..690ccf8a07530d1ee329ba06a4e267acd4e8d413 100644
--- a/src/logger.h
+++ b/src/logger.h
@@ -24,6 +24,9 @@
 #include "jami/def.h"
 
 //#define __STDC_FORMAT_MACROS 1
+#include <fmt/core.h>
+#include <fmt/format.h>
+
 #include <cinttypes> // for PRIx64
 #include <cstdarg>
 
@@ -107,6 +110,9 @@ public:
         return *this;
     }
 
+    DRING_PUBLIC
+    static void write(int level, const char* file, int line, std::string&& message);
+
     ///
     /// Printf fashion logging.
     ///
@@ -152,6 +158,25 @@ private:
     std::ostringstream os_; ///< string stream used with C++ stream style (stream operator<<)
 };
 
+namespace log {
+
+template<typename S, typename... Args>
+void dbg(const char* file, int line, S&& format, Args&&... args) {
+    Logger::write(LOG_DEBUG, file, line, fmt::format(std::forward<S>(format), std::forward<Args>(args)...));
+}
+
+template<typename S, typename... Args>
+void warn(const char* file, int line, S&& format, Args&&... args) {
+    Logger::write(LOG_WARNING, file, line, fmt::format(std::forward<S>(format), std::forward<Args>(args)...));
+}
+
+template<typename S, typename... Args>
+void error(const char* file, int line, S&& format, Args&&... args) {
+    Logger::write(LOG_ERR, file, line, fmt::format(std::forward<S>(format), std::forward<Args>(args)...));
+}
+
+}
+
 // We need to use macros for contextual information
 #define JAMI_INFO(...) ::jami::Logger::log(LOG_INFO, __FILE__, __LINE__, true, ##__VA_ARGS__)
 #define JAMI_DBG(...)  ::jami::Logger::log(LOG_DEBUG, __FILE__, __LINE__, true, ##__VA_ARGS__)
@@ -163,4 +188,8 @@ private:
 #define JAMI_XWARN(...) ::jami::Logger::log(LOG_WARNING, __FILE__, __LINE__, false, ##__VA_ARGS__)
 #define JAMI_XERR(...)  ::jami::Logger::log(LOG_ERR, __FILE__, __LINE__, false, ##__VA_ARGS__)
 
+#define JAMI_DEBUG(...) if(::jami::Logger::debugEnabled()) { ::jami::log::dbg(__FILE__, __LINE__, ##__VA_ARGS__); }
+#define JAMI_WARNING(...) ::jami::log::warn(__FILE__, __LINE__, ##__VA_ARGS__)
+#define JAMI_ERROR(...) ::jami::log::error(__FILE__, __LINE__, ##__VA_ARGS__)
+
 } // namespace jami