THRIFT-5898: Replace global variable with a singleton getter
Client: cpp
diff --git a/contrib/transport-sample/ThriftCommon.cpp b/contrib/transport-sample/ThriftCommon.cpp
index 2b676a8..9f08707 100644
--- a/contrib/transport-sample/ThriftCommon.cpp
+++ b/contrib/transport-sample/ThriftCommon.cpp
@@ -7,7 +7,7 @@
 {
 	//----------------------------------------------------------------------------
 	//Launch child process and pass R/W anonymous pipe handles on cmd line.
-	//This is a simple example and does not include elevation or other 
+	//This is a simple example and does not include elevation or other
 	//advanced features.
 	//
 	bool LaunchAnonPipeChild(std::string app, boost::shared_ptr<TServerTransport> transport)
@@ -25,7 +25,7 @@
 		//spawn the child process
 		if (!CreateProcessA(nullptr, handles, nullptr,nullptr,TRUE,0,nullptr,nullptr,&si,&pi))
 		{
-			GlobalOutput.perror("TPipeServer CreateProcess failed, GLE=", GetLastError());
+			TOutput::instance().perror("TPipeServer CreateProcess failed, GLE=", GetLastError());
 			return false;
 		}
 
diff --git a/lib/cpp/src/thrift/TDispatchProcessor.h b/lib/cpp/src/thrift/TDispatchProcessor.h
index ae522b2..8654dc6 100644
--- a/lib/cpp/src/thrift/TDispatchProcessor.h
+++ b/lib/cpp/src/thrift/TDispatchProcessor.h
@@ -61,7 +61,7 @@
     // (The old generated processor code used to try to skip a T_STRUCT and
     // continue.  However, that seems unsafe.)
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client", mtype);
+      TOutput::instance().printf("received invalid message type %d from client", mtype);
       return false;
     }
 
@@ -76,7 +76,7 @@
     in->readMessageBegin(fname, mtype, seqid);
 
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client", mtype);
+      TOutput::instance().printf("received invalid message type %d from client", mtype);
       return false;
     }
 
@@ -114,7 +114,7 @@
     in->readMessageBegin(fname, mtype, seqid);
 
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client", mtype);
+      TOutput::instance().printf("received invalid message type %d from client", mtype);
       return false;
     }
 
diff --git a/lib/cpp/src/thrift/TOutput.cpp b/lib/cpp/src/thrift/TOutput.cpp
index 2d95bd1..495db6c 100644
--- a/lib/cpp/src/thrift/TOutput.cpp
+++ b/lib/cpp/src/thrift/TOutput.cpp
@@ -31,8 +31,6 @@
 namespace apache {
 namespace thrift {
 
-/*THRIFT_EXPORT*/ TOutput GlobalOutput;   // if you need this exported, build your own wrapper lib around and export it yourself
-
 TOutput::TOutput() : f_(&errorTimeWrapper) {}
 
 void TOutput::printf(const char* message, ...) {
@@ -148,5 +146,11 @@
   return std::string(b_error);
 #endif // __ZEPHYR__
 }
+
+TOutput& TOutput::instance() {
+  static TOutput instance;
+  return instance;
+}
+
 }
 } // apache::thrift
diff --git a/lib/cpp/src/thrift/TOutput.h b/lib/cpp/src/thrift/TOutput.h
index 8a9061a..bd00630 100644
--- a/lib/cpp/src/thrift/TOutput.h
+++ b/lib/cpp/src/thrift/TOutput.h
@@ -20,8 +20,6 @@
 #ifndef _THRIFT_OUTPUT_H_
 #define _THRIFT_OUTPUT_H_ 1
 
-//#include <thrift/thrift_export.h>
-
 namespace apache {
 namespace thrift {
 
@@ -49,11 +47,13 @@
   /** Just like strerror_r but returns a C++ string object. */
   static std::string strerror_s(int errno_copy);
 
+  /** Get a singleton instance of the global TOutput object used by
+   * the library internally.  */
+  static TOutput& instance();
+
 private:
   void (*f_)(const char*);
 };
-
-/*THRIFT_EXPORT*/ extern TOutput GlobalOutput;   // if you need this exported, build your own wrapper lib around and export it yourself
 }
 } // namespace apache::thrift
 
diff --git a/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h b/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h
index 2a694ac..3ada635 100644
--- a/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h
+++ b/lib/cpp/src/thrift/async/TAsyncDispatchProcessor.h
@@ -62,7 +62,7 @@
     // (The old generated processor code used to try to skip a T_STRUCT and
     // continue.  However, that seems unsafe.)
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client", mtype);
+      TOutput::instance().printf("received invalid message type %d from client", mtype);
       _return(false);
       return;
     }
@@ -79,7 +79,7 @@
     in->readMessageBegin(fname, mtype, seqid);
 
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client", mtype);
+      TOutput::instance().printf("received invalid message type %d from client", mtype);
       _return(false);
       return;
     }
@@ -123,7 +123,7 @@
     // (The old generated processor code used to try to skip a T_STRUCT and
     // continue.  However, that seems unsafe.)
     if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
-      GlobalOutput.printf("received invalid message type %d from client", mtype);
+      TOutput::instance().printf("received invalid message type %d from client", mtype);
       _return(false);
       return;
     }
diff --git a/lib/cpp/src/thrift/concurrency/ThreadManager.cpp b/lib/cpp/src/thrift/concurrency/ThreadManager.cpp
index e917f4a..a98ce00 100644
--- a/lib/cpp/src/thrift/concurrency/ThreadManager.cpp
+++ b/lib/cpp/src/thrift/concurrency/ThreadManager.cpp
@@ -309,9 +309,9 @@
           try {
             task->run();
           } catch (const std::exception& e) {
-            GlobalOutput.printf("[ERROR] task->run() raised an exception: %s", e.what());
+            TOutput::instance().printf("[ERROR] task->run() raised an exception: %s", e.what());
           } catch (...) {
-            GlobalOutput.printf("[ERROR] task->run() raised an unknown exception");
+            TOutput::instance().printf("[ERROR] task->run() raised an unknown exception");
           }
 
           // Re-acquire the lock to proceed in the thread manager
diff --git a/lib/cpp/src/thrift/server/TConnectedClient.cpp b/lib/cpp/src/thrift/server/TConnectedClient.cpp
index 9a78e3e..18defd5 100644
--- a/lib/cpp/src/thrift/server/TConnectedClient.cpp
+++ b/lib/cpp/src/thrift/server/TConnectedClient.cpp
@@ -75,14 +75,14 @@
           // All other transport exceptions are logged.
           // State of connection is unknown.  Done.
           string errStr = string("TConnectedClient died: ") + ttx.what();
-          GlobalOutput(errStr.c_str());
+          TOutput::instance()(errStr.c_str());
           done = true;
           break;
         }
       }
     } catch (const TException& tex) {
       string errStr = string("TConnectedClient processing exception: ") + tex.what();
-      GlobalOutput(errStr.c_str());
+      TOutput::instance()(errStr.c_str());
       // Disconnect from client, because we could not process the message.
       done = true;
     }
@@ -100,21 +100,21 @@
     inputProtocol_->getTransport()->close();
   } catch (const TTransportException& ttx) {
     string errStr = string("TConnectedClient input close failed: ") + ttx.what();
-    GlobalOutput(errStr.c_str());
+    TOutput::instance()(errStr.c_str());
   }
 
   try {
     outputProtocol_->getTransport()->close();
   } catch (const TTransportException& ttx) {
     string errStr = string("TConnectedClient output close failed: ") + ttx.what();
-    GlobalOutput(errStr.c_str());
+    TOutput::instance()(errStr.c_str());
   }
 
   try {
     client_->close();
   } catch (const TTransportException& ttx) {
     string errStr = string("TConnectedClient client close failed: ") + ttx.what();
-    GlobalOutput(errStr.c_str());
+    TOutput::instance()(errStr.c_str());
   }
 }
 }
