diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,11 @@
+## 1.2.3
+
+* Added `withLoggedProcess_`
+
+## 1.2.2.1
+
+* Add missing `hClose` to `withSinkFileCautious`
+
 ## 1.2.2
 
 * `sinkHandleBuilder`, `sinkHandleFlush`, `BuilderInput`, and `FlushInput`
diff --git a/Data/Conduit/Binary.hs b/Data/Conduit/Binary.hs
--- a/Data/Conduit/Binary.hs
+++ b/Data/Conduit/Binary.hs
@@ -670,6 +670,7 @@
     cautiousCleanup
     (\(tmpFP, h) -> do
         a <- run $ inner $ sinkHandle h
+        hClose h
         renameFile tmpFP fp
         return a)
 
diff --git a/Data/Conduit/Process/Typed.hs b/Data/Conduit/Process/Typed.hs
--- a/Data/Conduit/Process/Typed.hs
+++ b/Data/Conduit/Process/Typed.hs
@@ -9,18 +9,24 @@
     -- * Generalized functions
   , withProcess
   , withProcess_
+  , withLoggedProcess_
     -- * Reexports
   , module System.Process.Typed
   ) where
 
 import System.Process.Typed hiding (withProcess, withProcess_)
 import qualified System.Process.Typed as P
-import Data.Conduit (ConduitM)
+import Data.Conduit (ConduitM, (.|), runConduit)
 import qualified Data.Conduit as C
 import qualified Data.Conduit.Binary as CB
 import Control.Monad.IO.Unlift
 import qualified Data.ByteString as S
 import System.IO (hClose)
+import qualified Data.Conduit.List as CL
+import qualified Data.ByteString.Lazy as BL
+import Data.IORef (IORef, newIORef, readIORef, modifyIORef)
+import Control.Exception (throwIO, catch)
+import Control.Concurrent.Async (concurrently)
 
 -- | Provide input to a process by writing to a conduit.
 --
@@ -38,6 +44,21 @@
     (\h -> C.addCleanup (\_ -> liftIO $ hClose h) (CB.sourceHandle h))
     `fmap` createPipe
 
+-- | Internal function: like 'createSource', but stick all chunks into
+-- the 'IORef'.
+createSourceLogged
+  :: MonadIO m
+  => IORef ([S.ByteString] -> [S.ByteString])
+  -> StreamSpec 'STOutput (ConduitM i S.ByteString m ())
+createSourceLogged ref =
+    -- We do not add a cleanup action to close the handle, since in
+    -- withLoggedProcess_ we attempt to read from the handle twice
+    (\h ->
+       (  CB.sourceHandle h
+       .| CL.iterM (\bs -> liftIO $ modifyIORef ref (. (bs:))))
+    )
+    `fmap` createPipe
+
 -- | Same as 'P.withProcess', but generalized to 'MonadUnliftIO'.
 --
 -- @since 1.2.1
@@ -57,3 +78,36 @@
   -> (Process stdin stdout stderr -> m a)
   -> m a
 withProcess_ pc f = withRunInIO $ \run -> P.withProcess pc (run . f)
+
+-- | Run a process, throwing an exception on a failure exit code. This
+-- will store all output from stdout and stderr in memory for better
+-- error messages. Note that this will require unbounded memory usage,
+-- so caveat emptor.
+--
+-- This will ignore any previous settings for the stdout and stderr
+-- streams, and instead force them to use 'createSource'.
+--
+-- @since 1.2.3
+withLoggedProcess_
+  :: MonadUnliftIO m
+  => ProcessConfig stdin stdoutIgnored stderrIgnored
+  -> (Process stdin (ConduitM () S.ByteString m ()) (ConduitM () S.ByteString m ()) -> m a)
+  -> m a
+withLoggedProcess_ pc inner = withUnliftIO $ \u -> do
+  stdoutBuffer <- newIORef id
+  stderrBuffer <- newIORef id
+  let pc' = setStdout (createSourceLogged stdoutBuffer)
+          $ setStderr (createSourceLogged stderrBuffer) pc
+  P.withProcess pc' $ \p -> do
+    a <- unliftIO u $ inner p
+    let drain src = unliftIO u (runConduit (src .| CL.sinkNull))
+    ((), ()) <- drain (getStdout p) `concurrently`
+                drain (getStderr p)
+    checkExitCode p `catch` \ece -> do
+      stdout <- readIORef stdoutBuffer
+      stderr <- readIORef stderrBuffer
+      throwIO ece
+        { eceStdout = BL.fromChunks $ stdout []
+        , eceStderr = BL.fromChunks $ stderr []
+        }
+    return a
diff --git a/conduit-extra.cabal b/conduit-extra.cabal
--- a/conduit-extra.cabal
+++ b/conduit-extra.cabal
@@ -1,5 +1,5 @@
 Name:                conduit-extra
-Version:             1.2.2
+Version:             1.2.3
 Synopsis:            Batteries included conduit: adapters for common libraries.
 Description:
     The conduit package itself maintains relative small dependencies. The purpose of this package is to collect commonly used utility functions wrapping other library dependencies, without depending on heavier-weight dependencies. The basic idea is that this package should only depend on haskell-platform packages and conduit.
