diff --git a/PreCompiledHeaders.cmake b/PreCompiledHeaders.cmake
index dce8f03b4c87f3ac598c970fe04e5e173e476c6e..f09e72ab569a20b3f841dd0b73132b36f301481f 100644
--- a/PreCompiledHeaders.cmake
+++ b/PreCompiledHeaders.cmake
@@ -23,6 +23,7 @@ set(STL_INC
     <climits>
     <ctype.h>
     <mutex>
+    <iomanip>
 )
 
 set(EXT_INC PRIVATE
diff --git a/src/Lib/AbstractDocument.hh b/src/Lib/AbstractDocument.hh
index dfec447f3bdbc696e313bc6985b487ea94ad1a8a..d7761f44e1d1d103600e9c77c245a315bd59f03b 100644
--- a/src/Lib/AbstractDocument.hh
+++ b/src/Lib/AbstractDocument.hh
@@ -4,14 +4,17 @@
 #error "This is a C++ header"
 #endif
 
+#include "../VivyApplication.hh"
 #include "Utils.hh"
 #include "Uuid.hh"
+#include "Log.hh"
 
 namespace Vivy
 {
 class AbstractDocument : public QObject {
     Q_OBJECT
     VIVY_UNMOVABLE_OBJECT(AbstractDocument)
+    VIVY_APP_LOGGABLE_OBJECT(AbstractDocument, logger)
 
     void copyOrRenameWith(const QFileInfo &newFile, auto action, auto success)
     {
@@ -21,7 +24,7 @@ class AbstractDocument : public QObject {
         QDir dirOp;
         const QString newAbsDirPath = newFile.dir().absolutePath();
         if (!dirOp.exists(newAbsDirPath)) {
-            qInfo() << "Create folder " << newAbsDirPath;
+            logInfo() << "Create folder " << VIVY_LOG_QUOTED(newAbsDirPath);
             dirOp.mkpath(newAbsDirPath);
         }
 
@@ -30,7 +33,7 @@ class AbstractDocument : public QObject {
         }
 
         if (newFile.exists()) {
-            qWarning() << "Deleting the already existing" << newFile;
+            logWarning() << "Deleting the already existing file " << VIVY_LOG_QUOTED(newFile);
             if (!dirOp.remove(newFile.absoluteFilePath()))
                 throw std::runtime_error("Failed to remove " +
                                          newFile.absoluteFilePath().toStdString());
diff --git a/src/Lib/AbstractMediaContext.hh b/src/Lib/AbstractMediaContext.hh
index f4a09ed6c040a96dcbea04d0b71fe2491430f727..a15609de50345b89f238deae99cbb8722de14456 100644
--- a/src/Lib/AbstractMediaContext.hh
+++ b/src/Lib/AbstractMediaContext.hh
@@ -10,10 +10,11 @@ extern "C" {
 #include <libavformat/avformat.h>
 #include <libswresample/swresample.h>
 #include <libavcodec/avfft.h>
-#include <memory.h>
 }
 
+#include "../VivyApplication.hh"
 #include "Utils.hh"
+#include "Log.hh"
 
 namespace Vivy
 {
@@ -53,6 +54,7 @@ public:
     static inline constexpr AVMediaType avMediaType = static_cast<AVMediaType>(AVMEDIA_TYPE);
 
 protected:
+    VIVY_APP_LOGGABLE_OBJECT(AbstractMediaStream, logger)
     using Super = AbstractMediaStream<AVMEDIA_TYPE>;
 
 protected:
@@ -78,10 +80,10 @@ protected:
         if (avcodec_open2(codecContext.get(), codec, nullptr) < 0)
             throw std::runtime_error("failed to open audio decoder for a stream");
 
-        qDebug() << "[Stream] Codec" << codec->name << "id:" << codecId;
-        qDebug() << "[Stream] sample rate:" << codecParams->sample_rate;
-        qDebug() << "[Stream] bit rate:   " << codecParams->bit_rate;
-        qDebug() << "[Stream] channels:   " << codecParams->channels;
+        VIVY_LOG_CTOR() << "Codec: " << VIVY_LOG_QUOTED(codec->name) << ", id: " << codecId;
+        VIVY_LOG_CTOR() << "Sample rate: " << codecParams->sample_rate;
+        VIVY_LOG_CTOR() << "Bit rate: " << codecParams->bit_rate;
+        VIVY_LOG_CTOR() << "Channels: " << codecParams->channels;
     }
 
 public:
@@ -121,6 +123,7 @@ public:
     using StreamWeakPtr                             = std::weak_ptr<Stream>;
 
 protected:
+    VIVY_APP_LOGGABLE_OBJECT(AbstractMediaContext, logger)
     using Super = AbstractMediaContext<Stream>;
 
 public:
@@ -160,10 +163,10 @@ public:
                                                  -1, // We don't want related streams
                                                  nullptr, 0);
         if (defaultStreamIndex < 0)
-            qCritical() << "Could not find the best stream";
+            logError() << "Could not find the best stream";
 
-        qDebug() << "Opened context for" << path << "with duration" << formatPtr->duration
-                 << "and default stream index" << defaultStreamIndex;
+        logDebug() << "Opened context for " << VIVY_LOG_QUOTED(path) << " with duration "
+                   << formatPtr->duration << " and default stream index " << defaultStreamIndex;
     }
 
     virtual ~AbstractMediaContext() {}
diff --git a/src/Lib/Audio.cc b/src/Lib/Audio.cc
index 218763c297441fe96745decac1d076922f209f15..fdf79c0fc29e9d58165d701c452447412f6b9655 100644
--- a/src/Lib/Audio.cc
+++ b/src/Lib/Audio.cc
@@ -46,10 +46,10 @@ AudioStream::AudioStream(AVCodec *streamCodec, AVFormatContext *formatPtr, AVStr
 AudioStream::~AudioStream() noexcept
 {
     if (dataPtr) {
-        qDebug() << "Free data ptr";
+        VIVY_LOG_DTOR() << "Free data ptr for audio stream";
         free(dataPtr);
     }
-    qDebug() << "Delete stream object";
+    VIVY_LOG_DTOR() << "Delete audio stream object";
 }
 
 QJsonObject
@@ -68,7 +68,7 @@ AudioStream::decodeData()
 {
     if (isDecoded())
         throw std::logic_error("audio stream is already resampled");
-    qDebug() << "Launch decoding of stream" << streamIndexInContext;
+    logDebug() << "Launch decoding of stream " << streamIndexInContext;
 
     AVPacket packet;
     av_init_packet(&packet);
@@ -137,8 +137,8 @@ AudioStream::decodeData()
         av_packet_unref(&packet);
     }
 
-    qDebug() << "Decoding data finished for stream" << streamIndexInContext
-             << "dataPtr =" << dataPtr << "with dataSize =" << dataSize;
+    logDebug() << "Decoding data finished for stream " << streamIndexInContext << " with dataPtr "
+               << dataPtr << " and dataSize " << dataSize;
 }
 
 // Delete decoded data, clean up thing
diff --git a/src/Lib/CRTPStore.hh b/src/Lib/CRTPStore.hh
index 8324d9c606635812731708f754c7997bbe6c49e2..2aa6da2c7bcb34ae8ed039058049d944b82bf4cf 100644
--- a/src/Lib/CRTPStore.hh
+++ b/src/Lib/CRTPStore.hh
@@ -4,6 +4,8 @@
 #error "This is a C++ header"
 #endif
 
+#include "../VivyApplication.hh"
+#include "Log.hh"
 #include "Utils.hh"
 #include "Uuid.hh"
 
@@ -21,6 +23,8 @@ template <class Store, class Document> class CRTPStore {
     VIVY_UNMOVABLE_OBJECT(CRTPStore)
 
 protected:
+    VIVY_APP_LOGGABLE_OBJECT(CRTPStore, logger)
+
     std::map<Uuid, std::shared_ptr<Document>> documents{};
     uint newDocumentNumber{ 1 };
     static inline const QString newDocumentBaseName = QStringLiteral("Untitled ");
@@ -56,7 +60,7 @@ public:
         auto *self = static_cast<Store *>(this);
 
         if (!self->documents.contains(uuid)) {
-            qCritical() << "Couldn't find the document " << uuid;
+            logError() << "Couldn't find the document " << uuid;
             throw std::runtime_error("Can't find the document");
         }
 
diff --git a/src/Lib/Log.cc b/src/Lib/Log.cc
index f26e77b3b7a89aa6221d0abebccfd3ab5200d7ff..b8d71f458293634242f1b18111e8a11c19ae7731 100644
--- a/src/Lib/Log.cc
+++ b/src/Lib/Log.cc
@@ -150,6 +150,36 @@ LogMessage::operator<<(const QString &msg) noexcept
     return (*this << msg.toStdString());
 }
 
+LogMessage &
+LogMessage::operator<<(const QFileInfo &fileInfo) noexcept
+{
+    return (*this << "QFileInfo{ " << fileInfo.absoluteFilePath() << "}");
+}
+
+LogMessage &
+LogMessage::operator<<(const double *ptr) noexcept
+{
+    return (*this << "Pointer{ double, " << pointerToString<double>(ptr) << " }");
+}
+
+LogMessage &
+LogMessage::operator<<(const unsigned char c) noexcept
+{
+    return (*this << static_cast<char>(c));
+}
+
+LogMessage &
+LogMessage::operator<<(const unsigned int i) noexcept
+{
+    return (*this << static_cast<unsigned long>(i));
+}
+
+LogMessage &
+LogMessage::operator<<(const unsigned long i) noexcept
+{
+    return (*this << std::to_string(i));
+}
+
 LogMessage &
 LogMessage::operator<<(const int i) noexcept
 {
diff --git a/src/Lib/Log.hh b/src/Lib/Log.hh
index 042df469398b7940ee8524bcf23449d98b7fc1f1..b559571d699ec8d1b8620f3c02fb8f5a66f01156 100644
--- a/src/Lib/Log.hh
+++ b/src/Lib/Log.hh
@@ -169,6 +169,14 @@ private:
     std::size_t indexInArray{ 0 };
     const Logger *parentLogger{ nullptr };
 
+    static std::string pointerToString(const auto *ptr) noexcept
+    {
+        std::stringstream stream;
+        stream << "0x" << std::setfill('0') << std::setw(sizeof(std::intptr_t) * 2) << std::hex
+               << reinterpret_cast<const std::intptr_t>(ptr);
+        return stream.str();
+    }
+
 public:
     VIVY_DISABLE_COPY_CTOR(LogMessage)
     VIVY_DISABLE_ASSIGN_OPERATORS(LogMessage)
@@ -186,10 +194,15 @@ public:
     LogMessage &operator<<(const std::string &) noexcept;
     LogMessage &operator<<(const std::string_view) noexcept;
     LogMessage &operator<<(const QString &) noexcept;
+    LogMessage &operator<<(const QFileInfo &) noexcept;
     LogMessage &operator<<(const char *) noexcept;
+    LogMessage &operator<<(const double *) noexcept;
     LogMessage &operator<<(const char) noexcept;
     LogMessage &operator<<(const int) noexcept;
     LogMessage &operator<<(const long) noexcept;
+    LogMessage &operator<<(const unsigned char) noexcept;
+    LogMessage &operator<<(const unsigned int) noexcept;
+    LogMessage &operator<<(const unsigned long) noexcept;
 };
 
 // A logger class, a client to LogSink. Will generate and send instances of
diff --git a/src/UI/MainWindow.cc b/src/UI/MainWindow.cc
index d6384702e0df03497d5ad7b27faf858484d6fac6..0130076f5a9ea93237f18d6aa2273ae8310cca3c 100644
--- a/src/UI/MainWindow.cc
+++ b/src/UI/MainWindow.cc
@@ -1,3 +1,5 @@
+#include "../Lib/Document/VivyDocumentStore.hh"
+#include "../Lib/Script/ScriptStore.hh"
 #include "../Lib/Utils.hh"
 #include "../VivyApplication.hh"
 #include "MainWindow.hh"
@@ -312,7 +314,7 @@ MainWindow::newDocument() noexcept
 {
     try {
         addTab(new VivyDocumentView(
-            vivyApp->documentStore.newDocument(VivyDocument::UntouchedByDefault), documents));
+            vivyApp->documentStore->newDocument(VivyDocument::UntouchedByDefault), documents));
     } catch (const std::runtime_error &e) {
         logError() << "Failed to create a new empty document: " << e.what();
     }
@@ -339,11 +341,11 @@ MainWindow::openDocument() noexcept
     // Handle the different types here
     try {
         if (fileType == Utils::DocumentType::Vivy)
-            addTab(new VivyDocumentView(vivyApp->documentStore.loadDocument(filename), documents));
+            addTab(new VivyDocumentView(vivyApp->documentStore->loadDocument(filename), documents));
 
         else if (fileType == Utils::DocumentType::VivyScript) {
-            auto scriptDocument = vivyApp->scriptStore.loadDocument(filename);
-            auto errorTuple     = vivyApp->scriptStore.executeScript(scriptDocument->getUuid());
+            auto scriptDocument = vivyApp->scriptStore->loadDocument(filename);
+            auto errorTuple     = vivyApp->scriptStore->executeScript(scriptDocument->getUuid());
             ScriptDocumentView *newView = new ScriptDocumentView(scriptDocument, documents);
 
             if (errorTuple.has_value()) {
diff --git a/src/UI/VivyDocumentView.cc b/src/UI/VivyDocumentView.cc
index fff3ef46225305cdf16bab667c781fcced9f2703..86e155afd60eac27964e0f270e8dba6f6d8ff4f8 100644
--- a/src/UI/VivyDocumentView.cc
+++ b/src/UI/VivyDocumentView.cc
@@ -6,6 +6,7 @@
 #include "DocumentViews/AssLinesModel.hh"
 #include "../VivyApplication.hh"
 #include "../Lib/Document/VivyDocument.hh"
+#include "../Lib/Document/VivyDocumentStore.hh"
 
 using namespace Vivy;
 
@@ -149,7 +150,7 @@ void
 VivyDocumentView::closeDocument() noexcept
 {
     logDebug() << "Closing document " << document->getUuid();
-    vivyApp->documentStore.closeDocument(document->getUuid());
+    vivyApp->documentStore->closeDocument(document->getUuid());
     allowToCloseAllDocks();
 }
 
diff --git a/src/VivyApplication.hh b/src/VivyApplication.hh
index 85e715d85209eb49388a21ec2aa102a3bcf56288..4a9985a35c48c5ed41d87f2dc2087f74f5ef7840 100644
--- a/src/VivyApplication.hh
+++ b/src/VivyApplication.hh
@@ -29,13 +29,14 @@
 #define VIVY_MACOS
 #endif
 
-#include "Lib/Script/ScriptStore.hh"
-#include "Lib/Document/VivyDocumentStore.hh"
 #include "Lib/Log.hh"
 
 namespace Vivy
 {
 class MainWindow;
+class ScriptStore;
+class VivyDocumentStore;
+class AbstractDocument;
 
 // Vivy application class
 class VivyApplication : public QApplication {
@@ -45,8 +46,8 @@ class VivyApplication : public QApplication {
     VIVY_LOGGABLE_OBJECT(logSink, APPLICATION, logger)
 
 public:
-    VivyDocumentStore documentStore{};
-    ScriptStore scriptStore{};
+    std::shared_ptr<VivyDocumentStore> documentStore{};
+    std::shared_ptr<ScriptStore> scriptStore{};
 
     enum class Font {
         Monospace,