diff --git a/lib/cpp/src/thrift/server/TNonblockingServer.cpp b/lib/cpp/src/thrift/server/TNonblockingServer.cpp
index d53535b..d7620eb 100644
--- a/lib/cpp/src/thrift/server/TNonblockingServer.cpp
+++ b/lib/cpp/src/thrift/server/TNonblockingServer.cpp
@@ -339,21 +339,21 @@
         }
       }
     } catch (const TTransportException& ttx) {
-      GlobalOutput.printf("TNonblockingServer: client died: %s", ttx.what());
+      TOutput::instance().printf("TNonblockingServer: client died: %s", ttx.what());
     } catch (const std::bad_alloc&) {
-      GlobalOutput("TNonblockingServer: caught bad_alloc exception.");
+      TOutput::instance()("TNonblockingServer: caught bad_alloc exception.");
       exit(1);
     } catch (const std::exception& x) {
-      GlobalOutput.printf("TNonblockingServer: process() exception: %s: %s",
+      TOutput::instance().printf("TNonblockingServer: process() exception: %s: %s",
                           typeid(x).name(),
                           x.what());
     } catch (...) {
-      GlobalOutput.printf("TNonblockingServer: unknown exception while processing.");
+      TOutput::instance().printf("TNonblockingServer: unknown exception while processing.");
     }
 
     // Signal completion back to the libevent thread via a pipe
     if (!connection_->notifyIOThread()) {
-      GlobalOutput.printf("TNonblockingServer: failed to notifyIOThread, closing.");
+      TOutput::instance().printf("TNonblockingServer: failed to notifyIOThread, closing.");
       connection_->server_->decrementActiveProcessors();
       connection_->close();
       throw TException("TNonblockingServer::Task::run: failed write on notify pipe");
@@ -447,7 +447,7 @@
         //In Nonblocking SSLSocket some operations need to be retried again.
         //Current approach is parsing exception message, but a better solution needs to be investigated.
         if(!strstr(te.what(), "retry")) {
-          GlobalOutput.printf("TConnection::workSocket(): %s", te.what());
+          TOutput::instance().printf("TConnection::workSocket(): %s", te.what());
           close();
 
           return;
@@ -464,7 +464,7 @@
       if (readWant_ > server_->getMaxFrameSize()) {
         // Don't allow giant frame sizes.  This prevents bad clients from
         // causing us to try and allocate a giant buffer.
-        GlobalOutput.printf(
+        TOutput::instance().printf(
             "TNonblockingServer: frame size too large "
             "(%" PRIu32 " > %" PRIu64
             ") from client %s. "
@@ -494,7 +494,7 @@
     case SOCKET_RECV:
       // It is an error to be in this state if we already have all the data
       if (!(readBufferPos_ < readWant_)) {
-        GlobalOutput.printf("TNonblockingServer: frame size too short");
+        TOutput::instance().printf("TNonblockingServer: frame size too short");
         close();
         return;
       }
@@ -507,7 +507,7 @@
         //In Nonblocking SSLSocket some operations need to be retried again.
         //Current approach is parsing exception message, but a better solution needs to be investigated.
         if(!strstr(te.what(), "retry")) {
-          GlobalOutput.printf("TConnection::workSocket(): %s", te.what());
+          TOutput::instance().printf("TConnection::workSocket(): %s", te.what());
           close();
         }
 
@@ -543,7 +543,7 @@
 
       // If there is no data to send, then let us move on
       if (writeBufferPos_ == writeBufferSize_) {
-        GlobalOutput("WARNING: Send state with no data to send");
+        TOutput::instance()("WARNING: Send state with no data to send");
         transition();
         return;
       }
@@ -552,7 +552,7 @@
         left = writeBufferSize_ - writeBufferPos_;
         sent = tSocket_->write_partial(writeBuffer_ + writeBufferPos_, left);
       } catch (TTransportException& te) {
-        GlobalOutput.printf("TConnection::workSocket(): %s ", te.what());
+        TOutput::instance().printf("TConnection::workSocket(): %s ", te.what());
         close();
         return;
       }
@@ -570,7 +570,7 @@
       return;
 
     default:
-      GlobalOutput.printf("Unexpected Socket State %d", socketState_);
+      TOutput::instance().printf("Unexpected Socket State %d", socketState_);
       assert(0);
       return;
     }
@@ -635,11 +635,11 @@
         server_->addTask(task);
       } catch (IllegalStateException& ise) {
         // The ThreadManager is not ready to handle any more tasks (it's probably shutting down).
-        GlobalOutput.printf("IllegalStateException: Server::process() %s", ise.what());
+        TOutput::instance().printf("IllegalStateException: Server::process() %s", ise.what());
         server_->decrementActiveProcessors();
         close();
       } catch (TimedOutException& to) {
-        GlobalOutput.printf("[ERROR] TimedOutException: Server::process() %s", to.what());
+        TOutput::instance().printf("[ERROR] TimedOutException: Server::process() %s", to.what());
         server_->decrementActiveProcessors();
         close();
       }
@@ -653,7 +653,7 @@
         // Invoke the processor
         processor_->process(inputProtocol_, outputProtocol_, connectionContext_);
       } catch (const TTransportException& ttx) {
-        GlobalOutput.printf(
+        TOutput::instance().printf(
             "TNonblockingServer transport error in "
             "process(): %s",
             ttx.what());
@@ -661,14 +661,14 @@
         close();
         return;
       } catch (const std::exception& x) {
-        GlobalOutput.printf("Server::process() uncaught exception: %s: %s",
+        TOutput::instance().printf("Server::process() uncaught exception: %s: %s",
                             typeid(x).name(),
                             x.what());
         server_->decrementActiveProcessors();
         close();
         return;
       } catch (...) {
-        GlobalOutput.printf("Server::process() unknown exception");
+        TOutput::instance().printf("Server::process() unknown exception");
         server_->decrementActiveProcessors();
         close();
         return;
@@ -784,7 +784,7 @@
     return;
 
   default:
-    GlobalOutput.printf("Unexpected Application State %d", appState_);
+    TOutput::instance().printf("Unexpected Application State %d", appState_);
     assert(0);
   }
 }
@@ -797,7 +797,7 @@
 
   // Delete a previously existing event
   if (eventFlags_ && event_del(&event_) == -1) {
-    GlobalOutput.perror("TConnection::setFlags() event_del", THRIFT_GET_SOCKET_ERROR);
+    TOutput::instance().perror("TConnection::setFlags() event_del", THRIFT_GET_SOCKET_ERROR);
     return;
   }
 
@@ -841,7 +841,7 @@
 
   // Add the event
   if (event_add(&event_, nullptr) == -1) {
-    GlobalOutput.perror("TConnection::setFlags(): could not event_add", THRIFT_GET_SOCKET_ERROR);
+    TOutput::instance().perror("TConnection::setFlags(): could not event_add", THRIFT_GET_SOCKET_ERROR);
   }
 }
 
@@ -988,7 +988,7 @@
 
     // Fail fast if we could not create a TConnection object
     if (clientConnection == nullptr) {
-      GlobalOutput.printf("thriftServerEventHandler: failed TConnection factory");
+      TOutput::instance().printf("thriftServerEventHandler: failed TConnection factory");
       clientSocket->close();
       return;
     }
@@ -1009,7 +1009,7 @@
       clientConnection->transition();
     } else {
       if (!clientConnection->notifyIOThread()) {
-        GlobalOutput.perror("[ERROR] notifyIOThread failed on fresh connection, closing", errno);
+        TOutput::instance().perror("[ERROR] notifyIOThread failed on fresh connection, closing", errno);
         clientConnection->close();
       }
     }
@@ -1042,13 +1042,13 @@
   size_t activeConnections = numTConnections_ - connectionStack_.size();
   if (numActiveProcessors_ > maxActiveProcessors_ || activeConnections > maxConnections_) {
     if (!overloaded_) {
-      GlobalOutput.printf("TNonblockingServer: overload condition begun.");
+      TOutput::instance().printf("TNonblockingServer: overload condition begun.");
       overloaded_ = true;
     }
   } else {
     if (overloaded_ && (numActiveProcessors_ <= overloadHysteresis_ * maxActiveProcessors_)
         && (activeConnections <= overloadHysteresis_ * maxConnections_)) {
-      GlobalOutput.printf(
+      TOutput::instance().printf(
           "TNonblockingServer: overload ended; "
           "%u dropped (%llu total)",
           nConnectionsDropped_,
@@ -1121,7 +1121,7 @@
   assert(ioThreads_.size() == numIOThreads_);
   assert(ioThreads_.size() > 0);
 
-  GlobalOutput.printf("TNonblockingServer: Serving with %d io threads.",
+  TOutput::instance().printf("TNonblockingServer: Serving with %d io threads.",
                       ioThreads_.size());
 
   // Launch all the secondary IO threads in separate threads
@@ -1160,7 +1160,7 @@
   // Ensure all threads are finished before exiting serve()
   for (uint32_t i = 0; i < ioThreads_.size(); ++i) {
     ioThreads_[i]->join();
-    GlobalOutput.printf("TNonblocking: join done for IO thread #%d", i);
+    TOutput::instance().printf("TNonblocking: join done for IO thread #%d", i);
   }
 }
 
@@ -1192,7 +1192,7 @@
 
   if (listenSocket_ != THRIFT_INVALID_SOCKET) {
     if (0 != ::THRIFT_CLOSESOCKET(listenSocket_)) {
-      GlobalOutput.perror("TNonblockingIOThread listenSocket_ close(): ", THRIFT_GET_SOCKET_ERROR);
+      TOutput::instance().perror("TNonblockingIOThread listenSocket_ close(): ", THRIFT_GET_SOCKET_ERROR);
     }
     listenSocket_ = THRIFT_INVALID_SOCKET;
   }
@@ -1200,7 +1200,7 @@
   for (auto notificationPipeFD : notificationPipeFDs_) {
     if (notificationPipeFD >= 0) {
       if (0 != ::THRIFT_CLOSESOCKET(notificationPipeFD)) {
-        GlobalOutput.perror("TNonblockingIOThread notificationPipe close(): ",
+        TOutput::instance().perror("TNonblockingIOThread notificationPipe close(): ",
                             THRIFT_GET_SOCKET_ERROR);
       }
       notificationPipeFD = THRIFT_INVALID_SOCKET;
@@ -1210,7 +1210,7 @@
 
 void TNonblockingIOThread::createNotificationPipe() {
   if (evutil_socketpair(AF_LOCAL, SOCK_STREAM, 0, notificationPipeFDs_) == -1) {
-    GlobalOutput.perror("TNonblockingServer::createNotificationPipe ", EVUTIL_SOCKET_ERROR());
+    TOutput::instance().perror("TNonblockingServer::createNotificationPipe ", EVUTIL_SOCKET_ERROR());
     throw TException("can't create notification pipe");
   }
   if (evutil_make_socket_nonblocking(notificationPipeFDs_[0]) < 0
@@ -1251,7 +1251,7 @@
 
   // Print some libevent stats
   if (number_ == 0) {
-    GlobalOutput.printf("TNonblockingServer: using libevent %s method %s",
+    TOutput::instance().printf("TNonblockingServer: using libevent %s method %s",
                         event_get_version(),
                         event_base_get_method(eventBase_));
   }
@@ -1271,7 +1271,7 @@
           "TNonblockingServer::serve(): "
           "event_add() failed on server listen event");
     }
-    GlobalOutput.printf("TNonblocking: IO thread #%d registered for listen.", number_);
+    TOutput::instance().printf("TNonblocking: IO thread #%d registered for listen.", number_);
   }
 
   createNotificationPipe();
@@ -1292,7 +1292,7 @@
         "TNonblockingServer::serve(): "
         "event_add() failed on task-done notification event");
   }
-  GlobalOutput.printf("TNonblocking: IO thread #%d registered for notify.", number_);
+  TOutput::instance().printf("TNonblocking: IO thread #%d registered for notify.", number_);
 }
 
 bool TNonblockingIOThread::notify(TNonblockingServer::TConnection* conn) {
@@ -1396,18 +1396,18 @@
       connection->transition();
     } else if (nBytes > 0) {
       // throw away these bytes and hope that next time we get a solid read
-      GlobalOutput.printf("notifyHandler: Bad read of %d bytes, wanted %d", nBytes, kSize);
+      TOutput::instance().printf("notifyHandler: Bad read of %d bytes, wanted %d", nBytes, kSize);
       ioThread->breakLoop(true);
       return;
     } else if (nBytes == 0) {
-      GlobalOutput.printf("notifyHandler: Notify socket closed!");
+      TOutput::instance().printf("notifyHandler: Notify socket closed!");
       ioThread->breakLoop(false);
       // exit the loop
       break;
     } else { // nBytes < 0
       if (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK
           && THRIFT_GET_SOCKET_ERROR != THRIFT_EAGAIN) {
-        GlobalOutput.perror("TNonblocking: notifyHandler read() failed: ", THRIFT_GET_SOCKET_ERROR);
+        TOutput::instance().perror("TNonblocking: notifyHandler read() failed: ", THRIFT_GET_SOCKET_ERROR);
         ioThread->breakLoop(true);
         return;
       }
@@ -1419,10 +1419,10 @@
 
 void TNonblockingIOThread::breakLoop(bool error) {
   if (error) {
-    GlobalOutput.printf("TNonblockingServer: IO thread #%d exiting with error.", number_);
+    TOutput::instance().printf("TNonblockingServer: IO thread #%d exiting with error.", number_);
     // TODO: figure out something better to do here, but for now kill the
     // whole process.
-    GlobalOutput.printf("TNonblockingServer: aborting process.");
+    TOutput::instance().printf("TNonblockingServer: aborting process.");
     ::abort();
   }
 
@@ -1458,9 +1458,9 @@
 
   // Actually set the sched params for the current thread.
   if (0 == pthread_setschedparam(pthread_self(), policy, &sp)) {
-    GlobalOutput.printf("TNonblocking: IO Thread #%d using high-priority scheduler!", number_);
+    TOutput::instance().printf("TNonblocking: IO Thread #%d using high-priority scheduler!", number_);
   } else {
-    GlobalOutput.perror("TNonblocking: pthread_setschedparam(): ", THRIFT_GET_SOCKET_ERROR);
+    TOutput::instance().perror("TNonblocking: pthread_setschedparam(): ", THRIFT_GET_SOCKET_ERROR);
   }
 #else
   THRIFT_UNUSED_VARIABLE(value);
@@ -1477,7 +1477,7 @@
 
   if (eventBase_ != nullptr)
   {
-    GlobalOutput.printf("TNonblockingServer: IO thread #%d entering loop...", number_);
+    TOutput::instance().printf("TNonblockingServer: IO thread #%d entering loop...", number_);
     // Run libevent engine, never returns, invokes calls to eventHandler
     event_base_loop(eventBase_, 0);
 
@@ -1489,14 +1489,14 @@
     cleanupEvents();
   }
 
-  GlobalOutput.printf("TNonblockingServer: IO thread #%d run() done!", number_);
+  TOutput::instance().printf("TNonblockingServer: IO thread #%d run() done!", number_);
 }
 
 void TNonblockingIOThread::cleanupEvents() {
   // stop the listen socket, if any
   if (listenSocket_ != THRIFT_INVALID_SOCKET) {
     if (event_del(&serverEvent_) == -1) {
-      GlobalOutput.perror("TNonblockingIOThread::stop() event_del: ", THRIFT_GET_SOCKET_ERROR);
+      TOutput::instance().perror("TNonblockingIOThread::stop() event_del: ", THRIFT_GET_SOCKET_ERROR);
     }
   }
 
diff --git a/lib/cpp/src/thrift/server/TServerFramework.cpp b/lib/cpp/src/thrift/server/TServerFramework.cpp
index 2431bc2..665713a 100644
--- a/lib/cpp/src/thrift/server/TServerFramework.cpp
+++ b/lib/cpp/src/thrift/server/TServerFramework.cpp
@@ -101,7 +101,7 @@
       pTransport->close();
     } catch (const TTransportException& ttx) {
       string errStr = string("TServerFramework " + name + " close failed: ") + ttx.what();
-      GlobalOutput(errStr.c_str());
+      TOutput::instance()(errStr.c_str());
     }
   }
 }
@@ -179,7 +179,7 @@
         // All other transport exceptions are logged.
         // State of connection is unknown.  Done.
         string errStr = string("TServerTransport died: ") + ttx.what();
-        GlobalOutput(errStr.c_str());
+        TOutput::instance()(errStr.c_str());
         break;
       }
     }
diff --git a/lib/cpp/src/thrift/transport/SocketCommon.cpp b/lib/cpp/src/thrift/transport/SocketCommon.cpp
index 0b064c7..2b826e3 100644
--- a/lib/cpp/src/thrift/transport/SocketCommon.cpp
+++ b/lib/cpp/src/thrift/transport/SocketCommon.cpp
@@ -37,7 +37,7 @@
 
 #ifndef __linux__
     if (isAbstractNamespace) {
-      GlobalOutput.perror("TSocket::open() Abstract Namespace Domain sockets only supported on linux: ", -99);
+      TOutput::instance().perror("TSocket::open() Abstract Namespace Domain sockets only supported on linux: ", -99);
       throw TTransportException(TTransportException::NOT_OPEN,
                                 " Abstract Namespace Domain socket path not supported");
     }
@@ -51,7 +51,7 @@
 
     if (addr_len > sizeof(((sockaddr_un*)nullptr)->sun_path)) {
         int errno_copy = THRIFT_GET_SOCKET_ERROR;
-        GlobalOutput.perror("TSocket::open() Unix Domain socket path too long", errno_copy);
+        TOutput::instance().perror("TSocket::open() Unix Domain socket path too long", errno_copy);
         throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path too long");
     }
 
diff --git a/lib/cpp/src/thrift/transport/TFDTransport.h b/lib/cpp/src/thrift/transport/TFDTransport.h
index fb84c9d..a9d5121 100644
--- a/lib/cpp/src/thrift/transport/TFDTransport.h
+++ b/lib/cpp/src/thrift/transport/TFDTransport.h
@@ -50,7 +50,7 @@
       try {
         close();
       } catch (TTransportException& ex) {
-        GlobalOutput.printf("~TFDTransport TTransportException: '%s'", ex.what());
+        TOutput::instance().printf("~TFDTransport TTransportException: '%s'", ex.what());
       }
     }
   }
