diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index 3537133a4724583a5e248a66b52627c96edbc865..c07a9d3925a0b2686a5750a37056702dbe79e5de 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -35,7 +35,7 @@
 #include "stringize.h"
 #include "llsdutil.h"
 #include "llevents.h"
-#include "llerrorcontrol.h"
+#include "wrapllerrs.h"
 
 #if defined(LL_WINDOWS)
 #define sleep(secs) _sleep((secs) * 1000)
@@ -233,68 +233,6 @@ class NamedTempDir: public boost::noncopyable
     std::string mPath;
 };
 
-// statically reference the function in test.cpp... it's short, we could
-// replicate, but better to reuse
-extern void wouldHaveCrashed(const std::string& message);
-
-/**
- * Capture log messages. This is adapted (simplified) from the one in
- * llerror_test.cpp. Sigh, should've broken that out into a separate header
- * file, but time for this project is short...
- */
-class TestRecorder : public LLError::Recorder
-{
-public:
-    TestRecorder():
-        // Mostly what we're trying to accomplish by saving and resetting
-        // LLError::Settings is to bypass the default RecordToStderr and
-        // RecordToWinDebug Recorders. As these are visible only inside
-        // llerror.cpp, we can't just call LLError::removeRecorder() with
-        // each. For certain tests we need to produce, capture and examine
-        // DEBUG log messages -- but we don't want to spam the user's console
-        // with that output. If it turns out that saveAndResetSettings() has
-        // some bad effect, give up and just let the DEBUG level log messages
-        // display.
-        mOldSettings(LLError::saveAndResetSettings())
-    {
-        LLError::setFatalFunction(wouldHaveCrashed);
-        LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
-        LLError::addRecorder(this);
-    }
-
-    ~TestRecorder()
-    {
-        LLError::removeRecorder(this);
-        LLError::restoreSettings(mOldSettings);
-    }
-
-    void recordMessage(LLError::ELevel level,
-                       const std::string& message)
-    {
-        mMessages.push_back(message);
-    }
-
-    /// Don't assume the message we want is necessarily the LAST log message
-    /// emitted by the underlying code; search backwards through all messages
-    /// for the sought string.
-    std::string messageWith(const std::string& search)
-    {
-        for (std::list<std::string>::const_reverse_iterator rmi(mMessages.rbegin()),
-                 rmend(mMessages.rend());
-             rmi != rmend; ++rmi)
-        {
-            if (rmi->find(search) != std::string::npos)
-                return *rmi;
-        }
-        // failed to find any such message
-        return std::string();
-    }
-
-    typedef std::list<std::string> MessageList;
-    MessageList mMessages;
-    LLError::Settings* mOldSettings;
-};
-
 /*****************************************************************************
 *   TUT
 *****************************************************************************/
@@ -843,7 +781,7 @@ namespace tut
     void object::test<10>()
     {
         set_test_name("'bogus' test");
-        TestRecorder recorder;
+        CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
                                  "print 'Hello world'\n");
         py.mParams.files.add(LLProcess::FileParam("bogus"));
@@ -874,7 +812,7 @@ namespace tut
         set_test_name("'tpipe' test");
         // Replace this test with one or more real 'tpipe' tests when we
         // implement 'tpipe' support
-        TestRecorder recorder;
+        CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
                                  "print 'Hello world'\n");
         py.mParams.files.add(LLProcess::FileParam());
@@ -892,7 +830,7 @@ namespace tut
         set_test_name("'npipe' test");
         // Replace this test with one or more real 'npipe' tests when we
         // implement 'npipe' support
-        TestRecorder recorder;
+        CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
                                  "print 'Hello world'\n");
         py.mParams.files.add(LLProcess::FileParam());
@@ -909,7 +847,7 @@ namespace tut
     void object::test<14>()
     {
         set_test_name("internal pipe name warning");
-        TestRecorder recorder;
+        CaptureLog recorder;
         PythonProcessLauncher py(get_test_name(),
                                  "import sys\n"
                                  "sys.exit(7)\n");
@@ -965,7 +903,7 @@ namespace tut
 #define EXPECT_FAIL_WITH_LOG(EXPECT, CODE)                              \
     do                                                                  \
     {                                                                   \
-        TestRecorder recorder;                                          \
+        CaptureLog recorder;                                            \
         ensure(#CODE " succeeded", ! (CODE));                           \
         ensure("wrong log message", ! recorder.messageWith(EXPECT).empty()); \
     } while (0)
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index ffda84729bd3c6cf1c453001e6cc2a96602e5def..a61f8451b3392a36bfc809079ee5a6782fb7e64c 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -30,6 +30,14 @@
 #define LL_WRAPLLERRS_H
 
 #include "llerrorcontrol.h"
+#include <boost/bind.hpp>
+#include <list>
+#include <string>
+#include <stdexcept>
+
+// statically reference the function in test.cpp... it's short, we could
+// replicate, but better to reuse
+extern void wouldHaveCrashed(const std::string& message);
 
 struct WrapLL_ERRS
 {
@@ -70,4 +78,61 @@ struct WrapLL_ERRS
     LLError::FatalFunction mPriorFatal;
 };
 
+/**
+ * Capture log messages. This is adapted (simplified) from the one in
+ * llerror_test.cpp.
+ */
+class CaptureLog : public LLError::Recorder
+{
+public:
+    CaptureLog():
+        // Mostly what we're trying to accomplish by saving and resetting
+        // LLError::Settings is to bypass the default RecordToStderr and
+        // RecordToWinDebug Recorders. As these are visible only inside
+        // llerror.cpp, we can't just call LLError::removeRecorder() with
+        // each. For certain tests we need to produce, capture and examine
+        // DEBUG log messages -- but we don't want to spam the user's console
+        // with that output. If it turns out that saveAndResetSettings() has
+        // some bad effect, give up and just let the DEBUG level log messages
+        // display.
+        mOldSettings(LLError::saveAndResetSettings())
+    {
+        LLError::setFatalFunction(wouldHaveCrashed);
+        LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+        LLError::addRecorder(this);
+    }
+
+    ~CaptureLog()
+    {
+        LLError::removeRecorder(this);
+        LLError::restoreSettings(mOldSettings);
+    }
+
+    void recordMessage(LLError::ELevel level,
+                       const std::string& message)
+    {
+        mMessages.push_back(message);
+    }
+
+    /// Don't assume the message we want is necessarily the LAST log message
+    /// emitted by the underlying code; search backwards through all messages
+    /// for the sought string.
+    std::string messageWith(const std::string& search)
+    {
+        for (std::list<std::string>::const_reverse_iterator rmi(mMessages.rbegin()),
+                 rmend(mMessages.rend());
+             rmi != rmend; ++rmi)
+        {
+            if (rmi->find(search) != std::string::npos)
+                return *rmi;
+        }
+        // failed to find any such message
+        return std::string();
+    }
+
+    typedef std::list<std::string> MessageList;
+    MessageList mMessages;
+    LLError::Settings* mOldSettings;
+};
+
 #endif /* ! defined(LL_WRAPLLERRS_H) */