diff --git a/Modules/Core/Common/include/otbLogger.h b/Modules/Core/Common/include/otbLogger.h
index ef420c7b2389a38af6be6d1f7cf19faaa4b7f1b5..0da8d382194a6815c31c19ccc21a3856a10fd383 100644
--- a/Modules/Core/Common/include/otbLogger.h
+++ b/Modules/Core/Common/include/otbLogger.h
@@ -59,8 +59,15 @@ public:
   // Overwrite this to provide custom formatting of log entries
   std::string BuildFormattedEntry(itk::Logger::PriorityLevelType, std::string const&) override;
 
+  /** Output logs about the RAM, caching and multi-threading settings */
   void LogSetupInformation();
-  
+
+  /** Return true if the LogSetupInformation has already been called*/
+  bool IsLogSetupInformationDone();
+
+  /** Set the flag m_LogSetupInfoDone to true */
+  void LogSetupInformationDone();
+
 protected:
   Logger();
   virtual ~Logger() ITK_OVERRIDE;
@@ -71,6 +78,8 @@ private:
 
   static Pointer CreateInstance();
 
+  bool m_LogSetupInfoDone;
+
 }; // class Logger
 
 } // namespace otb
diff --git a/Modules/Core/Common/src/otbLogger.cxx b/Modules/Core/Common/src/otbLogger.cxx
index b3730cf445a5816ca693da32de7d2a71f3aaba37..6678aa16320e4498b1a93310abbf346479467795 100644
--- a/Modules/Core/Common/src/otbLogger.cxx
+++ b/Modules/Core/Common/src/otbLogger.cxx
@@ -38,9 +38,6 @@ Logger::Pointer Logger::CreateInstance()
   defaultOutput->SetStream(std::cout);
   
   instance->AddLogOutput(defaultOutput);
-  
-  // Log setup information
-  instance->LogSetupInformation();
 
   return instance;
 }
@@ -61,6 +58,8 @@ Logger::Logger()
 
   this->SetTimeStampFormat(itk::LoggerBase::HUMANREADABLE);
   this->SetHumanReadableFormat("%Y-%m-%d %H:%M:%S");
+
+  m_LogSetupInfoDone = false;
 }
 
 Logger::~Logger()
@@ -69,22 +68,29 @@ Logger::~Logger()
 
 void Logger::LogSetupInformation()
 {
-  std::ostringstream oss;
-  
-  oss<<"Default RAM limit for OTB is "<<otb::ConfigurationManager::GetMaxRAMHint()<<" MB"<<std::endl;
-  this->Info(oss.str());
-  oss.str("");
-  oss.clear();
-
-  oss<<"GDAL maximum cache size is "<<GDALGetCacheMax64()/(1024*1024)<<" MB"<<std::endl;
-  this->Info(oss.str());
-  oss.str("");
-  oss.clear();
-
-  oss<<"OTB will use at most "<<itk::MultiThreader::GetGlobalDefaultNumberOfThreads()<<" threads"<<std::endl;
-  this->Info(oss.str());
-  oss.str("");
-  oss.clear();
+  if (! IsLogSetupInformationDone())
+    {
+    std::ostringstream oss;
+
+    oss<<"Default RAM limit for OTB is "<<otb::ConfigurationManager::GetMaxRAMHint()<<" MB"<<std::endl;
+    this->Info(oss.str());
+    oss.str("");
+    oss.clear();
+
+    oss<<"GDAL maximum cache size is "<<GDALGetCacheMax64()/(1024*1024)<<" MB"<<std::endl;
+    this->Info(oss.str());
+    oss.str("");
+    oss.clear();
+
+    oss<<"OTB will use at most "<<itk::MultiThreader::GetGlobalDefaultNumberOfThreads()<<" threads"<<std::endl;
+    this->Info(oss.str());
+    oss.str("");
+    oss.clear();
+
+    // only switch the flag for the singleton, so that other instances can call
+    // LogSetupInformation() several times
+    Instance()->LogSetupInformationDone();
+    }
 }
 
 std::string Logger::BuildFormattedEntry(itk::Logger::PriorityLevelType level, std::string const & content)
@@ -116,4 +122,14 @@ std::string Logger::BuildFormattedEntry(itk::Logger::PriorityLevelType level, st
   return s.str();
 }
 
+bool Logger::IsLogSetupInformationDone()
+{
+  return m_LogSetupInfoDone;
+}
+
+void Logger::LogSetupInformationDone()
+{
+  m_LogSetupInfoDone = true;
+}
+
 } // namespace otb