diff --git a/lib/cpp/src/thrift/transport/TFileTransport.cpp b/lib/cpp/src/thrift/transport/TFileTransport.cpp
index 3f4d812..87da682 100644
--- a/lib/cpp/src/thrift/transport/TFileTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TFileTransport.cpp
@@ -101,10 +101,10 @@
   if (fd_ > 0) {
     // flush any events in the queue
     flush();
-    GlobalOutput.printf("error, current file (%s) not closed", filename_.c_str());
+    TOutput::instance().printf("error, current file (%s) not closed", filename_.c_str());
     if (-1 == ::THRIFT_CLOSE(fd_)) {
       int errno_copy = THRIFT_ERRNO;
-      GlobalOutput.perror("TFileTransport: resetOutputFile() ::close() ", errno_copy);
+      TOutput::instance().perror("TFileTransport: resetOutputFile() ::close() ", errno_copy);
       throw TTransportException(TTransportException::UNKNOWN,
                                 "TFileTransport: error in file close",
                                 errno_copy);
@@ -159,7 +159,7 @@
   // close logfile
   if (fd_ > 0) {
     if (-1 == ::THRIFT_CLOSE(fd_)) {
-      GlobalOutput.perror("TFileTransport: ~TFileTransport() ::close() ", THRIFT_ERRNO);
+      TOutput::instance().perror("TFileTransport: ~TFileTransport() ::close() ", THRIFT_ERRNO);
     } else {
       // successfully closed fd
       fd_ = 0;
@@ -306,7 +306,7 @@
       openLogFile();
     } catch (...) {
       int errno_copy = THRIFT_ERRNO;
-      GlobalOutput.perror("TFileTransport: writerThread() openLogFile() ", errno_copy);
+      TOutput::instance().perror("TFileTransport: writerThread() openLogFile() ", errno_copy);
       fd_ = 0;
       hasIOError = true;
     }
@@ -322,12 +322,12 @@
         readState_.resetAllValues();
       } else {
         int errno_copy = THRIFT_ERRNO;
-        GlobalOutput.perror("TFileTransport: writerThread() truncate ", errno_copy);
+        TOutput::instance().perror("TFileTransport: writerThread() truncate ", errno_copy);
         hasIOError = true;
       }
     } catch (...) {
       int errno_copy = THRIFT_ERRNO;
-      GlobalOutput.perror("TFileTransport: writerThread() initialization ", errno_copy);
+      TOutput::instance().perror("TFileTransport: writerThread() initialization ", errno_copy);
       hasIOError = true;
     }
   }
