diff --git a/CHANGELOG.md b/CHANGELOG.md
index e54515676..b09c60abb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -73,6 +73,7 @@
     Feature #390: 3rd person look "over the shoulder"
     Feature #2386: Distant Statics in the form of Object Paging
     Feature #2404: Levelled List can not be placed into a container
+    Feature #2686: Timestamps in openmw.log
     Feature #4894: Consider actors as obstacles for pathfinding
     Feature #5043: Head Bobbing
     Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp
index aca050592..89aa2b9fd 100644
--- a/apps/openmw/main.cpp
+++ b/apps/openmw/main.cpp
@@ -135,7 +135,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
 
     if (variables.count ("help"))
     {
-        std::cout << desc << std::endl;
+        getRawStdout() << desc << std::endl;
         return false;
     }
 
@@ -144,7 +144,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
         cfgMgr.readConfiguration(variables, desc, true);
 
         Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapePath>().mPath.string());
-        std::cout << v.describe() << std::endl;
+        getRawStdout() << v.describe() << std::endl;
         return false;
     }
 
diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp
index 88219dcbe..987a3db7e 100644
--- a/components/debug/debugging.cpp
+++ b/components/debug/debugging.cpp
@@ -1,6 +1,7 @@
 #include "debugging.hpp"
 
 #include <chrono>
+#include <memory>
 
 #include <components/crashcatcher/crashcatcher.hpp>
 
@@ -133,11 +134,19 @@ namespace Debug
     }
 }
 
+static std::unique_ptr<std::ostream> rawStdout = nullptr;
+
+std::ostream& getRawStdout()
+{
+    return rawStdout ? *rawStdout : std::cout;
+}
+
 int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, char *argv[], const std::string& appName)
 {
 #if defined _WIN32
     (void)Debug::attachParentConsole();
 #endif
+    rawStdout = std::make_unique<std::ostream>(std::cout.rdbuf());
 
     // Some objects used to redirect cout and cerr
     // Scope must be here, so this still works inside the catch block for logging exceptions
diff --git a/components/debug/debugging.hpp b/components/debug/debugging.hpp
index 39390446f..d8849cd89 100644
--- a/components/debug/debugging.hpp
+++ b/components/debug/debugging.hpp
@@ -135,6 +135,9 @@ namespace Debug
 #endif
 }
 
+// Can be used to print messages without timestamps
+std::ostream& getRawStdout();
+
 int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, char *argv[], const std::string& appName);
 
 #endif