diff --git a/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx b/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx
index ec0ae5ae6d760b11ca6238deb582174752bb7f21..7336993ed392de64e980c05a7178fdc4cbe66ca7 100644
--- a/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx
+++ b/Modules/Core/Streaming/include/otbStreamingImageVirtualWriter.txx
@@ -183,6 +183,8 @@ void
 StreamingImageVirtualWriter<TInputImage>
 ::GenerateData(void)
 {
+  otb::Logger::Instance()->LogSetupInformation();
+
   /**
    * Prepare all the outputs. This may deallocate previous bulk data.
    */
diff --git a/Modules/Core/Streaming/include/otbStreamingManager.txx b/Modules/Core/Streaming/include/otbStreamingManager.txx
index 24e487a4e55998ee7d28b1be1a58cbda21ee8768..9d2f3ddbd8243ed40946058cafe96d6060d2926d 100644
--- a/Modules/Core/Streaming/include/otbStreamingManager.txx
+++ b/Modules/Core/Streaming/include/otbStreamingManager.txx
@@ -156,7 +156,7 @@ StreamingManager<TImage>::EstimateOptimalNumberOfDivisions(itk::DataObject * inp
   unsigned int optimalNumberOfDivisions =
       otb::PipelineMemoryPrintCalculator::EstimateOptimalNumberOfStreamDivisions(pipelineMemoryPrint, availableRAMInBytes);
 
-  otbLogMacro(Info,<<"Estimated memory for full processing: "<<pipelineMemoryPrint * otb::PipelineMemoryPrintCalculator::ByteToMegabyte<<"MB (avail.: "<<availableRAMInBytes * otb::PipelineMemoryPrintCalculator::ByteToMegabyte<<" NB), optimal image partitioning: "<<optimalNumberOfDivisions<<" blocks");
+  otbLogMacro(Info,<<"Estimated memory for full processing: "<<pipelineMemoryPrint * otb::PipelineMemoryPrintCalculator::ByteToMegabyte<<"MB (avail.: "<<availableRAMInBytes * otb::PipelineMemoryPrintCalculator::ByteToMegabyte<<" MB), optimal image partitioning: "<<optimalNumberOfDivisions<<" blocks");
   
   return optimalNumberOfDivisions;
 }
diff --git a/Modules/IO/ImageIO/include/otbImageFileWriter.txx b/Modules/IO/ImageIO/include/otbImageFileWriter.txx
index 6cfff64f8ae1df38f26344110537bb1c47d0336c..f61c624d02470aa03296ffd03499c85a6c2749e1 100644
--- a/Modules/IO/ImageIO/include/otbImageFileWriter.txx
+++ b/Modules/IO/ImageIO/include/otbImageFileWriter.txx
@@ -279,6 +279,8 @@ ImageFileWriter<TInputImage>
     itkExceptionMacro(<< "No input to writer");
     }
 
+  otb::Logger::Instance()->LogSetupInformation();
+
   /** Parse streaming modes */
   if(m_FilenameHelper->StreamingTypeIsSet())
     {
diff --git a/Modules/IO/TestKernel/include/otbTestMain.h b/Modules/IO/TestKernel/include/otbTestMain.h
index ccb70a639cc5ec5a295d775affc2d5a510747c7d..7a833306b5ecfd8e6b434488a0932f3fdc2a5933 100644
--- a/Modules/IO/TestKernel/include/otbTestMain.h
+++ b/Modules/IO/TestKernel/include/otbTestMain.h
@@ -28,7 +28,7 @@
 #include <iostream>
 
 #include "itkMultiThreader.h"
-#include "itkMacro.h"
+#include "otbMacro.h"
 
 #include "otbOGRDriversInit.h"
 #include "otbTestHelper.h"
@@ -298,6 +298,7 @@ int main(int ac, char* av[])
       }
   else
     {
+    otb::Logger::Instance()->LogSetupInformation();
     MainFuncPointer f = j->second;
     int             result;
     try
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
index 31f46f3a019e6fe335ebcae5535b4b6284bc2f4a..a6843b1422a18ec54fe357a45bbaa8323d36203f 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplication.cxx
@@ -645,6 +645,8 @@ int Application::ExecuteAndWriteOutput()
 {
   m_Chrono.Restart();
 
+  m_Logger->LogSetupInformation();
+
   int status = this->Execute();
 
   if (status == 0)