@@ -348,7 +348,7 @@
         ::THRIFT_FSYNC(fd_);
         if (-1 == ::THRIFT_CLOSE(fd_)) {
           int errno_copy = THRIFT_ERRNO;
-          GlobalOutput.perror("TFileTransport: writerThread() ::close() ", errno_copy);
+          TOutput::instance().perror("TFileTransport: writerThread() ::close() ", errno_copy);
         } else {
           // fd successfully closed
           fd_ = 0;
@@ -426,7 +426,7 @@
             std::unique_ptr<uint8_t[]> array(zeros);
             if (-1 == ::THRIFT_WRITE(fd_, zeros, padding)) {
               int errno_copy = THRIFT_ERRNO;
-              GlobalOutput.perror("TFileTransport: writerThread() error while padding zeros ",
+              TOutput::instance().perror("TFileTransport: writerThread() error while padding zeros ",
                                   errno_copy);
               hasIOError = true;
               continue;
@@ -440,7 +440,7 @@
         if (outEvent->eventSize_ > 0) {
           if (-1 == ::THRIFT_WRITE(fd_, outEvent->eventBuff_, outEvent->eventSize_)) {
             int errno_copy = THRIFT_ERRNO;
-            GlobalOutput.perror("TFileTransport: error while writing event ", errno_copy);
+            TOutput::instance().perror("TFileTransport: error while writing event ", errno_copy);
             hasIOError = true;
             continue;
           }
@@ -620,7 +620,7 @@
       // read error
       if (readState_.bufferLen_ == -1) {
         readState_.resetAllValues();
-        GlobalOutput("TFileTransport: error while reading from file");
+        TOutput::instance()("TFileTransport: error while reading from file");
         throw TTransportException("TFileTransport: error while reading from file");
       } else if (readState_.bufferLen_ == 0) { // EOF
         // wait indefinitely if there is no timeout
@@ -784,7 +784,7 @@
               "TFileTransport: log file corrupted at offset: %lu",
               static_cast<unsigned long>(offset_ + readState_.lastDispatchPtr_));
 
-      GlobalOutput(errorMsg);
+      TOutput::instance()(errorMsg);
       throw TTransportException(errorMsg);
     }
   }
@@ -829,7 +829,7 @@
   readState_.resetAllValues();
   currentEvent_ = nullptr;
   if (offset_ == -1) {
-    GlobalOutput("TFileTransport: lseek error in seekToChunk");
+    TOutput::instance()("TFileTransport: lseek error in seekToChunk");
     throw TTransportException("TFileTransport: lseek error in seekToChunk");
   }
 
@@ -898,7 +898,7 @@
   // make sure open call was successful
   if (fd_ == -1) {
     int errno_copy = THRIFT_ERRNO;
-    GlobalOutput.perror("TFileTransport: openLogFile() ::open() file: " + filename_, errno_copy);
+    TOutput::instance().perror("TFileTransport: openLogFile() ::open() file: " + filename_, errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, filename_, errno_copy);
   }
 }
@@ -924,7 +924,7 @@
 
 bool TFileTransportBuffer::addEvent(eventInfo* event) {
   if (bufferMode_ == READ) {
-    GlobalOutput("Trying to write to a buffer in read mode");
+    TOutput::instance()("Trying to write to a buffer in read mode");
   }
   if (writePoint_ < size_) {
     buffer_[writePoint_++] = event;
diff --git a/lib/cpp/src/thrift/transport/TFileTransport.h b/lib/cpp/src/thrift/transport/TFileTransport.h
index 902d906..64aec6d 100644
--- a/lib/cpp/src/thrift/transport/TFileTransport.h
+++ b/lib/cpp/src/thrift/transport/TFileTransport.h
@@ -218,7 +218,7 @@
 
   void setEventBufferSize(uint32_t bufferSize) {
     if (bufferAndThreadInitialized_) {
-      GlobalOutput("Cannot change the buffer size after writer thread started");
+      TOutput::instance()("Cannot change the buffer size after writer thread started");
       return;
     }
     eventBufferSize_ = bufferSize;
diff --git a/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp b/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp
index 0e59ae4..0c6654c 100644
--- a/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TNonblockingServerSocket.cpp
@@ -172,7 +172,7 @@
     if (::THRIFT_STAT(path_.c_str(), &path_info) < 0) {
 #endif
       const std::string vError = "TNonblockingServerSocket::isOpen(): The domain socket path '" + path_ + "' does not exist (yet).";
-      GlobalOutput.perror(vError.c_str(), THRIFT_GET_SOCKET_ERROR);
+      TOutput::instance().perror(vError.c_str(), THRIFT_GET_SOCKET_ERROR);
       return false;
     }
   }
@@ -224,7 +224,7 @@
       // of the Administrators security group on Windows XP and earlier. But
       // we do not target WinXP anymore so no special checks required.
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
+      TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
                           errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
@@ -241,7 +241,7 @@
                          cast_sockopt(&tcpSendBuffer_),
                          sizeof(tcpSendBuffer_))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
+      TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not set SO_SNDBUF",
@@ -256,7 +256,7 @@
                          cast_sockopt(&tcpRecvBuffer_),
                          sizeof(tcpRecvBuffer_))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
+      TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not set SO_RCVBUF",
@@ -268,7 +268,7 @@
   struct linger ling = {0, 0};
   if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&ling), sizeof(ling))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_LINGER", errno_copy);
   }
@@ -276,7 +276,7 @@
   // Keepalive to ensure full result flushing
   if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_KEEPALIVE, const_cast_sockopt(&one), sizeof(one))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_KEEPALIVE ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() SO_KEEPALIVE ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
       "Could not set TCP_NODELAY",
@@ -286,7 +286,7 @@
 #ifdef SO_NOSIGPIPE
   if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() SO_NOSIGPIPE", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() SO_NOSIGPIPE", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not set SO_NOSIGPIPE",
