diff --git a/include/aidge/data/Data.hpp b/include/aidge/data/Data.hpp
index d8412dbd4ddb4ec371649d180bce10a80dd624f3..47ce3514dae9b3b9dc061cc5e0d9dc7d5f440d0b 100644
--- a/include/aidge/data/Data.hpp
+++ b/include/aidge/data/Data.hpp
@@ -52,6 +52,7 @@ public:
         return mType;
     }
     virtual ~Data() = default;
+    virtual std::string toString() const;
 
 private:
     const std::string mType;
@@ -84,4 +85,4 @@ namespace Aidge {
 inline auto format_as(DataType dt) { return EnumStrings<Aidge::DataType>::data[static_cast<int>(dt)]; }
 }
 
-#endif /* AIDGE_DATA_H_ */
\ No newline at end of file
+#endif /* AIDGE_DATA_H_ */
diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp
index b82ec89d0096d47644e1bb4bd3819536ce7ccd66..1f9c5a5ec14cca4469b0329f2f968cf9dbc7b0de 100644
--- a/include/aidge/data/Tensor.hpp
+++ b/include/aidge/data/Tensor.hpp
@@ -445,7 +445,7 @@ public:
         set<expectedType>(getStorageIdx(coordIdx), value);
     }
 
-    std::string toString() const;
+    std::string toString() const override;
 
     inline void print() const { fmt::print("{}\n", toString()); }
 
diff --git a/include/aidge/graph/GraphView.hpp b/include/aidge/graph/GraphView.hpp
index 46fa56ef0e7d63ce10bb3c96a8d7e1c42b191322..0c6b7f03326491711fd57ed939642d1eec80b0d8 100644
--- a/include/aidge/graph/GraphView.hpp
+++ b/include/aidge/graph/GraphView.hpp
@@ -98,6 +98,8 @@ public:
      */
     void save(const std::string& path, bool verbose = false, bool showProducers = true) const;
 
