diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+# Changelog for sandwich
+
+## Unreleased changes
diff --git a/ChangeLog.md b/ChangeLog.md
deleted file mode 100644
--- a/ChangeLog.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Changelog for sandwich
-
-## Unreleased changes
diff --git a/sandwich.cabal b/sandwich.cabal
--- a/sandwich.cabal
+++ b/sandwich.cabal
@@ -4,12 +4,12 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 051e0a3136fc22e2cf0e40f976c23333d46c6cf3010c98662c72c14ded3bf8ab
+-- hash: dafc0d430b62985e6470bd64597adb7947665b8d43fc94fc965d785b8d6d64bf
 
 name:           sandwich
-version:        0.1.0.2
+version:        0.1.0.3
 synopsis:       Yet another test framework for Haskell
-description:    Please see the README on GitHub at <https://github.com/githubuser/sandwich#readme>
+description:    Please see the <https://codedownio.github.io/sandwich documentation>.
 category:       Testing
 homepage:       https://codedownio.github.io/sandwich
 bug-reports:    https://github.com/codedownio/sandwich/issues
@@ -21,7 +21,7 @@
 build-type:     Simple
 extra-source-files:
     README.md
-    ChangeLog.md
+    CHANGELOG.md
 
 source-repository head
   type: git
@@ -94,7 +94,7 @@
       aeson
     , ansi-terminal
     , async
-    , base <=4.14
+    , base <4.15
     , brick
     , bytestring
     , colour
@@ -140,7 +140,7 @@
       aeson
     , ansi-terminal
     , async
-    , base <=4.14
+    , base <4.15
     , brick
     , bytestring
     , colour
@@ -187,7 +187,7 @@
       aeson
     , ansi-terminal
     , async
-    , base <=4.14
+    , base <4.15
     , brick
     , bytestring
     , colour
@@ -239,7 +239,7 @@
       aeson
     , ansi-terminal
     , async
-    , base <=4.14
+    , base <4.15
     , brick
     , bytestring
     , colour
@@ -292,7 +292,7 @@
       aeson
     , ansi-terminal
     , async
-    , base <=4.14
+    , base <4.15
     , brick
     , bytestring
     , colour
diff --git a/src/Test/Sandwich/Formatters/TerminalUI.hs b/src/Test/Sandwich/Formatters/TerminalUI.hs
--- a/src/Test/Sandwich/Formatters/TerminalUI.hs
+++ b/src/Test/Sandwich/Formatters/TerminalUI.hs
@@ -108,7 +108,7 @@
       writeTVar currentFixedTree newFixed
       return newFixed
     writeBChan eventChan (RunTreeUpdated newFixedTree)
-    threadDelay 100000 -- Sleep 100ms
+    threadDelay terminalUIRefreshPeriod
 
   let buildVty = do
         v <- V.mkVty V.defaultConfig
diff --git a/src/Test/Sandwich/Formatters/TerminalUI/Types.hs b/src/Test/Sandwich/Formatters/TerminalUI/Types.hs
--- a/src/Test/Sandwich/Formatters/TerminalUI/Types.hs
+++ b/src/Test/Sandwich/Formatters/TerminalUI/Types.hs
@@ -31,6 +31,8 @@
   -- ^ Whether to show or hide visibility thresholds next to nodes.
   , terminalUILogLevel :: Maybe LogLevel
   -- ^ Log level for test log displays.
+  , terminalUIRefreshPeriod :: Int
+  -- ^ Time in microseconds between UI refreshes. Defaults to 100ms. Can be increased if CPU usage of the UI is too high.
   , terminalUIDefaultEditor :: Maybe String
   -- ^ Default value to use for the EDITOR environment variable when one is not provided.
   -- If 'Nothing' and EDITOR can't be found, edit commands will do nothing.
@@ -62,6 +64,7 @@
   , terminalUIShowFileLocations = False
   , terminalUIShowVisibilityThresholds = False
   , terminalUILogLevel = Just LevelWarn
+  , terminalUIRefreshPeriod = 100000
   , terminalUIDefaultEditor = Just "emacsclient +LINE:COLUMN --no-wait"
   , terminalUIOpenInEditor = autoOpenInEditor
   }
diff --git a/src/Test/Sandwich/Interpreters/RunTree/Logging.hs b/src/Test/Sandwich/Interpreters/RunTree/Logging.hs
--- a/src/Test/Sandwich/Interpreters/RunTree/Logging.hs
+++ b/src/Test/Sandwich/Interpreters/RunTree/Logging.hs
@@ -1,4 +1,3 @@
--- |
 
 module Test.Sandwich.Interpreters.RunTree.Logging (
   logToMemory
diff --git a/src/Test/Sandwich/Types/RunTree.hs b/src/Test/Sandwich/Types/RunTree.hs
--- a/src/Test/Sandwich/Types/RunTree.hs
+++ b/src/Test/Sandwich/Types/RunTree.hs
@@ -6,6 +6,7 @@
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 module Test.Sandwich.Types.RunTree where
 
@@ -19,7 +20,7 @@
 import Data.Sequence hiding ((:>))
 import qualified Data.Set as S
 import qualified Data.Text as T
-import Data.Time.Clock
+import Data.Time
 import Data.Typeable
 import GHC.Stack
 import Test.Sandwich.Types.ArgParsing
@@ -208,8 +209,34 @@
 type LogFn = Loc -> LogSource -> LogLevel -> LogStr -> IO ()
 type LogEntryFormatter = UTCTime -> Loc -> LogSource -> LogLevel -> LogStr -> BS8.ByteString
 
+-- The defaultLogStr formatter weirdly puts information after the message. Use our own
 defaultLogEntryFormatter :: LogEntryFormatter
-defaultLogEntryFormatter _ts a b c d = fromLogStr $ defaultLogStr a b c d
+defaultLogEntryFormatter ts loc src level msg = fromLogStr $
+  toLogStr (BS8.pack $ formatTime defaultTimeLocale "%F %X%4Q %Z" ts)
+  <> " ["
+  <> defaultLogLevelStr level
+  <> "] ("
+  <> toLogStr src
+  <> ") "
+  <> (if isDefaultLoc loc then "" else "@(" <> toLogStr (BS8.pack $ fileLocStr loc) <> ") ")
+  <> msg
+  <> "\n"
+
+  where
+    defaultLogLevelStr :: LogLevel -> LogStr
+    defaultLogLevelStr level = case level of
+      LevelOther t -> toLogStr t
+      _ -> toLogStr $ BS8.pack $ Prelude.drop 5 $ show level
+
+    isDefaultLoc :: Loc -> Bool
+    isDefaultLoc (Loc "<unknown>" "<unknown>" "<unknown>" (0,0) (0,0)) = True
+    isDefaultLoc _ = False
+
+    fileLocStr loc = (loc_package loc) ++ ':' : (loc_module loc) ++
+      ' ' : (loc_filename loc) ++ ':' : (line loc) ++ ':' : (char loc)
+      where
+        line = show . fst . loc_start
+        char = show . snd . loc_start
 
 data TestTimerType =
   NullTestTimerType