@@ -298,7 +298,7 @@
   int flags = THRIFT_FCNTL(serverSocket_, THRIFT_F_GETFL, 0);
   if (flags == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "THRIFT_FCNTL() THRIFT_F_GETFL failed",
@@ -307,7 +307,7 @@
 
   if (-1 == THRIFT_FCNTL(serverSocket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() THRIFT_FCNTL() THRIFT_O_NONBLOCK ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() THRIFT_FCNTL() THRIFT_O_NONBLOCK ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "THRIFT_FCNTL() THRIFT_F_SETFL THRIFT_O_NONBLOCK failed",
@@ -328,7 +328,7 @@
   if (-1
       == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&one), sizeof(one))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not set TCP_NODELAY",
@@ -340,7 +340,7 @@
   if (TSocket::getUseLowMinRto()) {
     if (-1 == setsockopt(s, IPPROTO_TCP, TCP_LOW_MIN_RTO, const_cast_sockopt(&one), sizeof(one))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TNonblockingServerSocket::listen() setsockopt() TCP_LOW_MIN_RTO ", errno_copy);
+      TOutput::instance().perror("TNonblockingServerSocket::listen() setsockopt() TCP_LOW_MIN_RTO ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
         "Could not set TCP_NODELAY",
@@ -373,7 +373,7 @@
                                  AI_PASSIVE | AI_V4MAPPED);
 #endif
     } catch (const std::system_error& e) {
-      GlobalOutput.printf("getaddrinfo() -> %d; %s", e.code().value(), e.what());
+      TOutput::instance().printf("getaddrinfo() -> %d; %s", e.code().value(), e.what());
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not resolve host for server socket.");
@@ -392,7 +392,7 @@
 
     if (serverSocket_ == THRIFT_INVALID_SOCKET) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TNonblockingServerSocket::listen() socket() ", errno_copy);
+      TOutput::instance().perror("TNonblockingServerSocket::listen() socket() ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not create server socket.",
@@ -416,7 +416,7 @@
       // use short circuit evaluation here to only sleep if we need to
     } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
 #else
-    GlobalOutput.perror("TNonblockingServerSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
+    TOutput::instance().perror("TNonblockingServerSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " Unix Domain socket path not supported");
 #endif
@@ -452,7 +452,7 @@
                              IPV6_V6ONLY,
                              cast_sockopt(&zero),
                              sizeof(zero))) {
-          GlobalOutput.perror("TNonblockingServerSocket::listen() IPV6_V6ONLY ", THRIFT_GET_SOCKET_ERROR);
+          TOutput::instance().perror("TNonblockingServerSocket::listen() IPV6_V6ONLY ", THRIFT_GET_SOCKET_ERROR);
         }
       }
 #endif // #ifdef IPV6_V6ONLY
@@ -472,7 +472,7 @@
       std::memset(&sa, 0, len);
       if (::getsockname(serverSocket_, reinterpret_cast<struct sockaddr*>(&sa), &len) < 0) {
         errno_copy = THRIFT_GET_SOCKET_ERROR;
-        GlobalOutput.perror("TNonblockingServerSocket::getPort() getsockname() ", errno_copy);
+        TOutput::instance().perror("TNonblockingServerSocket::getPort() getsockname() ", errno_copy);
       } else {
         if (sa.ss_family == AF_INET6) {
           const auto* sin = reinterpret_cast<const struct sockaddr_in6*>(&sa);
@@ -487,7 +487,7 @@
 
   // throw error if socket still wasn't created successfully
   if (serverSocket_ == THRIFT_INVALID_SOCKET) {
-    GlobalOutput.perror("TNonblockingServerSocket::listen() socket() ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() socket() ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not create server socket.",
@@ -507,7 +507,7 @@
     } else {
       THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TNonblockingServerSocket::listen() Could not bind to port %d", port_);
     }
-    GlobalOutput(errbuf);
+    TOutput::instance()(errbuf);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not bind",
@@ -520,7 +520,7 @@
   // Call listen
   if (-1 == ::listen(serverSocket_, acceptBacklog_)) {
     errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::listen() listen() ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::listen() listen() ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN, "Could not listen", errno_copy);
   }
@@ -558,7 +558,7 @@
 
   if (clientSocket == THRIFT_INVALID_SOCKET) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TNonblockingServerSocket::acceptImpl() ::accept() ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::acceptImpl() ::accept() ", errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "accept()", errno_copy);
   }
 
@@ -567,7 +567,7 @@
   if (flags == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     ::THRIFT_CLOSESOCKET(clientSocket);
-    GlobalOutput.perror("TNonblockingServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
+    TOutput::instance().perror("TNonblockingServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
     throw TTransportException(TTransportException::UNKNOWN,
                               "THRIFT_FCNTL(THRIFT_F_GETFL)",
                               errno_copy);
@@ -576,7 +576,7 @@
   if (-1 == THRIFT_FCNTL(clientSocket, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     ::THRIFT_CLOSESOCKET(clientSocket);
-    GlobalOutput
+    TOutput::instance()
         .perror("TNonblockingServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_SETFL ~THRIFT_O_NONBLOCK ",
                 errno_copy);
     throw TTransportException(TTransportException::UNKNOWN,
diff --git a/lib/cpp/src/thrift/transport/TPipe.cpp b/lib/cpp/src/thrift/transport/TPipe.cpp
index a18c4f7..8d02636 100644
--- a/lib/cpp/src/thrift/transport/TPipe.cpp
+++ b/lib/cpp/src/thrift/transport/TPipe.cpp
@@ -144,7 +144,7 @@
   readOverlap_.reset(buf, len, ready_event_.h);
   thread_->addWorkItem(&readOverlap_);
   if (readOverlap_.success == FALSE && readOverlap_.last_error != ERROR_IO_PENDING) {
-    GlobalOutput.perror("TPipe ::ReadFile errored GLE=", readOverlap_.last_error);
+    TOutput::instance().perror("TPipe ::ReadFile errored GLE=", readOverlap_.last_error);
     throw TTransportException(TTransportException::UNKNOWN, "TPipe: ReadFile failed");
   }
 }
@@ -186,14 +186,14 @@
     BOOL result = ::WriteFile(pipe, buf + written, len - written, nullptr, &tempOverlap);
 
     if (result == FALSE && ::GetLastError() != ERROR_IO_PENDING) {
-      GlobalOutput.perror("TPipe ::WriteFile errored GLE=", ::GetLastError());
+      TOutput::instance().perror("TPipe ::WriteFile errored GLE=", ::GetLastError());
       throw TTransportException(TTransportException::UNKNOWN, "TPipe: write failed");
     }
 
     DWORD bytes = 0;
     result = ::GetOverlappedResult(pipe, &tempOverlap, &bytes, TRUE);
     if (!result) {
-      GlobalOutput.perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
+      TOutput::instance().perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
       throw TTransportException(TTransportException::UNKNOWN, "TPipe: GetOverlappedResult failed");
     }
     written += bytes;
@@ -208,14 +208,14 @@
   BOOL result = ::ReadFile(pipe, buf, len, nullptr, &tempOverlap);
 
   if (result == FALSE && ::GetLastError() != ERROR_IO_PENDING) {
-    GlobalOutput.perror("TPipe ::ReadFile errored GLE=", ::GetLastError());
+    TOutput::instance().perror("TPipe ::ReadFile errored GLE=", ::GetLastError());
     throw TTransportException(TTransportException::UNKNOWN, "TPipe: read failed");
   }
 
   DWORD bytes = 0;
   result = ::GetOverlappedResult(pipe, &tempOverlap, &bytes, TRUE);
   if (!result) {
-    GlobalOutput.perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
+    TOutput::instance().perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
     throw TTransportException(TTransportException::UNKNOWN, "TPipe: GetOverlappedResult failed");
   }
   return bytes;
@@ -286,13 +286,13 @@
       break; // success!
 
     if (::GetLastError() != ERROR_PIPE_BUSY) {
-      GlobalOutput.perror("TPipe::open ::CreateFile errored GLE=", ::GetLastError());
+      TOutput::instance().perror("TPipe::open ::CreateFile errored GLE=", ::GetLastError());
       throw TTransportException(TTransportException::NOT_OPEN, "Unable to open pipe");
     }
   } while (::WaitNamedPipeA(pipename_.c_str(), TimeoutSeconds_ * 1000));
 
   if (hPipe.h == INVALID_HANDLE_VALUE) {
-    GlobalOutput.perror("TPipe::open ::CreateFile errored GLE=", ::GetLastError());
+    TOutput::instance().perror("TPipe::open ::CreateFile errored GLE=", ::GetLastError());
     throw TTransportException(TTransportException::NOT_OPEN, "Unable to open pipe");
   }
 
diff --git a/lib/cpp/src/thrift/transport/TPipeServer.cpp b/lib/cpp/src/thrift/transport/TPipeServer.cpp
index fd1aeee..a99ba3b 100644
--- a/lib/cpp/src/thrift/transport/TPipeServer.cpp
+++ b/lib/cpp/src/thrift/transport/TPipeServer.cpp
@@ -61,7 +61,7 @@
     // pass the handles on to the client before the serve (acceptImpl)
     // blocking call.
     if (!createAnonPipe()) {
-      GlobalOutput.perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
+      TOutput::instance().perror("TPipeServer Create(Anon)Pipe failed, GLE=", GetLastError());
       throw TTransportException(TTransportException::NOT_OPEN,
                                 " TPipeServer Create(Anon)Pipe failed");
     }
@@ -231,7 +231,7 @@
                           nullptr);    // not overlapped
 
   if (!fSuccess && GetLastError() != ERROR_MORE_DATA) {
-    GlobalOutput.perror("TPipeServer unable to initiate pipe comms, GLE=", GetLastError());
+    TOutput::instance().perror("TPipeServer unable to initiate pipe comms, GLE=", GetLastError());
     throw TTransportException(TTransportException::NOT_OPEN,
                               " TPipeServer unable to initiate pipe comms");
   }
@@ -243,7 +243,7 @@
   if (stopping_)
     return;
   if (!createNamedPipe(lockProof)) {
-    GlobalOutput.perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError());
+    TOutput::instance().perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError());
     throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer CreateNamedPipe failed");
   }
 
@@ -257,7 +257,7 @@
   // function returns a nonzero value. If the function returns
   // zero, GetLastError should return ERROR_PIPE_CONNECTED.
   if (connectOverlap_.success) {
-    GlobalOutput.printf("Client connected.");
+    TOutput::instance().printf("Client connected.");
     cached_client_.reset(new TPipe(Pipe_));
     // make sure people know that a connection is ready
     SetEvent(listen_event_.h);
@@ -267,7 +267,7 @@
   DWORD dwErr = connectOverlap_.last_error;
   switch (dwErr) {
   case ERROR_PIPE_CONNECTED:
-    GlobalOutput.printf("Client connected.");
+    TOutput::instance().printf("Client connected.");
     cached_client_.reset(new TPipe(Pipe_));
     // make sure people know that a connection is ready
     SetEvent(listen_event_.h);
@@ -275,7 +275,7 @@
   case ERROR_IO_PENDING:
     return; // acceptImpl will do the appropriate WaitForMultipleObjects
   default:
-    GlobalOutput.perror("TPipeServer ConnectNamedPipe failed, GLE=", dwErr);
+    TOutput::instance().perror("TPipeServer ConnectNamedPipe failed, GLE=", dwErr);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " TPipeServer ConnectNamedPipe failed");
   }
@@ -320,19 +320,19 @@
         throw;
       }
 
-      GlobalOutput.perror("Client connection failed. TTransportExceptionType=", ttx.getType());
+      TOutput::instance().perror("Client connection failed. TTransportExceptionType=", ttx.getType());
       // kick off the next connection before throwing
       initiateNamedConnect(lock);
       throw TTransportException(TTransportException::CLIENT_DISCONNECT, ttx.what());
     }
-    GlobalOutput.printf("Client connected.");
+    TOutput::instance().printf("Client connected.");
     // kick off the next connection before returning
     initiateNamedConnect(lock);
     return client; // success!
   }
   // if we got here, then we are in an error / shutdown case
   DWORD gle = GetLastError(); // save error before doing cleanup
-  GlobalOutput.perror("TPipeServer ConnectNamedPipe GLE=", gle);
+  TOutput::instance().perror("TPipeServer ConnectNamedPipe GLE=", gle);
   if(gle == ERROR_OPERATION_ABORTED) {
     TAutoCrit lock(pipe_protect_);    	// Needed to insure concurrent thread to be out of interrupt.
     throw TTransportException(TTransportException::INTERRUPTED, "TPipeServer: server interupted");
@@ -357,7 +357,7 @@
   if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(securityDescriptor_.c_str(),
                                                             SDDL_REVISION_1, &psd, &size)) {
     DWORD lastError = GetLastError();
-    GlobalOutput.perror("TPipeServer::ConvertStringSecurityDescriptorToSecurityDescriptorA() GLE=",
+    TOutput::instance().perror("TPipeServer::ConvertStringSecurityDescriptorToSecurityDescriptorA() GLE=",
                         lastError);
     throw TTransportException(
         TTransportException::NOT_OPEN,
@@ -387,7 +387,7 @@
 
   if (hPipe.h == INVALID_HANDLE_VALUE) {
     Pipe_.reset();
-    GlobalOutput.perror("TPipeServer::TCreateNamedPipe() GLE=", lastError);
+    TOutput::instance().perror("TPipeServer::TCreateNamedPipe() GLE=", lastError);
     throw TTransportException(TTransportException::NOT_OPEN, "TCreateNamedPipe() failed",
                               lastError);
   }
@@ -401,12 +401,12 @@
   SECURITY_DESCRIPTOR sd; // security information for pipes
 
   if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
-    GlobalOutput.perror("TPipeServer InitializeSecurityDescriptor (anon) failed, GLE=",
+    TOutput::instance().perror("TPipeServer InitializeSecurityDescriptor (anon) failed, GLE=",
                         GetLastError());
     return false;
   }
   if (!SetSecurityDescriptorDacl(&sd, true, nullptr, false)) {
-    GlobalOutput.perror("TPipeServer SetSecurityDescriptorDacl (anon) failed, GLE=",
+    TOutput::instance().perror("TPipeServer SetSecurityDescriptorDacl (anon) failed, GLE=",
                         GetLastError());
     return false;
   }
@@ -417,12 +417,12 @@
   HANDLE ClientAnonReadH, PipeW_H, ClientAnonWriteH, Pipe_H;
   if (!CreatePipe(&ClientAnonReadH, &PipeW_H, &sa, 0)) // create stdin pipe
   {
-    GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
+    TOutput::instance().perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
     return false;
   }
   if (!CreatePipe(&Pipe_H, &ClientAnonWriteH, &sa, 0)) // create stdout pipe
   {
-    GlobalOutput.perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
+    TOutput::instance().perror("TPipeServer CreatePipe (anon) failed, GLE=", GetLastError());
     CloseHandle(ClientAnonReadH);
     CloseHandle(PipeW_H);
     return false;
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.cpp b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
index f665fbd..6c0de08 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
@@ -386,14 +386,14 @@
       if (rc < 0) {
         string errors;
         buildErrors(errors, errno_copy, error);
-        GlobalOutput(("SSL_shutdown: " + errors).c_str());
+        TOutput::instance()(("SSL_shutdown: " + errors).c_str());
       }
     } catch (TTransportException& te) {
       // Don't emit an exception because this method is called by the
       // destructor. There's also not much that a user can do to recover, so
       // just clean up as much as possible without throwing, similar to the rc
       // < 0 case above.
-      GlobalOutput.printf("SSL_shutdown: %s", te.what());
+      TOutput::instance().printf("SSL_shutdown: %s", te.what());
     }
     SSL_free(ssl_);
     ssl_ = nullptr;
@@ -609,7 +609,7 @@
   int flags;
   if ((flags = THRIFT_FCNTL(socket_, THRIFT_F_GETFL, 0)) < 0
       || THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK) < 0) {
-    GlobalOutput.perror("thriftServerEventHandler: set THRIFT_O_NONBLOCK (THRIFT_FCNTL) ",
+    TOutput::instance().perror("thriftServerEventHandler: set THRIFT_O_NONBLOCK (THRIFT_FCNTL) ",
                         THRIFT_GET_SOCKET_ERROR);
     ::THRIFT_CLOSESOCKET(socket_);
     return;
@@ -865,7 +865,7 @@
       return TSSL_EINTR; // repeat operation
     }
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TSSLSocket::read THRIFT_POLL() ", errno_copy);
+    TOutput::instance().perror("TSSLSocket::read THRIFT_POLL() ", errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
   } else if (ret > 0){
     if (fds[1].revents & THRIFT_POLLIN) {
diff --git a/lib/cpp/src/thrift/transport/TServerSocket.cpp b/lib/cpp/src/thrift/transport/TServerSocket.cpp
index b0c9aeb..563f234 100644
--- a/lib/cpp/src/thrift/transport/TServerSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TServerSocket.cpp
@@ -228,7 +228,7 @@
     if (::THRIFT_STAT(path_.c_str(), &path_info) < 0) {
 #endif
       const std::string vError = "TServerSocket::isOpen(): The domain socket path '" + path_ + "' does not exist (yet).";
-      GlobalOutput.perror(vError.c_str(), THRIFT_GET_SOCKET_ERROR);
+      TOutput::instance().perror(vError.c_str(), THRIFT_GET_SOCKET_ERROR);
       return false;
     }
   }
@@ -291,7 +291,7 @@
       // of the Administrators security group on Windows XP and earlier. But
       // we do not target WinXP anymore so no special checks required.
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
+      TOutput::instance().perror("TServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
                           errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
@@ -308,7 +308,7 @@
                          cast_sockopt(&tcpSendBuffer_),
                          sizeof(tcpSendBuffer_))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
+      TOutput::instance().perror("TServerSocket::listen() setsockopt() SO_SNDBUF ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not set SO_SNDBUF",
@@ -323,7 +323,7 @@
                          cast_sockopt(&tcpRecvBuffer_),
                          sizeof(tcpRecvBuffer_))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
+      TOutput::instance().perror("TServerSocket::listen() setsockopt() SO_RCVBUF ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not set SO_RCVBUF",
@@ -335,7 +335,7 @@
   struct linger ling = {0, 0};
   if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&ling), sizeof(ling))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() setsockopt() SO_LINGER ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN, "Could not set SO_LINGER", errno_copy);
   }
@@ -343,7 +343,7 @@
 #ifdef SO_NOSIGPIPE
   if (-1 == setsockopt(serverSocket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() setsockopt() SO_NOSIGPIPE", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() setsockopt() SO_NOSIGPIPE", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not set SO_NOSIGPIPE",
@@ -355,7 +355,7 @@
   int flags = THRIFT_FCNTL(serverSocket_, THRIFT_F_GETFL, 0);
   if (flags == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "THRIFT_FCNTL() THRIFT_F_GETFL failed",
@@ -363,7 +363,7 @@
   }
   if (-1 == THRIFT_FCNTL(serverSocket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() THRIFT_FCNTL() THRIFT_O_NONBLOCK ", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() THRIFT_FCNTL() THRIFT_O_NONBLOCK ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "THRIFT_FCNTL() THRIFT_F_SETFL THRIFT_O_NONBLOCK failed",
@@ -382,7 +382,7 @@
   if (!isUnixDomainSocket()) {
     if (-1 == setsockopt(serverSocket_, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one, sizeof(one))) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_DEFER_ACCEPT ", errno_copy);
+      TOutput::instance().perror("TServerSocket::listen() setsockopt() TCP_DEFER_ACCEPT ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN, "Could not set TCP_DEFER_ACCEPT",
                                 errno_copy);
@@ -394,7 +394,7 @@
   if (-1
       == setsockopt(serverSocket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&one), sizeof(one))) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() setsockopt() TCP_NODELAY ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not set TCP_NODELAY",
@@ -410,7 +410,7 @@
   THRIFT_SOCKET sv[2];
   // Create the socket pair used to interrupt
   if (-1 == THRIFT_SOCKETPAIR(AF_LOCAL, SOCK_STREAM, 0, sv)) {
-    GlobalOutput.perror("TServerSocket::listen() socketpair() interrupt",
+    TOutput::instance().perror("TServerSocket::listen() socketpair() interrupt",
                         THRIFT_GET_SOCKET_ERROR);
     interruptSockWriter_ = THRIFT_INVALID_SOCKET;
     interruptSockReader_ = THRIFT_INVALID_SOCKET;
@@ -421,7 +421,7 @@
 
   // Create the socket pair used to interrupt all clients
   if (-1 == THRIFT_SOCKETPAIR(AF_LOCAL, SOCK_STREAM, 0, sv)) {
-    GlobalOutput.perror("TServerSocket::listen() socketpair() childInterrupt",
+    TOutput::instance().perror("TServerSocket::listen() socketpair() childInterrupt",
                         THRIFT_GET_SOCKET_ERROR);
     childInterruptSockWriter_ = THRIFT_INVALID_SOCKET;
     pChildInterruptSockReader_.reset();
@@ -448,7 +448,7 @@
                                  AI_PASSIVE | AI_V4MAPPED);
 #endif
     } catch (const std::system_error& e) {
-      GlobalOutput.printf("getaddrinfo() -> %d; %s", e.code().value(), e.what());
+      TOutput::instance().printf("getaddrinfo() -> %d; %s", e.code().value(), e.what());
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not resolve host for server socket.");
@@ -468,7 +468,7 @@
 
     if (serverSocket_ == THRIFT_INVALID_SOCKET) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::listen() socket() ", errno_copy);
+      TOutput::instance().perror("TServerSocket::listen() socket() ", errno_copy);
       close();
       throw TTransportException(TTransportException::NOT_OPEN,
                                 "Could not create server socket.",
@@ -492,7 +492,7 @@
       // use short circuit evaluation here to only sleep if we need to
     } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
 #else
-    GlobalOutput.perror("TServerSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
+    TOutput::instance().perror("TServerSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " Unix Domain socket path not supported");
 #endif
@@ -530,7 +530,7 @@
                              IPV6_V6ONLY,
                              cast_sockopt(&zero),
                              sizeof(zero))) {
-          GlobalOutput.perror("TServerSocket::listen() IPV6_V6ONLY ", THRIFT_GET_SOCKET_ERROR);
+          TOutput::instance().perror("TServerSocket::listen() IPV6_V6ONLY ", THRIFT_GET_SOCKET_ERROR);
         }
       }
 #endif // #ifdef IPV6_V6ONLY
@@ -552,7 +552,7 @@
     std::memset(&sa, 0, len);
     if (::getsockname(serverSocket_, reinterpret_cast<struct sockaddr*>(&sa), &len) < 0) {
       errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::getPort() getsockname() ", errno_copy);
+      TOutput::instance().perror("TServerSocket::getPort() getsockname() ", errno_copy);
     } else {
       if (sa.ss_family == AF_INET6) {
         const auto* sin = reinterpret_cast<const struct sockaddr_in6*>(&sa);
@@ -564,14 +564,14 @@
         const auto* sin = reinterpret_cast<const struct sockaddr_un*>(&sa);
         path_ = sin->sun_path;
       } else {
-        GlobalOutput.perror("TServerSocket::getPort() getsockname() unhandled socket type",EINVAL);
+        TOutput::instance().perror("TServerSocket::getPort() getsockname() unhandled socket type",EINVAL);
       }
     }
   }
 
   // throw error if socket still wasn't created successfully
   if (serverSocket_ == THRIFT_INVALID_SOCKET) {
-    GlobalOutput.perror("TServerSocket::listen() socket() ", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() socket() ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not create server socket.",
@@ -591,7 +591,7 @@
     } else {
       THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() Could not bind to port %d", port_);
     }
-    GlobalOutput(errbuf);
+    TOutput::instance()(errbuf);
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not bind",
@@ -604,7 +604,7 @@
   // Call listen
   if (boundSocketType_ == SocketType::NONE && -1 == ::listen(serverSocket_, acceptBacklog_)) {
     errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() listen() ", errno_copy);
+    TOutput::instance().perror("TServerSocket::listen() listen() ", errno_copy);
     close();
     throw TTransportException(TTransportException::NOT_OPEN, "Could not listen", errno_copy);
   }
@@ -657,14 +657,14 @@
         continue;
       }
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TServerSocket::acceptImpl() THRIFT_POLL() ", errno_copy);
+      TOutput::instance().perror("TServerSocket::acceptImpl() THRIFT_POLL() ", errno_copy);
       throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
     } else if (ret > 0) {
       // Check for an interrupt signal
       if (interruptSockReader_ != THRIFT_INVALID_SOCKET && (fds[1].revents & THRIFT_POLLIN)) {
         int8_t buf;
         if (-1 == recv(interruptSockReader_, cast_sockopt(&buf), sizeof(int8_t), 0)) {
-          GlobalOutput.perror("TServerSocket::acceptImpl() recv() interrupt ",
+          TOutput::instance().perror("TServerSocket::acceptImpl() recv() interrupt ",
                               THRIFT_GET_SOCKET_ERROR);
         }
         throw TTransportException(TTransportException::INTERRUPTED);
@@ -675,7 +675,7 @@
         break;
       }
     } else {
-      GlobalOutput("TServerSocket::acceptImpl() THRIFT_POLL 0");
+      TOutput::instance()("TServerSocket::acceptImpl() THRIFT_POLL 0");
       throw TTransportException(TTransportException::UNKNOWN);
     }
   }
@@ -687,7 +687,7 @@
 
   if (clientSocket == THRIFT_INVALID_SOCKET) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::acceptImpl() ::accept() ", errno_copy);
+    TOutput::instance().perror("TServerSocket::acceptImpl() ::accept() ", errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "accept()", errno_copy);
   }
 
@@ -696,7 +696,7 @@
   if (flags == -1) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     ::THRIFT_CLOSESOCKET(clientSocket);
-    GlobalOutput.perror("TServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
+    TOutput::instance().perror("TServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_GETFL ", errno_copy);
     throw TTransportException(TTransportException::UNKNOWN,
                               "THRIFT_FCNTL(THRIFT_F_GETFL)",
                               errno_copy);
@@ -705,7 +705,7 @@
   if (-1 == THRIFT_FCNTL(clientSocket, THRIFT_F_SETFL, flags & ~THRIFT_O_NONBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
     ::THRIFT_CLOSESOCKET(clientSocket);
-    GlobalOutput
+    TOutput::instance()
         .perror("TServerSocket::acceptImpl() THRIFT_FCNTL() THRIFT_F_SETFL ~THRIFT_O_NONBLOCK ",
                 errno_copy);
     throw TTransportException(TTransportException::UNKNOWN,
@@ -744,7 +744,7 @@
   if (notifySocket != THRIFT_INVALID_SOCKET) {
     int8_t byte = 0;
     if (-1 == send(notifySocket, cast_sockopt(&byte), sizeof(int8_t), 0)) {
-      GlobalOutput.perror("TServerSocket::notify() send() ", THRIFT_GET_SOCKET_ERROR);
+      TOutput::instance().perror("TServerSocket::notify() send() ", THRIFT_GET_SOCKET_ERROR);
     }
   }
 }
diff --git a/lib/cpp/src/thrift/transport/TSocket.cpp b/lib/cpp/src/thrift/transport/TSocket.cpp
index 97ca746..48953aa 100644
--- a/lib/cpp/src/thrift/transport/TSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSocket.cpp
@@ -197,7 +197,7 @@
     if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
       goto try_again;
     }
-    GlobalOutput.perror("TSocket::hasPendingDataToRead() THRIFT_IOCTL_SOCKET() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::hasPendingDataToRead() THRIFT_IOCTL_SOCKET() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
   }
   return numBytesAvailable > 0;
@@ -226,7 +226,7 @@
         if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
           continue;
         }
-        GlobalOutput.perror("TSocket::peek() THRIFT_POLL() ", errno_copy);
+        TOutput::instance().perror("TSocket::peek() THRIFT_POLL() ", errno_copy);
         throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
       } else if (ret > 0) {
         // Check the interruptListener
@@ -256,7 +256,7 @@
       return false;
     }
 #endif
-    GlobalOutput.perror("TSocket::peek() recv() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::peek() recv() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::UNKNOWN, "recv()", errno_copy);
   }
   return (r > 0);
@@ -276,7 +276,7 @@
 
   if (socket_ == THRIFT_INVALID_SOCKET) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TSocket::open() socket() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::open() socket() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, "socket()", errno_copy);
   }
 
@@ -320,13 +320,13 @@
   if (connTimeout_ > 0) {
     if (-1 == THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TSocket::open() THRIFT_FCNTL() " + getSocketInfo(), errno_copy);
+      TOutput::instance().perror("TSocket::open() THRIFT_FCNTL() " + getSocketInfo(), errno_copy);
       throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
     }
   } else {
     if (-1 == THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags & ~THRIFT_O_NONBLOCK)) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TSocket::open() THRIFT_FCNTL " + getSocketInfo(), errno_copy);
+      TOutput::instance().perror("TSocket::open() THRIFT_FCNTL " + getSocketInfo(), errno_copy);
       throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
     }
   }
@@ -342,7 +342,7 @@
 
     ret = connect(socket_, (struct sockaddr*)&address, structlen);
 #else
-    GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
+    TOutput::instance().perror("TSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " Unix Domain socket path not supported");
 #endif
@@ -358,7 +358,7 @@
   if ((THRIFT_GET_SOCKET_ERROR != THRIFT_EINPROGRESS)
       && (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TSocket::open() connect() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::open() connect() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, "connect() failed", errno_copy);
   }
 
@@ -376,25 +376,25 @@
     int ret2 = getsockopt(socket_, SOL_SOCKET, SO_ERROR, cast_sockopt(&val), &lon);
     if (ret2 == -1) {
       int errno_copy = THRIFT_GET_SOCKET_ERROR;
-      GlobalOutput.perror("TSocket::open() getsockopt() " + getSocketInfo(), errno_copy);
+      TOutput::instance().perror("TSocket::open() getsockopt() " + getSocketInfo(), errno_copy);
       throw TTransportException(TTransportException::NOT_OPEN, "getsockopt()", errno_copy);
     }
     // no errors on socket, go to town
     if (val == 0) {
       goto done;
     }
-    GlobalOutput.perror("TSocket::open() error on socket (after THRIFT_POLL) " + getSocketInfo(),
+    TOutput::instance().perror("TSocket::open() error on socket (after THRIFT_POLL) " + getSocketInfo(),
                         val);
     throw TTransportException(TTransportException::NOT_OPEN, "socket open() error", val);
   } else if (ret == 0) {
     // socket timed out
     string errStr = "TSocket::open() timed out " + getSocketInfo();
-    GlobalOutput(errStr.c_str());
+    TOutput::instance()(errStr.c_str());
     throw TTransportException(TTransportException::NOT_OPEN, "open() timed out");
   } else {
     // error on THRIFT_POLL()
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TSocket::open() THRIFT_POLL() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::open() THRIFT_POLL() " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_POLL() failed", errno_copy);
   }
 
@@ -402,7 +402,7 @@
   // Set socket back to normal mode (blocking)
   if (-1 == THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags)) {
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TSocket::open() THRIFT_FCNTL " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::open() THRIFT_FCNTL " + getSocketInfo(), errno_copy);
     throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
   }
 
@@ -473,7 +473,7 @@
   if (error) {
     string errStr = "TSocket::open() getaddrinfo() " + getSocketInfo()
                     + string(THRIFT_GAI_STRERROR(error));
-    GlobalOutput(errStr.c_str());
+    TOutput::instance()(errStr.c_str());
     close();
     throw TTransportException(TTransportException::NOT_OPEN,
                               "Could not resolve host for client socket.");
@@ -563,7 +563,7 @@
       if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
         goto try_again;
       }
-      GlobalOutput.perror("TSocket::read() THRIFT_POLL() ", errno_copy);
+      TOutput::instance().perror("TSocket::read() THRIFT_POLL() ", errno_copy);
       throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
     } else if (ret > 0) {
       // Check the interruptListener
@@ -571,7 +571,7 @@
         throw TTransportException(TTransportException::INTERRUPTED, "Interrupted");
       }
     } else /* ret == 0 */ {
-      GlobalOutput.printf("TSocket::read() THRIFT_EAGAIN (timed out) after %d ms", recvTimeout_);
+      TOutput::instance().printf("TSocket::read() THRIFT_EAGAIN (timed out) after %d ms", recvTimeout_);
       throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_EAGAIN (timed out)");
     }
 