+    void logOutputs(const std::string& dirName) const;
+
     /**
      * Check that a node is in the current GraphView.
      * @param nodePtr Node to check
@@ -283,7 +285,7 @@ public:
      *   added to the list, and so on.
      * - Any remaining nodes have no path to the root node and are added in
      *   arbitrary order. In this case, the ranking is not garanteed to be unique.
-     * 
+     *
      * If the ranking cannot be garanteed to be unique, the second item indicates
      * the rank from which unicity cannot be garanteed.
      * @return std::pair<std::vector<NodePtr>, size_t> Pair with the list of ranked
diff --git a/include/aidge/utils/Directories.hpp b/include/aidge/utils/Directories.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3bc07b9dd58e472096102c1b0c66971164d632a3
--- /dev/null
+++ b/include/aidge/utils/Directories.hpp
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2023 CEA-List
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+
+#ifndef AIDGE_DIRECTORIES_H_
+#define AIDGE_DIRECTORIES_H_
+
+
+#include <string>  // std::string
+#include <sstream> // std::stringstream
+#include <iostream>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef WIN32
+#include <direct.h>
+#else
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace Aidge {
+
+    bool isNotValidFilePath(int c) {
+        return (iscntrl(c)
+            || c == '<'
+            || c == '>'
+            || c == ':'
+            || c == '"'
+            || c == '|'
+            || c == '?'
+            || c == '*');
+    }
+
+    std::string filePath(const std::string& str) {
+        std::string filePath(str);
+        std::replace_if(filePath.begin(), filePath.end(),
+                        isNotValidFilePath, '_');
+        return filePath;
+    }
+
+
+    bool createDirectories(const std::string& dirName)
+    {
+        std::stringstream path(dirName);
+        std::string dir;
+        std::string pathToDir("");
+        int status = 0;
+
+        while (std::getline(path, dir, '/') && status == 0) {
+            pathToDir += dir + '/';
+            struct stat fileStat;
+            if (stat(pathToDir.c_str(), &fileStat) != 0) {
+                // Directory does not exist
+    #ifdef WIN32
+                status = _mkdir(pathToDir.c_str());
+    #else
+    #if defined(S_IRWXU)
+                status = mkdir(pathToDir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
+    #else
+                status = mkdir(pathToDir.c_str());
+    #endif
+    #endif
+            } else if (!S_ISDIR(fileStat.st_mode)) {
+                status = -1;
+            }
+        }
+        return (status == 0 || errno == EEXIST);
+    }
+
+
+}
+
+#endif //AIDGE_DIRECTORIES_H_
+
diff --git a/python_binding/data/pybind_Data.cpp b/python_binding/data/pybind_Data.cpp
index df3792fd784a2ef2b9418628959629ac59c04094..724b10f874beed608bf885baccaf74ea7a89fd68 100644
--- a/python_binding/data/pybind_Data.cpp
+++ b/python_binding/data/pybind_Data.cpp
@@ -26,12 +26,12 @@ void init_Data(py::module& m){
     .value("Int64", DataType::Int64)
     .value("UInt8", DataType::UInt8)
     .value("UInt32", DataType::UInt32)
-    .value("UInt64", DataType::UInt64)   
+    .value("UInt64", DataType::UInt64)
     ;
 
     py::class_<Data, std::shared_ptr<Data>>(m,"Data")
     .def(py::init<const std::string&>());
 
-    
+
 }
 }
diff --git a/python_binding/graph/pybind_GraphView.cpp b/python_binding/graph/pybind_GraphView.cpp
index a41d0d92835be2b5ef07d30c4a5233da1e3906b7..eae05d8e2c04a877e5942600d7120024f20c4788 100644
--- a/python_binding/graph/pybind_GraphView.cpp
+++ b/python_binding/graph/pybind_GraphView.cpp
@@ -30,7 +30,7 @@ void init_GraphView(py::module& m) {
           :param path: save location
           :type path: str
           )mydelimiter")
-
+          .def("log_outputs", &GraphView::logOutputs, py::arg("path"))
           .def("get_output_nodes", &GraphView::outputNodes,
           R"mydelimiter(
           Get set of output Nodes.
diff --git a/src/graph/GraphView.cpp b/src/graph/GraphView.cpp
index 005a7e679da5941d0995204b6c2a28a01ce376b4..edcea9544037634aede8102dadffdf1c75dd2427 100644
--- a/src/graph/GraphView.cpp
+++ b/src/graph/GraphView.cpp
@@ -26,6 +26,7 @@
 #include "aidge/operator/GenericOperator.hpp"
 #include "aidge/operator/MetaOperator.hpp"
 #include "aidge/utils/ErrorHandling.hpp"
+#include "aidge/utils/Directories.hpp"
 
 ///////////////////////////////////////////////////////
 //        FUNCTIONAL DESCRIPTION
@@ -193,6 +194,29 @@ void Aidge::GraphView::save(const std::string& path, bool verbose, bool showProd
     fmt::print(fp.get(), "\n");
 }
 
+void Aidge::GraphView::logOutputs(const std::string& dirName) const {
+  if (!Aidge::createDirectories(dirName)){
+    AIDGE_THROW_OR_ABORT(std::runtime_error, "Failed to create directory: {}.", dirName);
+  }
+  for (std::shared_ptr<Node> nodePtr : getNodes()) {
+
+    const std::string& nodePath = dirName + "/" + Aidge::filePath(nodePtr->name()) +"/";
+    if (!Aidge::createDirectories(nodePath)){
+      AIDGE_THROW_OR_ABORT(std::runtime_error, "Failed to create directory: {}.", nodePath);
+    }
+
+    for (IOIndex_t outIdx = 0; outIdx < nodePtr->nbOutputs(); ++outIdx) {
+      const std::string& inputPath = nodePath +"output_" + std::to_string(outIdx) + ".log";
+      auto fp = std::unique_ptr<FILE, decltype(&std::fclose)>(std::fopen(inputPath.c_str(), "w"), &std::fclose);
+      if (!fp) {
+        AIDGE_THROW_OR_ABORT(std::runtime_error,
+            "Could not create graph view log file: {}", inputPath);
+      }
+      fmt::print(fp.get(), "{}\n", nodePtr->getOperator()->getRawOutput(outIdx)->toString().c_str());
+    }
+  }
+}
+
 void Aidge::GraphView::setRootNode(NodePtr node) {
   AIDGE_ASSERT(mNodes.find(node) != mNodes.end(), "Root node is not in the GraphView!");
   mRootNode = node;
@@ -356,7 +380,7 @@ void Aidge::GraphView::forwardDims(const std::vector<std::vector<Aidge::DimSize_
                 }
             } else {
                 AIDGE_ASSERT(nodePtr->getOperator()->getRawInput(i)
-                    && !std::static_pointer_cast<Tensor>(nodePtr->getOperator()->getRawInput(i))->empty(), 
+                    && !std::static_pointer_cast<Tensor>(nodePtr->getOperator()->getRawInput(i))->empty(),
                   "Missing input#{} for node {} ({})", i, nodePtr->name(), nodePtr->type());
             }