diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 83d380fafdbbea0b9db8dbca1181e1f8196e6229..4bf482711985728d286225dcac5a5649911d9abe 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -1155,8 +1155,25 @@ namespace
 }
 
 namespace {
-	LLMutex gLogMutex;
-	LLMutex gCallStacksLogMutex;
+	// We need a couple different mutexes, but we want to use the same mechanism
+	// for both. Make getMutex() a template function with different instances
+	// for different MutexDiscriminator values.
+	enum MutexDiscriminator
+	{
+		LOG_MUTEX,
+		STACKS_MUTEX
+	};
+	// Some logging calls happen very early in processing -- so early that our
+	// module-static variables aren't yet initialized. getMutex() wraps a
+	// function-static LLMutex so that early calls can still have a valid
+	// LLMutex instance.
+	template <MutexDiscriminator MTX>
+	LLMutex* getMutex()
+	{
+		// guaranteed to be initialized the first time control reaches here
+		static LLMutex sMutex;
+		return &sMutex;
+	}
 
 	bool checkLevelMap(const LevelMap& map, const std::string& key,
 						LLError::ELevel& level)
@@ -1204,7 +1221,7 @@ namespace LLError
 
 	bool Log::shouldLog(CallSite& site)
 	{
-		LLMutexTrylock lock(&gLogMutex, 5);
+		LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
 		if (!lock.isLocked())
 		{
 			return false;
@@ -1255,7 +1272,7 @@ namespace LLError
 
 	std::ostringstream* Log::out()
 	{
-		LLMutexTrylock lock(&gLogMutex,5);
+		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		// If we hit a logging request very late during shutdown processing,
 		// when either of the relevant LLSingletons has already been deleted,
 		// DO NOT resurrect them.
@@ -1275,7 +1292,7 @@ namespace LLError
 
 	void Log::flush(std::ostringstream* out, char* message)
 	{
-		LLMutexTrylock lock(&gLogMutex,5);
+		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		if (!lock.isLocked())
 		{
 			return;
@@ -1315,7 +1332,7 @@ namespace LLError
 
 	void Log::flush(std::ostringstream* out, const CallSite& site)
 	{
-		LLMutexTrylock lock(&gLogMutex,5);
+		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
 		if (!lock.isLocked())
 		{
 			return;
@@ -1514,7 +1531,7 @@ namespace LLError
    //static
    void LLCallStacks::push(const char* function, const int line)
    {
-       LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+       LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
        if (!lock.isLocked())
        {
            return;
@@ -1549,7 +1566,7 @@ namespace LLError
    //static
    void LLCallStacks::end(std::ostringstream* _out)
    {
-       LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+       LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
        if (!lock.isLocked())
        {
            return;
@@ -1565,13 +1582,13 @@ namespace LLError
 		   clear() ;
 	   }
 
-	   LLError::Log::flush(_out, sBuffer[sIndex++]) ;	   
+	   LLError::Log::flush(_out, sBuffer[sIndex++]) ;
    }
 
    //static
    void LLCallStacks::print()
    {
-       LLMutexTrylock lock(&gCallStacksLogMutex, 5);
+       LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);
        if (!lock.isLocked())
        {
            return;
@@ -1609,7 +1626,7 @@ namespace LLError
 
 bool debugLoggingEnabled(const std::string& tag)
 {
-    LLMutexTrylock lock(&gLogMutex, 5);
+    LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
     if (!lock.isLocked())
     {
         return false;