@@ -630,7 +630,7 @@
     }
 
     // Now it's not a try again case, but a real probblez
-    GlobalOutput.perror("TSocket::read() recv() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::read() recv() " + getSocketInfo(), errno_copy);
 
     // Some other error, whatevz
     throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
@@ -675,7 +675,7 @@
     }
     // Fail on a send error
     int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TSocket::write_partial() send() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::write_partial() send() " + getSocketInfo(), errno_copy);
 
     if (errno_copy == THRIFT_EPIPE || errno_copy == THRIFT_ECONNRESET
         || errno_copy == THRIFT_ENOTCONN) {
@@ -737,7 +737,7 @@
   if (ret == -1) {
     int errno_copy
         = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
-    GlobalOutput.perror("TSocket::setLinger() setsockopt() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::setLinger() setsockopt() " + getSocketInfo(), errno_copy);
   }
 }
 
@@ -753,7 +753,7 @@
   if (ret == -1) {
     int errno_copy
         = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
-    GlobalOutput.perror("TSocket::setNoDelay() setsockopt() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::setNoDelay() setsockopt() " + getSocketInfo(), errno_copy);
   }
 }
 
@@ -765,7 +765,7 @@
   if (timeout_ms < 0) {
     char errBuf[512];
     sprintf(errBuf, "TSocket::setGenericTimeout with negative input: %d\n", timeout_ms);
-    GlobalOutput(errBuf);
+    TOutput::instance()(errBuf);
     return;
   }
 
@@ -783,7 +783,7 @@
   if (ret == -1) {
     int errno_copy
         = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
-    GlobalOutput.perror("TSocket::setGenericTimeout() setsockopt() ", errno_copy);
+    TOutput::instance().perror("TSocket::setGenericTimeout() setsockopt() ", errno_copy);
   }
 }
 
@@ -818,7 +818,7 @@
   if (ret == -1) {
     int errno_copy
         = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
-    GlobalOutput.perror("TSocket::setKeepAlive() setsockopt() " + getSocketInfo(), errno_copy);
+    TOutput::instance().perror("TSocket::setKeepAlive() setsockopt() " + getSocketInfo(), errno_copy);
   }
 }
 
diff --git a/lib/cpp/src/thrift/transport/TSocketPool.cpp b/lib/cpp/src/thrift/transport/TSocketPool.cpp
index f56c76e..5c3aa4e 100644
--- a/lib/cpp/src/thrift/transport/TSocketPool.cpp
+++ b/lib/cpp/src/thrift/transport/TSocketPool.cpp
@@ -79,7 +79,7 @@
     randomize_(true),
     alwaysTryLast_(true) {
   if (hosts.size() != ports.size()) {
-    GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
+    TOutput::instance()("TSocketPool::TSocketPool: hosts.size != ports.size");
     throw TTransportException(TTransportException::BAD_ARGS);
   }
 
@@ -229,7 +229,7 @@
           TSocket::open();
         } catch (const TException &e) {
           string errStr = "TSocketPool::open failed " + getSocketInfo() + ": " + e.what();
-          GlobalOutput(errStr.c_str());
+          TOutput::instance()(errStr.c_str());
           socket_ = THRIFT_INVALID_SOCKET;
           continue;
         }
@@ -251,7 +251,7 @@
     }
   }
 
-  GlobalOutput("TSocketPool::open: all connections failed");
+  TOutput::instance()("TSocketPool::open: all connections failed");
   throw TTransportException(TTransportException::NOT_OPEN);
 }
 
diff --git a/lib/cpp/src/thrift/transport/TZlibTransport.cpp b/lib/cpp/src/thrift/transport/TZlibTransport.cpp
index 657ce52..1a17110 100644
--- a/lib/cpp/src/thrift/transport/TZlibTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TZlibTransport.cpp
@@ -83,7 +83,7 @@
   if (status != Z_OK) {
     string output = "TZlibTransport: zlib failure in destructor: "
                     + TZlibTransportException::errorMessage(status, message);
-    GlobalOutput(output.c_str());
+    TOutput::instance()(output.c_str());
   }
 }
 
diff --git a/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp b/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp
index 02beec7..cbfd96f 100644
--- a/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp
+++ b/lib/cpp/src/thrift/windows/OverlappedSubmissionThread.cpp
@@ -52,7 +52,7 @@
   BOOL result = ::GetOverlappedResult(h, &overlap, &bytes, TRUE);
   if (signal_failure && !result) // get overlapped error case
   {
-    GlobalOutput.perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
+    TOutput::instance().perror("TPipe ::GetOverlappedResult errored GLE=", ::GetLastError());
     throw TTransportException(TTransportException::UNKNOWN, "TPipe: GetOverlappedResult failed");
   }
   return bytes;
@@ -113,7 +113,7 @@
   InitializeSListHead(&workList_);
   thread_ = (HANDLE)_beginthreadex(NULL, 0, thread_proc, this, 0, NULL);
   if (thread_ == 0) {
-    GlobalOutput.perror("TOverlappedSubmissionThread unable to create thread, errno=", errno);
+    TOutput::instance().perror("TOverlappedSubmissionThread unable to create thread, errno=", errno);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " TOverlappedSubmissionThread unable to create thread");
   }
diff --git a/lib/cpp/src/thrift/windows/Sync.h b/lib/cpp/src/thrift/windows/Sync.h
index e143b86..ab09925 100644
--- a/lib/cpp/src/thrift/windows/Sync.h
+++ b/lib/cpp/src/thrift/windows/Sync.h
@@ -76,7 +76,7 @@
   TAutoResetEvent() {
     h = CreateEvent(nullptr, FALSE, FALSE, nullptr);
     if (h == nullptr) {
-      GlobalOutput.perror("TAutoResetEvent unable to create event, GLE=", GetLastError());
+      TOutput::instance().perror("TAutoResetEvent unable to create event, GLE=", GetLastError());
       throw apache::thrift::concurrency::SystemResourceException("CreateEvent failed");
     }
   }
@@ -89,7 +89,7 @@
   TManualResetEvent() {
     h = CreateEvent(nullptr, TRUE, FALSE, nullptr);
     if (h == nullptr) {
-      GlobalOutput.perror("TManualResetEvent unable to create event, GLE=", GetLastError());
+      TOutput::instance().perror("TManualResetEvent unable to create event, GLE=", GetLastError());
       throw apache::thrift::concurrency::SystemResourceException("CreateEvent failed");
     }
   }
diff --git a/lib/cpp/test/processor/ServerThread.h b/lib/cpp/test/processor/ServerThread.h
index 9cca2d6..45c0906 100644
--- a/lib/cpp/test/processor/ServerThread.h
+++ b/lib/cpp/test/processor/ServerThread.h
@@ -91,7 +91,7 @@
       try {
         stop();
       } catch (...) {
-        GlobalOutput.printf("error shutting down server");
+        TOutput::instance().printf("error shutting down server");
       }
     }
   }