diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index 3e9ec14eb387a9c4d3d00826d40f4c520b2ee885..2ecda65d6f25335a27d97625db1840db1f4fba9c 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -30,6 +30,7 @@
 #include "stdtypes.h"
 #include "lldefs.h"
 #include "llerror.h"
+#include "llformat.h"
 #include "llstring.h"
 #include "lltimer.h"
 #include "llfasttimer.h"
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 87e7016f396ee0f62ec6f3a9d26db7da03073b0f..fe5587365cf06137b82157994b6dd95db4b5e83b 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -11,9 +11,11 @@
 
 #include "llcommon.h"
 #include "llapr.h"
+#include "llerrorcontrol.h"
 #include "llerrorthread.h"
 #include "llframetimer.h"
 #include "llmemory.h"
+#include "lltimer.h"
 
 //
 // Signal handling
@@ -174,10 +176,8 @@ LLSD LLApp::getOptionData(OptionPriority level)
 
 void LLApp::stepFrame()
 {
-	// Update the static frame timer.
 	LLFrameTimer::updateFrameTime();
-
-	// Run ready runnables
+	LLEventTimer::updateClass();
 	mRunner.run();
 }
 
@@ -544,7 +544,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
 		else
 		{
 			// Don't log anything, even errors - this is because this signal could happen anywhere.
-			gErrorStream.setLevel(LLErrorStream::NONE);
+			LLError::setDefaultLevel(LLError::LEVEL_NONE);
 		}
 		
 		// Change the signal that we reraise to SIGABRT, so we generate a core dump.
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 9f643fd9eb93dbb2896e0c8838a364a39706c41c..52b37bb05cd70ad05d927dac5420c7923fb0515c 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -1,40 +1,1041 @@
 /** 
  * @file llerror.cpp
- * @brief Function to crash.
+ * @date   December 2006
+ * @brief error message system
  *
- * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
  * $License$
  */
+
 #include "linden_common.h"
 
 #include "llerror.h"
+#include "llerrorcontrol.h"
+
+#include "llapr.h"
+extern apr_thread_mutex_t *gLogMutexp;
+#include "llfile.h"
+#include "llfixedbuffer.h"
+#include "lllivefile.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+
+#include <algorithm>
+#include <cctype>
+#include <map>
+#include <sstream>
+#if !LL_WINDOWS
+#include <stdio.h>
+#include <syslog.h>
+#endif
+#include <time.h>
+#if LL_WINDOWS
+#include <windows.h>
+#endif
+#include <vector>
+
+
+#ifdef __GNUC__
+#include <cxxabi.h>
+#endif
+
+namespace {
+#if !LL_WINDOWS
+	class RecordToSyslog : public LLError::Recorder
+	{
+	public:
+		RecordToSyslog(const std::string& identity)
+			: mIdentity(identity)
+		{
+			openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0);
+				// we need to set the string from a local copy of the string
+				// since apparanetly openlog expects the const char* to remain
+				// valid even after it returns (presumably until closelog)
+		}
+		
+		~RecordToSyslog()
+		{
+			closelog();
+		}
+		
+		virtual void recordMessage(LLError::ELevel level,
+									const std::string& message)
+		{
+			int syslogPriority = LOG_CRIT;
+			switch (level) {
+				case LLError::LEVEL_DEBUG:	syslogPriority = LOG_DEBUG;	break;
+				case LLError::LEVEL_INFO:	syslogPriority = LOG_INFO;	break;
+				case LLError::LEVEL_WARN:	syslogPriority = LOG_WARNING; break;
+				case LLError::LEVEL_ERROR:	syslogPriority = LOG_CRIT;	break;
+				default:					syslogPriority = LOG_CRIT;
+			}
+			
+			syslog(syslogPriority, "%s", message.c_str());
+		}
+	private:
+		std::string mIdentity;
+	};
+#endif
+
+	class RecordToFile : public LLError::Recorder
+	{
+	public:
+		RecordToFile(const std::string& filename)
+		{
+			mFile.open(filename.c_str(), llofstream::out | llofstream::app);
+			if (!mFile)
+			{
+				llinfos << "Error setting log file to " << filename << llendl;
+			}
+		}
+		
+		~RecordToFile()
+		{
+			mFile.close();
+		}
+		
+		bool okay() { return mFile; }
+		
+		virtual bool wantsTime() { return true; }
+		
+		virtual void recordMessage(LLError::ELevel level,
+									const std::string& message)
+		{
+			mFile << message << std::endl;
+			// mFile.flush();
+				// *FIX: should we do this? 
+		}
+	
+	private:
+		llofstream mFile;
+	};
+	
+	
+	class RecordToStderr : public LLError::Recorder
+	{
+	public:
+		RecordToStderr(bool timestamp) : mTimestamp(timestamp) { }
+
+		virtual bool wantsTime() { return mTimestamp; }
+		
+		virtual void recordMessage(LLError::ELevel level,
+									const std::string& message)
+		{
+			fprintf(stderr, "%s\n", message.c_str());
+		}
+	
+	private:
+		bool mTimestamp;
+	};
 
-LLErrorBuffer gErrorBuffer;
-LLErrorStream gErrorStream(&gErrorBuffer);
+	class RecordToFixedBuffer : public LLError::Recorder
+	{
+	public:
+		RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { }
+		
+		virtual void recordMessage(LLError::ELevel level,
+									const std::string& message)
+		{
+			mBuffer.addLine(message.c_str());
+		}
+	
+	private:
+		LLFixedBuffer& mBuffer;
+	};
+
+#if LL_WINDOWS
+	class RecordToWinDebug: public LLError::Recorder
+	{
+	public:
+		virtual void recordMessage(LLError::ELevel level,
+									const std::string& message)
+		{
+			llutf16string utf16str =
+				wstring_to_utf16str(utf8str_to_wstring(message));
+			utf16str += '\n';
+			OutputDebugString(utf16str.c_str());
+		}
+	};
+#endif
+}
 
 
-void _llcrash_and_loop()
+namespace
 {
-	// Now, we go kaboom!
-	U32* crash = NULL;
+	std::string className(const std::type_info& type)
+	{
+#ifdef __GNUC__
+		// GCC: type_info::name() returns a mangled class name, must demangle
+
+		static size_t abi_name_len = 100;
+		static char* abi_name_buf = (char*)malloc(abi_name_len);
+			// warning: above is voodoo inferred from the GCC manual,
+			// do NOT change
+
+		int status;
+			// We don't use status, and shouldn't have to pass apointer to it
+			// but gcc 3.3 libstc++'s implementation of demangling is broken
+			// and fails without.
+			
+		char* name = abi::__cxa_demangle(type.name(),
+										abi_name_buf, &abi_name_len, &status);
+			// this call can realloc the abi_name_buf pointer (!)
+
+		return name ? name : type.name();
+
+#elif LL_WINDOWS
+		// DevStudio: type_info::name() includes the text "class " at the start
+
+		static const std::string class_prefix = "class ";
+
+		std::string name = type.name();
+		std::string::size_type p = name.find(class_prefix);
+		if (p == std::string::npos)
+		{
+			return name;
+		}
+
+		return name.substr(p + class_prefix.size());
+
+#else		
+		return type.name();
+#endif
+	}
+
+	std::string functionName(const std::string& preprocessor_name)
+	{
+#if LL_WINDOWS
+		// DevStudio: the __FUNCTION__ macro string includes
+		// the type and/or namespace prefixes
+
+		std::string::size_type p = preprocessor_name.rfind(':');
+		if (p == std::string::npos)
+		{
+			return preprocessor_name;
+		}
+		return preprocessor_name.substr(p + 1);
+
+#else
+		return preprocessor_name;
+#endif
+	}
+
+
+	class LogControlFile : public LLLiveFile
+	{
+		LOG_CLASS(LogControlFile);
+	
+	public:
+		static LogControlFile& fromDirectory(const std::string& dir);
+		
+		virtual void loadFile();
+		
+	private:
+		LogControlFile(const std::string &filename)
+			: LLLiveFile(filename)
+			{ }
+	};
+
+	LogControlFile& LogControlFile::fromDirectory(const std::string& dir)
+	{
+		std::string dirBase = dir + "/";
+			// NB: We have no abstraction in llcommon  for the "proper"
+			// delimiter but it turns out that "/" works on all three platforms
+			
+		std::string file = dirBase + "logcontrol-dev.xml";
+		
+		llstat stat_info;
+		if (LLFile::stat(file.c_str(), &stat_info)) {
+			// NB: stat returns non-zero if it can't read the file, for example
+			// if it doesn't exist.  LLFile has no better abstraction for 
+			// testing for file existence.
+			
+			file = dirBase + "logcontrol.xml";
+		}
+		return * new LogControlFile(file);
+			// NB: This instance is never freed
+	}
+	
+	void LogControlFile::loadFile()
+	{
+		LLSD configuration;
+
+		{
+			llifstream file(filename().c_str());
+			if (file.is_open())
+			{
+				LLSDSerialize::fromXML(configuration, file);
+			}
+
+			if (configuration.isUndefined())
+			{
+				llwarns << filename() << " missing, ill-formed,"
+							" or simply undefined; not changing configuration"
+						<< llendl;
+				return;
+			}
+		}
+		
+		LLError::configure(configuration);
+		llwarns << "error logging reconfigured from " << filename() << llendl;
+	}
+
+
+	typedef std::map<std::string, LLError::ELevel> LevelMap;
+	typedef std::vector<LLError::Recorder*> Recorders;
+	typedef std::vector<LLError::CallSite*> CallSiteVector;
+
+	class Globals
+	{
+	public:
+		std::ostringstream messageStream;
+		bool messageStreamInUse;
+
+		void addCallSite(LLError::CallSite&);
+		void invalidateCallSites();
+		
+		static Globals& get();
+			// return the one instance of the globals
+
+	private:
+		CallSiteVector callSites;
+
+		Globals()
+			:	messageStreamInUse(false)
+			{ }
+		
+	};
+
+	void Globals::addCallSite(LLError::CallSite& site)
+	{
+		callSites.push_back(&site);
+	}
+	
+	void Globals::invalidateCallSites()
+	{
+		for (CallSiteVector::const_iterator i = callSites.begin();
+			 i != callSites.end();
+			 ++i)
+		{
+			(*i)->invalidate();
+		}
+		
+		callSites.clear();
+	}
 
-	*crash = 0;
+	Globals& Globals::get()
+	{
+		/* This pattern, of returning a reference to a static function
+		   variable, is to ensure that this global is constructed before
+		   it is used, no matter what the global initializeation sequence
+		   is.
+		   See C++ FAQ Lite, sections 10.12 through 10.14
+		*/
+		static Globals* globals = new Globals;		
+		return *globals;
+	}
+}
+
+namespace LLError
+{
+	class Settings
+	{
+	public:
+		bool printLocation;
 
-	while(TRUE)
+		LLError::ELevel defaultLevel;
+		
+		LevelMap functionLevelMap;
+		LevelMap classLevelMap;
+		LevelMap fileLevelMap;
+		
+		LLError::FatalFunction crashFunction;
+		LLError::TimeFunction timeFunction;
+		
+		Recorders recorders;
+		Recorder* fileRecorder;
+		Recorder* fixedBufferRecorder;
+		std::string fileRecorderFileName;
+		
+		int shouldLogCallCounter;
+		
+		static Settings& get();
+	
+		static void reset();
+		static Settings* saveAndReset();
+		static void restore(Settings*);
+		
+	private:
+		Settings()
+			:	printLocation(false),
+				defaultLevel(LLError::LEVEL_DEBUG),
+				crashFunction(NULL),
+				timeFunction(NULL),
+				fileRecorder(NULL),
+				fixedBufferRecorder(NULL),
+				shouldLogCallCounter(0)
+			{ }
+		
+		static Settings*& getPtr();
+	};
+	
+	Settings& Settings::get()
+	{
+		Settings* p = getPtr();
+		if (!p)
+		{
+			reset();
+			p = getPtr();
+		}
+		return *p;
+	}
+	
+	void Settings::reset()
+	{
+		Globals::get().invalidateCallSites();
+		
+		Settings*& p = getPtr();
+		delete p;
+		p = new Settings();
+	}
+	
+	Settings* Settings::saveAndReset()
+	{
+		Globals::get().invalidateCallSites();
+		
+		Settings*& p = getPtr();
+		Settings* originalSettings = p;
+		p = new Settings();
+		return originalSettings;
+	}
+	
+	void Settings::restore(Settings* originalSettings)
 	{
+		Globals::get().invalidateCallSites();
+		
+		Settings*& p = getPtr();
+		delete p;
+		p = originalSettings;
+	}
 	
-		// Loop forever, in case the crash didn't work?
+	Settings*& Settings::getPtr()
+	{
+		static Settings* currentSettings = NULL;
+		return currentSettings;
 	}
 }
 
-LLScopedErrorLevel::LLScopedErrorLevel(LLErrorBuffer::ELevel error_level)
+namespace LLError
 {
-	mOrigErrorLevel = gErrorStream.getErrorLevel();
-	gErrorStream.setErrorLevel(error_level);
+	CallSite::CallSite(ELevel level,
+					const char* file, int line,
+					const std::type_info& class_info, const char* function)
+		: mLevel(level), mFile(file), mLine(line),
+		  mClassInfo(class_info), mFunction(function),
+		  mCached(false), mShouldLog(false)
+		{ }
+
+
+	void CallSite::invalidate()
+		{ mCached = false; }
 }
 
+namespace
+{
+	bool shouldLogToStderr()
+	{
+#if LL_DARWIN
+		// On Mac OS X, stderr from apps launched from the Finder goes to the
+		// console log.  It's generally considered bad form to spam too much
+		// there.
+		
+		// If stdin is a tty, assume the user launched from the command line and
+		// therefore wants to see stderr.  Otherwise, assume we've been launched
+		// from the finder and shouldn't spam stderr.
+		return isatty(0);
+#else
+		return true;
+#endif
+	}
+	
+	bool stderrLogWantsTime()
+	{
+#if LL_WINDOWS
+		return false;
+#else
+		return true;
+#endif
+	}
+	
+	
+	void commonInit(const std::string& dir)
+	{
+		LLError::Settings::reset();
+		
+		LLError::setDefaultLevel(LLError::LEVEL_INFO);
+		LLError::setFatalFunction(LLError::crashAndLoop);
+		LLError::setTimeFunction(LLError::utcTime);
+
+		if (shouldLogToStderr())
+		{
+			LLError::addRecorder(new RecordToStderr(stderrLogWantsTime()));
+		}
+		
+#if LL_WINDOWS
+		LLError::addRecorder(new RecordToWinDebug);
+#endif
+
+		LogControlFile& e = LogControlFile::fromDirectory(dir);
+		e.addToEventTimer();
+	}
+}
 
-LLScopedErrorLevel::~LLScopedErrorLevel()
+namespace LLError
 {
-	gErrorStream.setErrorLevel(mOrigErrorLevel);
+	void initForServer(const std::string& identity)
+	{
+		std::string dir = LLApp::instance()->getOption("configdir");
+		commonInit(dir);
+#if !LL_WINDOWS
+		addRecorder(new RecordToSyslog(identity));
+#endif
+	}
+
+	void initForApplication(const std::string& dir)
+	{
+		commonInit(dir);
+	}
+
+	void setPrintLocation(bool print)
+	{
+		Settings& s = Settings::get();
+		s.printLocation = print;
+	}
+
+	void setFatalFunction(FatalFunction f)
+	{
+		Settings& s = Settings::get();
+		s.crashFunction = f;
+	}
+
+	void setTimeFunction(TimeFunction f)
+	{
+		Settings& s = Settings::get();
+		s.timeFunction = f;
+	}
+
+	void setDefaultLevel(ELevel level)
+	{
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+		g.invalidateCallSites();
+		s.defaultLevel = level;
+	}
+
+	void setFunctionLevel(const std::string& function_name, ELevel level)
+	{
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+		g.invalidateCallSites();
+		s.functionLevelMap[function_name] = level;
+	}
+
+	void setClassLevel(const std::string& class_name, ELevel level)
+	{
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+		g.invalidateCallSites();
+		s.classLevelMap[class_name] = level;
+	}
+
+	void setFileLevel(const std::string& file_name, ELevel level)
+	{
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+		g.invalidateCallSites();
+		s.fileLevelMap[file_name] = level;
+	}
 }
+
+namespace {
+	LLError::ELevel decodeLevel(std::string name)
+	{
+		static LevelMap level_names;
+		if (level_names.empty())
+		{
+			level_names["ALL"]		= LLError::LEVEL_ALL;
+			level_names["DEBUG"]	= LLError::LEVEL_DEBUG;
+			level_names["INFO"]		= LLError::LEVEL_INFO;
+			level_names["WARN"]		= LLError::LEVEL_WARN;
+			level_names["ERROR"]	= LLError::LEVEL_ERROR;
+			level_names["NONE"]		= LLError::LEVEL_NONE;
+		}
+		
+		std::transform(name.begin(), name.end(), name.begin(), toupper);
+		
+		LevelMap::const_iterator i = level_names.find(name);
+		if (i == level_names.end())
+		{
+			llwarns << "unrecognized logging level: '" << name << "'" << llendl;
+			return LLError::LEVEL_INFO;
+		}
+		
+		return i->second;
+	}
+	
+	void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level)
+	{
+		LLSD::array_const_iterator i, end;
+		for (i = list.beginArray(), end = list.endArray(); i != end; ++i)
+		{
+			map[*i] = level;
+		}
+	}
+}
+
+namespace LLError
+{
+	void configure(const LLSD& config)
+	{
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+		
+		g.invalidateCallSites();
+		s.functionLevelMap.clear();
+		s.classLevelMap.clear();
+		s.fileLevelMap.clear();
+		
+		setPrintLocation(config["print-location"]);
+		setDefaultLevel(decodeLevel(config["default-level"]));
+		
+		LLSD sets = config["settings"];
+		LLSD::array_const_iterator a, end;
+		for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a)
+		{
+			const LLSD& entry = *a;
+			
+			ELevel level = decodeLevel(entry["level"]);
+			
+			setLevels(s.functionLevelMap,	entry["functions"],	level);
+			setLevels(s.classLevelMap,		entry["classes"],	level);
+			setLevels(s.fileLevelMap,		entry["files"],		level);
+		}
+	}
+}
+
+
+namespace LLError
+{
+	Recorder::~Recorder()
+		{ }
+
+	// virtual
+	bool Recorder::wantsTime()
+		{ return false; }
+
+
+
+	void addRecorder(Recorder* recorder)
+	{
+		if (recorder == NULL)
+		{
+			return;
+		}
+		Settings& s = Settings::get();
+		s.recorders.push_back(recorder);
+	}
+
+	void removeRecorder(Recorder* recorder)
+	{
+		if (recorder == NULL)
+		{
+			return;
+		}
+		Settings& s = Settings::get();
+		s.recorders.erase(
+			std::remove(s.recorders.begin(), s.recorders.end(), recorder),
+			s.recorders.end());
+	}
+}
+
+namespace LLError
+{
+	void logToFile(const std::string& file_name)
+	{
+		LLError::Settings& s = LLError::Settings::get();
+
+		removeRecorder(s.fileRecorder);
+		delete s.fileRecorder;
+		s.fileRecorder = NULL;
+		s.fileRecorderFileName.clear();
+		
+		if (file_name.empty())
+		{
+			return;
+		}
+		
+		RecordToFile* f = new RecordToFile(file_name);
+		if (!f->okay())
+		{
+			delete f;
+			return;
+		}
+
+		s.fileRecorderFileName = file_name;
+		s.fileRecorder = f;
+		addRecorder(f);
+	}
+	
+	void logToFixedBuffer(LLFixedBuffer* fixedBuffer)
+	{
+		LLError::Settings& s = LLError::Settings::get();
+
+		removeRecorder(s.fixedBufferRecorder);
+		delete s.fixedBufferRecorder;
+		s.fixedBufferRecorder = NULL;
+		
+		if (!fixedBuffer)
+		{
+			return;
+		}
+		
+		s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer);
+		addRecorder(s.fixedBufferRecorder);
+	}
+
+	std::string logFileName()
+	{
+		LLError::Settings& s = LLError::Settings::get();
+		return s.fileRecorderFileName;
+	}
+}
+
+namespace
+{
+	void writeToRecorders(LLError::ELevel level, const std::string& message)
+	{
+		LLError::Settings& s = LLError::Settings::get();
+	
+		std::string messageWithTime;
+		
+		for (Recorders::const_iterator i = s.recorders.begin();
+			i != s.recorders.end();
+			++i)
+		{
+			LLError::Recorder* r = *i;
+			
+			if (r->wantsTime()  &&  s.timeFunction != NULL)
+			{
+				if (messageWithTime.empty())
+				{
+					messageWithTime = s.timeFunction() + " " + message;
+				}
+				
+				r->recordMessage(level, messageWithTime);
+			}
+			else
+			{
+				r->recordMessage(level, message);
+			}
+		}
+	}
+}
+
+
+/*
+Recorder formats:
+
+$type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG"
+$loc = "$file($line)"
+$msg = "$loc : " if FATAL or printing loc
+		"" otherwise
+$msg += "$type: "
+$msg += contents of stringstream
+
+$time = "%Y-%m-%dT%H:%M:%SZ" if UTC
+	 or "%Y-%m-%dT%H:%M:%S %Z" if local
+
+syslog:	"$msg"
+file: "$time $msg\n"
+stderr: "$time $msg\n" except on windows, "$msg\n"
+fixedbuf: "$msg"
+winddebug: "$msg\n"
+
+Note: if FATAL, an additional line gets logged first, with $msg set to
+	"$loc : error"
+	
+You get:
+	llfoo.cpp(42) : error
+	llfoo.cpp(42) : ERROR: something
+	
+*/
+
+namespace {
+	bool checkLevelMap(const LevelMap& map, const std::string& key,
+						LLError::ELevel& level)
+	{
+		LevelMap::const_iterator i = map.find(key);
+		if (i == map.end())
+		{
+			return false;
+		}
+		
+		level = i->second;
+		return true;
+	}
+	
+	class LogLock
+	{
+	public:
+		LogLock();
+		~LogLock();
+		bool ok() const { return mOK; }
+	private:
+		bool mLocked;
+		bool mOK;
+	};
+	
+	LogLock::LogLock()
+		: mLocked(false), mOK(false)
+	{
+		if (!gLogMutexp)
+		{
+			mOK = true;
+			return;
+		}
+		
+		const int MAX_RETRIES = 5;
+		for (int attempts = 0; attempts < MAX_RETRIES; ++attempts)
+		{
+			apr_status_t s = apr_thread_mutex_trylock(gLogMutexp);
+			if (!APR_STATUS_IS_EBUSY(s))
+			{
+				mLocked = true;
+				mOK = true;
+				return;
+			}
+
+			ms_sleep(1);
+			//apr_thread_yield();
+				// Just yielding won't necessarily work, I had problems with
+				// this on Linux - doug 12/02/04
+		}
+
+		// We're hosed, we can't get the mutex.  Blah.
+		std::cerr << "LogLock::LogLock: failed to get mutex for log"
+					<< std::endl;
+	}
+	
+	LogLock::~LogLock()
+	{
+		if (mLocked)
+		{
+			apr_thread_mutex_unlock(gLogMutexp);
+		}
+	}
+}
+
+namespace LLError
+{
+	bool Log::shouldLog(CallSite& site)
+	{
+		LogLock lock;
+		if (!lock.ok())
+		{
+			return false;
+		}
+		
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+		
+		s.shouldLogCallCounter += 1;
+		
+		std::string class_name = className(site.mClassInfo);
+		std::string function_name = functionName(site.mFunction);
+		if (site.mClassInfo != typeid(NoClassInfo))
+		{
+			function_name = class_name + "::" + function_name;
+		}
+
+		ELevel compareLevel = s.defaultLevel;
+
+		checkLevelMap(s.functionLevelMap, function_name, compareLevel)
+		|| checkLevelMap(s.classLevelMap, class_name, compareLevel)
+		|| checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel);
+
+		site.mCached = true;
+		g.addCallSite(site);
+		return site.mShouldLog = site.mLevel >= compareLevel;
+	}
+
+
+	std::ostringstream* Log::out()
+	{
+		LogLock lock;
+		if (lock.ok())
+		{
+			Globals& g = Globals::get();
+
+			if (!g.messageStreamInUse)
+			{
+				g.messageStreamInUse = true;
+				return &g.messageStream;
+			}
+		}
+		
+		return new std::ostringstream;
+	}
+
+	void Log::flush(std::ostringstream* out, const CallSite& site)
+	{
+		LogLock lock;
+		if (!lock.ok())
+		{
+			return;
+		}
+		
+		Globals& g = Globals::get();
+		Settings& s = Settings::get();
+
+		std::string message = out->str();
+		if (out == &g.messageStream)
+		{
+			g.messageStream.clear();
+			g.messageStream.str("");
+			g.messageStreamInUse = false;
+		}
+		else
+		{
+			delete out;
+		}
+
+		if (site.mLevel == LEVEL_ERROR)
+		{
+			std::ostringstream fatalMessage;
+			fatalMessage << abbreviateFile(site.mFile)
+						<< "(" << site.mLine << ") : error";
+			
+			writeToRecorders(site.mLevel, fatalMessage.str());
+		}
+		
+		
+		std::ostringstream prefix;
+
+		switch (site.mLevel)
+		{
+			case LEVEL_DEBUG:		prefix << "DEBUG: ";	break;
+			case LEVEL_INFO:		prefix << "INFO: ";		break;
+			case LEVEL_WARN:		prefix << "WARNING: ";	break;
+			case LEVEL_ERROR:		prefix << "ERROR: ";	break;
+			default:				prefix << "XXX: ";		break;
+		};
+		
+		if (s.printLocation)
+		{
+			prefix << abbreviateFile(site.mFile)
+					<< "(" << site.mLine << ") : ";
+		}
+		
+		if (message.find(functionName(site.mFunction)) == std::string::npos)
+		{
+	#if LL_WINDOWS
+			// DevStudio: __FUNCTION__ already includes the full class name
+	#else
+			if (site.mClassInfo != typeid(NoClassInfo))
+			{
+				prefix << className(site.mClassInfo) << "::";
+			}
+	#endif
+			prefix << site.mFunction << ": ";
+		}
+		
+		prefix << message;
+		message = prefix.str();
+		
+		writeToRecorders(site.mLevel, message);
+		
+		if (site.mLevel == LEVEL_ERROR  &&  s.crashFunction)
+		{
+			s.crashFunction(message);
+		}
+	}
+}
+
+
+
+
+namespace LLError
+{
+	Settings* saveAndResetSettings()
+	{
+		return Settings::saveAndReset();
+	}
+	
+	void restoreSettings(Settings* s)
+	{
+		return Settings::restore(s);
+	}
+
+	std::string removePrefix(std::string& s, const std::string& p)
+	{
+		std::string::size_type where = s.find(p);
+		if (where == std::string::npos)
+		{
+			return s;
+		}
+		
+		return std::string(s, where + p.size());
+	}
+	
+	std::string abbreviateFile(const std::string& filePath)
+	{
+		std::string f = filePath;
+
+#if LL_WINDOWS
+		static std::string indra_prefix = "indra\\";
+#else
+		static std::string indra_prefix = "indra/";
+#endif
+		f = removePrefix(f, indra_prefix);
+
+#if LL_DARWIN
+		static std::string newview_prefix = "newview/../";
+		f = removePrefix(f, newview_prefix);
+#endif
+
+		return f;
+	}
+
+	int shouldLogCallCount()
+	{
+		Settings& s = Settings::get();
+		return s.shouldLogCallCounter;
+	}
+
+	void crashAndLoop(const std::string& message)
+	{
+		// Now, we go kaboom!
+		int* crash = NULL;
+
+		*crash = 0;
+
+		while(true)
+		{
+			// Loop forever, in case the crash didn't work?
+		}
+	}
+
+	std::string utcTime()
+	{
+		time_t now = time(NULL);
+		const size_t BUF_SIZE = 64;
+		char time_str[BUF_SIZE];	/* Flawfinder: ignore */
+		
+		int chars = strftime(time_str, BUF_SIZE, 
+								  "%Y-%m-%dT%H:%M:%SZ",
+								  gmtime(&now));
+
+		return chars ? time_str : "time error";
+	}
+}
+
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index d3d680ed3306452ceeb05bc43d7abb3686ac749e..84ac0fa7f08a8b29d9ae540cd18a3b6b5f0e9f43 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -1,8 +1,9 @@
 /** 
  * @file llerror.h
- * @brief Constants, functions, and macros for logging and runtime errors.
+ * @date   December 2006
+ * @brief error message system
  *
- * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
  * $License$
  */
 
@@ -10,209 +11,208 @@
 #define LL_LLERROR_H
 
 #include <sstream>
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "llerrorstream.h"
-#include "llerrorbuffer.h"
-
-// Specific error codes
-const S32 LL_ERR_NOERR = 0;
-const S32 LL_ERR_ASSET_REQUEST_FAILED = -1;
-//const S32 LL_ERR_ASSET_REQUEST_INVALID = -2;
-const S32 LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
-const S32 LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
-const S32 LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
-const S32 LL_ERR_EOF = -39;
-const S32 LL_ERR_CANNOT_OPEN_FILE = -42;
-const S32 LL_ERR_FILE_NOT_FOUND = -43;
-const S32 LL_ERR_FILE_EMPTY     = -44;
-const S32 LL_ERR_TCP_TIMEOUT    = -23016;
-const S32 LL_ERR_CIRCUIT_GONE   = -23017;
-
-// Error types
-
-#define LLERR_IMAGE				(1 << 1) // Image requests
-#define LLERR_MESSAGE			(1 << 2) // Messaging
-#define LLERR_PERF				(1 << 3) // Performance
-#define LLERR_SQL				(1 << 4) // SQL statements
-#define LLERR_DOUG				(1 << 5) // Doug's debugging
-#define LLERR_USER_INPUT		(1 << 6) // Keyboard and mouse
-#define LLERR_TIMING			(1 << 7) // Verbose time info
-#define LLERR_TASK				(1 << 8) // Tracking tasks
-#define LLERR_MSG_HANDLER		(1 << 9) //
-#define LLERR_CIRCUIT_INFO		(1 << 10) // Message system circuit info
-#define LLERR_PHYSICS			(1 << 11) // physics
-#define LLERR_VFS				(1 << 12) // VFS
-const U32 LLERR_ALL = 0xffff;
-const U32 LLERR_NONE = 0x0;
-
-// Define one of these for different error levels in release...
-// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output.
-#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output
-#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output.
-
-
-//////////////////////////////////////////
-//
-//  Implementation - ignore
-//
-//
-#ifdef _DEBUG
-#define SHOW_DEBUG
-#define SHOW_WARN
-#define SHOW_INFO
-#define SHOW_ASSERT
-#else // _DEBUG
-
-#ifdef RELEASE_SHOW_DEBUG
-#define SHOW_DEBUG
-#endif
-
-#ifdef RELEASE_SHOW_WARN
-#define SHOW_WARN
-#endif
-
-#ifdef RELEASE_SHOW_INFO
-#define SHOW_INFO
-#endif
-
-#ifdef RELEASE_SHOW_ASSERT
-#define SHOW_ASSERT
-#endif
-
-#endif // _DEBUG
-
-
-extern LLErrorStream gErrorStream;
-
-
-// LL Error macros
-//
-// Usage:
-//
-// llerrs << "An error, oh my!" << variable << endl;
-// llwarns << "Another error, fuck me!" << variable << endl;
-// llwarnst(LLERR_IMAGE) << "Debug, mother fucker" << endl;
-//
-// NOTE: The output format of filename(lineno): is so that MS DevStudio
-// can parse the output and automatically jump to that location
-
-inline std::string llerrno_string(int errnum)
+#include <typeinfo>
+
+#include "llerrorlegacy.h"
+
+
+/* Error Logging Facility
+
+	Information for most users:
+	
+	Code can log messages with constuctions like this:
+	
+		llinfos << "request to fizzbip agent " << agent_id
+			<< " denied due to timeout" << llendl;
+		
+	Messages can be logged to one of four increasing levels of concern,
+	using one of four "streams":
+
+		lldebugs	- debug messages that are normally supressed
+		llinfos		- informational messages that are normall shown
+		llwarns		- warning messages that singal a problem
+		llerrs		- error messages that are major, unrecoverable failures
+		
+	The later (llerrs) automatically crashes the process after the message
+	is logged.
+	
+	Note that these "streams" are actually #define magic.  Rules for use:
+		* they cannot be used as normal streams, only to start a message
+		* messages written to them MUST be terminated with llendl
+		* between the opening and closing, the << operator is indeed
+		  writing onto a std::ostream, so all conversions and stream
+		  formating are available
+	
+	These messages are automatically logged with function name, and (if enabled)
+	file and line of the message.  (Note: Existing messages that already include
+	the function name don't get name printed twice.)
+	
+	If you have a class, adding LOG_CLASS line to the declaration will cause
+	all messages emitted from member functions (normal and static) to be tagged
+	with the proper class name as well as the function name:
+	
+		class LLFoo
+		{
+			LOG_CLASS(LLFoo);
+		public:
+			...
+		};
+	
+		void LLFoo::doSomething(int i)
+		{
+			if (i > 100)
+			{
+				llwanrs << "called with a big value for i: " << i << llendl; 
+			}
+			...
+		}
+	
+	will result in messages like:
+	
+		WARN: LLFoo::doSomething: called with a big value for i: 283
+	
+	Which messages are logged and which are supressed can be controled at run
+	time from the live file logcontrol.xml based on function, class and/or 
+	source file.  See etc/logcontrol-dev.xml for details.
+	
+	Lastly, logging is now very efficient in both compiled code and execution
+	when skipped.  There is no need to wrap messages, even debugging ones, in
+	#ifdef _DEBUG constructs.  lldebugs messages are compiled into all builds,
+	even release.  Which means you can use them to help debug even when deployed
+	to a real grid.
+*/
+
+namespace LLError
 {
-	std::stringstream res;
-	res << "error(" << errnum << "):" << strerror(errnum) << " ";
-	return res.str();
+	enum ELevel
+	{
+		LEVEL_ALL = 0,
+			// used to indicate that all messagess should be logged
+			
+		LEVEL_DEBUG = 0,
+		LEVEL_INFO = 1,
+		LEVEL_WARN = 2,
+		LEVEL_ERROR = 3,	// used to be called FATAL
+		
+		LEVEL_NONE = 4
+			// not really a level
+			// used to indicate that no messages should be logged
+	};
+	
+	/*	Macro support
+		The classes CallSite and Log are used by the logging macros below.
+		They are not intended for general use.
+	*/
+	
+	class CallSite;
+	
+	class Log
+	{
+	public:
+		static bool shouldLog(CallSite&);
+		static std::ostringstream* out();
+		static void flush(std::ostringstream*, const CallSite&);
+	};
+	
+	class CallSite
+	{
+		// Represents a specific place in the code where a message is logged
+		// This is public because it is used by the macros below.  It is not
+		// intended for public use.
+	public:
+		CallSite(ELevel, const char* file, int line,
+				const std::type_info& class_info, const char* function);
+						
+		bool shouldLog()
+			{ return mCached ? mShouldLog : Log::shouldLog(*this); }
+			// this member function needs to be in-line for efficiency
+		
+		void invalidate();
+		
+	private:
+		// these describe the call site and never change
+		const ELevel			mLevel;
+		const char* const		mFile;
+		const int				mLine;
+		const std::type_info&	mClassInfo;
+		const char* const		mFunction;
+		
+		// these implement a cache of the call to shouldLog()
+		bool mCached;
+		bool mShouldLog;
+		
+		friend class Log;
+	};
+	
+	
+	class End { };
+	inline std::ostream& operator<<(std::ostream& s, const End&)
+		{ return s; }
+		// used to indicate the end of a message
+		
+	class NoClassInfo { };
+		// used to indicate no class info known for logging
 }
 
-inline std::string llerror_file_line(const char* file, S32 line)
-{
-	std::stringstream res;
-	res << file << "(" <<line << ")";
-	return res.str();
-}
 
-// Used to throw an error which is always causes a system halt.
-#define llerrs if (gErrorStream.isEnabledFor(LLErrorBuffer::FATAL)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::FATAL; \
-		llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : error\n"; \
-		llerror_oss <<  "ERROR: " << llerror_file_line(__FILE__, __LINE__) << " "
-
-// Used to show warnings
-#define llwarns if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \
-		if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : WARNING: "; \
-		else llerror_oss << "WARNING: "; \
-		llerror_oss
-
-// Alerts are for serious non-fatal situations that are not supposed to happen and need to alert someone
-#define llalerts if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \
-		if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : ALERT: "; \
-		else llerror_oss << "ALERT: ";  \
-		llerror_oss
-
-// Used to show informational messages that don't get disabled
-#define llinfos if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \
-		if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \
-		else llerror_oss << "INFO: ";  \
-		llerror_oss
-
-#define llinfost(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO, type)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \
-		if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \
-		else llerror_oss << "INFO: [" << #type << "] ";  \
-		llerror_oss
- 
-// Used for general debugging output
-#define lldebugs if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \
-		if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \
-		else llerror_oss << "DEBUG: ";  \
-		llerror_oss
-
-#define lldebugst(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG, type)) \
-	{	std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \
-		if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \
-		else llerror_oss << "DEBUG: [" << #type << "] ";  \
-		llerror_oss
-
-#define llendl std::endl; gErrorStream.crashOnError(llerror_oss, llerror_level); }
-#define llendflush std::endl << std::flush; gErrorStream.crashOnError(llerror_oss, llerror_level); }
-#define llcont llerror_oss
-
-#define llerror(msg, num)		llerrs << "Error # " << num << ": " << msg << llendl;
-
-#define llwarning(msg, num)		llwarns << "Warning # " << num << ": " << msg << llendl;
-
-#ifdef SHOW_ASSERT
-#define llassert(func)			if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
-#else
-#define llassert(func)
-#endif
-#define llassert_always(func)	if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
-
-#ifdef SHOW_ASSERT
-#define llverify(func)			if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
-#else
-#define llverify(func)			(func); // get rid of warning C4189
-#endif
-
-// handy compile-time assert - enforce those template parameters! 
-#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1]	/* Flawfinder: ignore */
- 
-// Makes the app go down in flames, but on purpose!
-void _llcrash_and_loop();
-
-// Use as follows:
-// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl;
-//
-// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
-// should perhaps be replaced with boost::format.
-inline std::string llformat(const char *fmt, ...)
-{
-	char tstr[1024];	/* Flawfinder: ignore */
-	va_list va;
-	va_start(va, fmt);
-#if LL_WINDOWS
-	_vsnprintf(tstr, 1024, fmt, va);
-#else
-	vsnprintf(tstr, 1024, fmt, va);	/* Flawfinder: ignore */
-#endif
-	va_end(va);
-	return std::string(tstr);
-}
 
-// Helper class to temporarily change error level for the current scope.
-class LLScopedErrorLevel
-{
-public:
-	LLScopedErrorLevel(LLErrorBuffer::ELevel error_level);
-	~LLScopedErrorLevel();
-
-private:
-	LLErrorBuffer::ELevel mOrigErrorLevel;
-};
- 
+/*
+	Class type information for logging
+ */
+
+#define LOG_CLASS(s)	typedef s _LL_CLASS_TO_LOG
+	// Declares class to tag logged messages with.
+	// See top of file for example of how to use this
+	
+typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
+	// Outside a class declartion, or in class without LOG_CLASS(), this
+	// typedef causes the messages to not be associated with any class.
+
+
+
+
+
+/*
+	Error Logging Macros
+	See top of file for common usage.	
+*/
+
+#define lllog(level) \
+	{ \
+		static LLError::CallSite _site( \
+			level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\
+		if (_site.shouldLog()) \
+		{ \
+			std::ostringstream* _out = LLError::Log::out(); \
+			(*_out)
+	
+#define llendl \
+			LLError::End(); \
+			LLError::Log::flush(_out, _site); \
+		} \
+	}
+
+#define llinfos		lllog(LLError::LEVEL_INFO)
+#define lldebugs	lllog(LLError::LEVEL_DEBUG)
+#define llwarns		lllog(LLError::LEVEL_WARN)
+#define llerrs		lllog(LLError::LEVEL_ERROR)
+
+#define llcont		(*_out)
+	/*
+		Use this construct if you need to do computation in the middle of a
+		message:
+		
+			llinfos << "the agent " << agend_id;
+			switch (f)
+			{
+				case FOP_SHRUGS:	llcont << "shrugs";				break;
+				case FOP_TAPS:		llcont << "points at " << who;	break;
+				case FOP_SAYS:		llcont << "says " << message;	break;
+			}
+			llcont << " for " << t << " seconds" << llendl;
+		
+		Such computation is done iff the message will be logged.
+	*/
+
+
 #endif // LL_LLERROR_H
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..b1950eebf06f0154f81f2d0dbf4c1de54b9c468a
--- /dev/null
+++ b/indra/llcommon/llerrorcontrol.h
@@ -0,0 +1,123 @@
+/** 
+ * @file llerrorcontrol.h
+ * @date   December 2006
+ * @brief error message system control
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLERRORCONTROL_H
+#define LL_LLERRORCONTROL_H
+
+#include "llerror.h"
+
+#include <string>
+
+class LLFixedBuffer;
+class LLSD;
+
+/*
+	This is the part of the LLError namespace that manages the messages
+	produced by the logging.  The logging support is defined in llerror.h.
+	Most files do not need to include this.
+	
+	These implementations are in llerror.cpp.
+*/
+
+
+namespace LLError
+{
+	void initForServer(const std::string& identity);
+		// resets all logging settings to defaults needed by server processes
+		// logs to stderr, syslog, and windows debug log
+		// the identity string is used for in the syslog
+
+	void initForApplication(const std::string& dir);
+		// resets all logging settings to defaults needed by applicaitons
+		// logs to stderr and windows debug log
+		// sets up log configuration from the file logcontrol.xml in dir
+
+
+	/*
+		Settings that control what is logged.
+		Setting a level means log messages at that level or above.
+	*/
+	
+	void setPrintLocation(bool);
+	void setDefaultLevel(LLError::ELevel);
+	void setFunctionLevel(const std::string& function_name, LLError::ELevel);
+	void setClassLevel(const std::string& class_name, LLError::ELevel);
+	void setFileLevel(const std::string& file_name, LLError::ELevel);
+	
+	void configure(const LLSD&);
+		// the LLSD can configure all of the settings
+		// usually read automatically from the live errorlog.xml file
+
+
+	/*
+		Control functions.
+	*/
+
+	typedef void (*FatalFunction)(const std::string& message);
+	void crashAndLoop(const std::string& message);
+		// Default fatal funtion: divides by zero and loops forever
+
+	void setFatalFunction(FatalFunction);
+		// The fatal function will be called when an message of LEVEL_ERROR
+		// is logged.  Note: supressing a LEVEL_ERROR message from being logged
+		// (by, for example, setting a class level to LEVEL_NONE), will keep
+		// the that message from causing the fatal funciton to be invoked.
+		
+	typedef std::string (*TimeFunction)();
+	std::string utcTime();
+	
+	void setTimeFunction(TimeFunction);
+		// The function is use to return the current time, formatted for
+		// display by those error recorders that want the time included.
+
+
+
+	class Recorder
+	{
+		// An object that handles the actual output or error messages.
+	public:
+		virtual ~Recorder();
+		
+		virtual void recordMessage(LLError::ELevel, const std::string& message) = 0;
+			// use the level for better display, not for filtering
+			
+		virtual bool wantsTime(); // default returns false
+			// override and return true if the recorder wants the time string
+			// included in the text of the message
+	};
+	
+	void addRecorder(Recorder*);
+	void removeRecorder(Recorder*);
+		// each error message is passed to each recorder via recordMessage()
+	
+	void logToFile(const std::string& filename);
+	void logToFixedBuffer(LLFixedBuffer*);
+		// Utilities to add recorders for logging to a file or a fixed buffer
+		// A second call to the same function will remove the logger added
+		// with the first.
+		// Passing the empty string or NULL to just removes any prior.
+	std::string logFileName();
+		// returns name of current logging file, empty string if none
+
+
+	/*
+		Utilities for use by the unit tests of LLError itself.
+	*/
+
+	class Settings;
+	Settings* saveAndResetSettings();
+	void restoreSettings(Settings *);
+		
+	std::string abbreviateFile(const std::string& filePath);
+	int shouldLogCallCount();
+	
+};
+
+#endif // LL_LLERRORCONTROL_H
+
diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h
new file mode 100644
index 0000000000000000000000000000000000000000..19523512a64710e148593f19bb7c646f8f7acd2b
--- /dev/null
+++ b/indra/llcommon/llerrorlegacy.h
@@ -0,0 +1,98 @@
+/** 
+ * @file llerrorlegacy.h
+ * @date   January 2007
+ * @brief old things from the older error system
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLERRORLEGACY_H
+#define LL_LLERRORLEGACY_H
+
+
+
+/*
+	LEGACY -- DO NOT USE THIS STUFF ANYMORE
+*/
+
+// Specific error codes
+const int LL_ERR_NOERR = 0;
+const int LL_ERR_ASSET_REQUEST_FAILED = -1;
+//const int LL_ERR_ASSET_REQUEST_INVALID = -2;
+const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
+const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
+const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
+const int LL_ERR_EOF = -39;
+const int LL_ERR_CANNOT_OPEN_FILE = -42;
+const int LL_ERR_FILE_NOT_FOUND = -43;
+const int LL_ERR_FILE_EMPTY     = -44;
+const int LL_ERR_TCP_TIMEOUT    = -23016;
+const int LL_ERR_CIRCUIT_GONE   = -23017;
+
+
+
+// Define one of these for different error levels in release...
+// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output.
+#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output
+#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output.
+
+
+//////////////////////////////////////////
+//
+//  Implementation - ignore
+//
+//
+#ifdef _DEBUG
+#define SHOW_DEBUG
+#define SHOW_WARN
+#define SHOW_INFO
+#define SHOW_ASSERT
+#else // _DEBUG
+
+#ifdef RELEASE_SHOW_DEBUG
+#define SHOW_DEBUG
+#endif
+
+#ifdef RELEASE_SHOW_WARN
+#define SHOW_WARN
+#endif
+
+#ifdef RELEASE_SHOW_INFO
+#define SHOW_INFO
+#endif
+
+#ifdef RELEASE_SHOW_ASSERT
+#define SHOW_ASSERT
+#endif
+
+#endif // _DEBUG
+
+
+
+#define lldebugst(type)			lldebugs
+#define llendflush				llendl
+
+
+#define llerror(msg, num)		llerrs << "Error # " << num << ": " << msg << llendl;
+
+#define llwarning(msg, num)		llwarns << "Warning # " << num << ": " << msg << llendl;
+
+#ifdef SHOW_ASSERT
+#define llassert(func)			if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
+#else
+#define llassert(func)
+#endif
+#define llassert_always(func)	if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
+
+#ifdef SHOW_ASSERT
+#define llverify(func)			if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
+#else
+#define llverify(func)			(func); // get rid of warning C4189
+#endif
+
+// handy compile-time assert - enforce those template parameters! 
+#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1]   /* Flawfinder: ignore */
+	//XXX: used in two places in llcommon/llskipmap.h
+
+#endif // LL_LLERRORLEGACY_H
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 16e2f5c5a10bd43b4122ffa94ce6660249ef608e..4acd94f9431d3157ff965dc911e7e097f22bc209 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -178,6 +178,7 @@ void llifstream::open(const char* _Filename,	/* Flawfinder: ignore */
 	}
 	llassert(_Filebuffer == NULL);
 	_Filebuffer = new _Myfb(filep);
+	_ShouldClose = true;
 	_Myios::init(_Filebuffer);
 }
 
@@ -189,13 +190,17 @@ bool llifstream::is_open() const
 }
 llifstream::~llifstream()
 {	
+	if (_ShouldClose)
+	{
+		close();
+	}
 	delete _Filebuffer;
 }
 
 llifstream::llifstream(const char *_Filename,
 	ios_base::openmode _Mode,
 	int _Prot)
-	: std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL)
+	: std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
 
 {	// construct with named file and specified mode
 	open(_Filename, _Mode | ios_base::in, _Prot);	/* Flawfinder: ignore */
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 67de0f43fcf36d2c823fd77992d9db85af071c25..2899f51a600ea07cb497ce2ddd70d4f624e4c4bd 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -68,7 +68,7 @@ class	llifstream	:	public	std::basic_istream < char , std::char_traits < char >
 	typedef std::basic_ios<char,std::char_traits< char > > _Myios;
 
 	llifstream()
-		: std::basic_istream<char,std::char_traits< char > >(NULL,true),_Filebuffer(NULL)
+		: std::basic_istream<char,std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false)
 	{	// construct unopened
 	}
 
@@ -78,7 +78,8 @@ class	llifstream	:	public	std::basic_istream < char , std::char_traits < char >
 
 	explicit llifstream(_Filet *_File)
 		: std::basic_istream<char,std::char_traits< char > >(NULL,true),
-			_Filebuffer(new _Myfb(_File))
+			_Filebuffer(new _Myfb(_File)),
+			_ShouldClose(false)
 	{	// construct with specified C stream
 	}
 	virtual ~llifstream();
@@ -95,6 +96,7 @@ class	llifstream	:	public	std::basic_istream < char , std::char_traits < char >
 
 private:
 	_Myfb* _Filebuffer;	// the file buffer
+	bool _ShouldClose;
 };
 
 
diff --git a/indra/llcommon/llformat.cpp b/indra/llcommon/llformat.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0c2a6d3b1e27655498e3e399da596d38783f2352
--- /dev/null
+++ b/indra/llcommon/llformat.cpp
@@ -0,0 +1,28 @@
+/** 
+ * @file llformat.cpp
+ * @date   January 2007
+ * @brief string formatting utility
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llformat.h"
+
+#include <stdarg.h>
+
+std::string llformat(const char *fmt, ...)
+{
+	char tstr[1024];	/* Flawfinder: ignore */
+	va_list va;
+	va_start(va, fmt);
+#if LL_WINDOWS
+	_vsnprintf(tstr, 1024, fmt, va);
+#else
+	vsnprintf(tstr, 1024, fmt, va);	/* Flawfinder: ignore */
+#endif
+	va_end(va);
+	return std::string(tstr);
+}
diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h
new file mode 100644
index 0000000000000000000000000000000000000000..7079656b72ebf60c37621fd639aa4153b9ac3c29
--- /dev/null
+++ b/indra/llcommon/llformat.h
@@ -0,0 +1,23 @@
+/** 
+ * @file llformat.h
+ * @date   January 2007
+ * @brief string formatting utility
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLFORMAT_H
+#define LL_LLFORMAT_H
+
+#include <string>
+
+// Use as follows:
+// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl;
+//
+// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun)
+// should perhaps be replaced with boost::format.
+
+std::string llformat(const char *fmt, ...);
+
+#endif // LL_LLFORMAT_H
diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp
index 7dad6f82d8c6838fc9515fa5d02b5f62c8ec5242..df2e94035254cf2804dfebe89134fbe7d432067a 100644
--- a/indra/llcommon/lllivefile.cpp
+++ b/indra/llcommon/lllivefile.cpp
@@ -8,24 +8,56 @@
 #include "linden_common.h"
 
 #include "lllivefile.h"
+#include "llframetimer.h"
+#include "lltimer.h"
 
+class LLLiveFile::Impl
+{
+public:
+	Impl(const std::string &filename, const F32 refresh_period);
+	~Impl();
+	
+	bool check();
+	
+	
+	bool mForceCheck;
+	F32 mRefreshPeriod;
+	LLFrameTimer mRefreshTimer;
 
-LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period) :
-mForceCheck(true),
-mRefreshPeriod(refresh_period),
-mFilename(filename),
-mLastModTime(0),
-mLastExists(false)
+	std::string mFilename;
+	time_t mLastModTime;
+	bool mLastExists;
+	
+	LLEventTimer* mEventTimer;
+};
+
+LLLiveFile::Impl::Impl(const std::string &filename, const F32 refresh_period)
+	: mForceCheck(true),
+	mRefreshPeriod(refresh_period),
+	mFilename(filename),
+	mLastModTime(0),
+	mLastExists(false),
+	mEventTimer(NULL)
 {
 }
 
+LLLiveFile::Impl::~Impl()
+{
+	delete mEventTimer;
+}
+
+LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period)
+	: impl(* new Impl(filename, refresh_period))
+{
+}
 
 LLLiveFile::~LLLiveFile()
 {
+	delete &impl;
 }
 
 
-bool LLLiveFile::checkAndReload()
+bool LLLiveFile::Impl::check()
 {
 	if (!mForceCheck && mRefreshTimer.getElapsedTimeF32() < mRefreshPeriod)
 	{
@@ -46,9 +78,8 @@ bool LLLiveFile::checkAndReload()
 		// broken somehow.  Clear flags and return.
 		if (mLastExists)
 		{
-			loadFile(); // Load the file, even though it's missing to allow it to clear state.
 			mLastExists = false;
-			return true;
+			return true;	// no longer existing is a change!
 		}
 		return false;
 	}
@@ -68,7 +99,44 @@ bool LLLiveFile::checkAndReload()
 	mLastExists = true;
 	mLastModTime = stat_data.st_mtime;
 	
-	loadFile();
 	return true;
 }
 
+bool LLLiveFile::checkAndReload()
+{
+	bool changed = impl.check();
+	if (changed)
+	{
+		loadFile();
+	}
+	return changed;
+}
+
+std::string LLLiveFile::filename() const
+{
+	return impl.mFilename;
+}
+
+namespace
+{
+	class LiveFileEventTimer : public LLEventTimer
+	{
+	public:
+		LiveFileEventTimer(LLLiveFile& f, F32 refresh)
+			: LLEventTimer(refresh), mLiveFile(f)
+			{ }
+			
+		void tick()
+			{ mLiveFile.checkAndReload(); }
+	
+	private:
+		LLLiveFile& mLiveFile;
+	};
+	
+}
+
+void LLLiveFile::addToEventTimer()
+{
+	impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod);
+}
+
diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h
index 97c88a5c5c70fb607be23351a314c5c95f296840..a71844e5a9ba9b40f2a4e08660f769c92a52930f 100644
--- a/indra/llcommon/lllivefile.h
+++ b/indra/llcommon/lllivefile.h
@@ -9,7 +9,6 @@
 #ifndef LL_LLLIVEFILE_H
 #define LL_LLLIVEFILE_H
 
-#include "llframetimer.h"
 
 class LLLiveFile
 {
@@ -17,18 +16,22 @@ class LLLiveFile
 	LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f);
 	virtual ~LLLiveFile();
 
-	bool checkAndReload(); // Returns true if the file changed in any way
+	bool checkAndReload();
+		// Returns true if the file changed in any way
+		// Call this before using anything that was read & cached from the file
+
+	std::string filename() const;
+
+	void addToEventTimer();
+		// Normally, just calling checkAndReload() is enough.  In some cases
+		// though, you may need to let the live file periodically check itself.
 
 protected:
 	virtual void loadFile() = 0; // Implement this to load your file if it changed
 
-	bool mForceCheck;
-	F32 mRefreshPeriod;
-	LLFrameTimer mRefreshTimer;
-
-	std::string mFilename;
-	time_t mLastModTime;
-	bool mLastExists;
+private:
+	class Impl;
+	Impl& impl;
 };
 
 #endif //LL_LLLIVEFILE_H
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 25bd7ceac8e97bf1d84a12f2b9d8481eb79f8392..45d7acd417459fb31b61dd38d5c689e0d25d74eb 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -10,6 +10,7 @@
 
 #include <math.h>
 #include "../llmath/llmath.h"
+#include "llformat.h"
 
 namespace {
 	class ImplMap;
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 0555231010471622660cec0e747fdede84617c21..a381af74d03cf9696bea802d84526b20abc899bb 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -11,6 +11,7 @@
 
 #include "stdtypes.h"
 #include "llerror.h"
+#include "llfile.h"
 #include <algorithm>
 #include <map>
 #include <stdio.h>
diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h
index ad428ce5652169f138ba60009eb1877d511102a6..20db115c6ea8476950c124ed01f7510ca7d43d23 100644
--- a/indra/llcommon/llstringtable.h
+++ b/indra/llcommon/llstringtable.h
@@ -10,6 +10,8 @@
 #ifndef LL_STRING_TABLE_H
 #define LL_STRING_TABLE_H
 
+#include "lldefs.h"
+#include "llformat.h"
 #include "llstl.h"
 #include <list>
 #include <set>
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 4ba47e7689493d1f6f06efb7850ce5c2ef6e0ce8..9e1a0ee12ccd73c67d18c2a3d4df7fb73a78063c 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -4402,33 +4402,6 @@ void process_secured_template_checksum_request(LLMessageSystem* msg, void**)
 	send_template_reply(msg, token);
 }
 
-void process_log_control(LLMessageSystem* msg, void**)
-{
-	U8 level;
-	U32 mask;
-	BOOL time;
-	BOOL location;
-	BOOL remote_infos;
-
-	msg->getU8Fast(_PREHASH_Options, _PREHASH_Level, level);
-	msg->getU32Fast(_PREHASH_Options, _PREHASH_Mask, mask);
-	msg->getBOOLFast(_PREHASH_Options, _PREHASH_Time, time);
-	msg->getBOOLFast(_PREHASH_Options, _PREHASH_Location, location);
-	msg->getBOOLFast(_PREHASH_Options, _PREHASH_RemoteInfos, remote_infos);
-
-	gErrorStream.setLevel(LLErrorStream::ELevel(level));
-	gErrorStream.setDebugMask(mask);
-	gErrorStream.setTime(time);
-	gErrorStream.setPrintLocation(location);
-	gErrorStream.setElevatedRemote(remote_infos);
-
-	llinfos << "Logging set to level " << gErrorStream.getLevel() 
-		<< " mask " << std::hex << gErrorStream.getDebugMask() << std::dec
-		<< " time " << gErrorStream.getTime()
-		<< " loc " << gErrorStream.getPrintLocation()
-		<< llendl;
-}
-
 void process_log_messages(LLMessageSystem* msg, void**)
 {
 	U8 log_message;
@@ -4749,7 +4722,6 @@ BOOL start_messaging_system(
 	gMessageSystem->setHandlerFuncFast(_PREHASH_PacketAck,             process_packet_ack,	    NULL);
 	gMessageSystem->setHandlerFuncFast(_PREHASH_TemplateChecksumRequest,  process_template_checksum_request,	NULL);
 	gMessageSystem->setHandlerFuncFast(_PREHASH_SecuredTemplateChecksumRequest,  process_secured_template_checksum_request,	NULL);
-	gMessageSystem->setHandlerFuncFast(_PREHASH_LogControl,			process_log_control,	NULL);
 	gMessageSystem->setHandlerFuncFast(_PREHASH_LogMessages,			process_log_messages,	NULL);
 	gMessageSystem->setHandlerFuncFast(_PREHASH_CreateTrustedCircuit,
 				       process_create_trusted_circuit,
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index ec76e1f755b9f7d468275fce4490200ec10d82e3..48d950e377a0b0f8129cbbab2956cfcce602311f 100644
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -187,6 +187,8 @@ class LLMessagePollInfo;
 
 class LLMessageSystem
 {
+	LOG_CLASS(LLMessageSystem);
+	
 public:
 	U8										mSendBuffer[MAX_BUFFER_SIZE];
 	// Encoded send buffer needs to be slightly larger since the zero
@@ -757,7 +759,6 @@ BOOL start_messaging_system(
 void end_messaging_system();
 
 void null_message_callback(LLMessageSystem *msg, void **data);
-void process_log_control(LLMessageSystem* msg, void**);
 
 //
 // Inlines
diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index 18be31af585b9a9576999c0ab4bd7be1919d3285..c2d7c9c2a34dd39e7e31a5bcc62d8ef042d1aaea 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -489,7 +489,6 @@ char * _PREHASH_NVPair;
 char * _PREHASH_ObjectSpinStart;
 char * _PREHASH_UseEstateSun;
 char * _PREHASH_LogoutBlock;
-char * _PREHASH_RelayLogControl;
 char * _PREHASH_RegionID;
 char * _PREHASH_Creator;
 char * _PREHASH_ProposalText;
@@ -1294,7 +1293,6 @@ char * _PREHASH_AssetBlock;
 char * _PREHASH_AcceptNotices;
 char * _PREHASH_SetGroupAcceptNotices;
 char * _PREHASH_CloseCircuit;
-char * _PREHASH_LogControl;
 char * _PREHASH_TeleportFinish;
 char * _PREHASH_PathRevolutions;
 char * _PREHASH_ClassifiedInfoReply;
@@ -1963,7 +1961,6 @@ void init_prehash_data()
 	_PREHASH_ObjectSpinStart = gMessageStringTable.getString("ObjectSpinStart");
 	_PREHASH_UseEstateSun = gMessageStringTable.getString("UseEstateSun");
 	_PREHASH_LogoutBlock = gMessageStringTable.getString("LogoutBlock");
-	_PREHASH_RelayLogControl = gMessageStringTable.getString("RelayLogControl");
 	_PREHASH_RegionID = gMessageStringTable.getString("RegionID");
 	_PREHASH_Creator = gMessageStringTable.getString("Creator");
 	_PREHASH_ProposalText = gMessageStringTable.getString("ProposalText");
@@ -2768,7 +2765,6 @@ void init_prehash_data()
 	_PREHASH_AcceptNotices = gMessageStringTable.getString("AcceptNotices");
 	_PREHASH_SetGroupAcceptNotices = gMessageStringTable.getString("SetGroupAcceptNotices");
 	_PREHASH_CloseCircuit = gMessageStringTable.getString("CloseCircuit");
-	_PREHASH_LogControl = gMessageStringTable.getString("LogControl");
 	_PREHASH_TeleportFinish = gMessageStringTable.getString("TeleportFinish");
 	_PREHASH_PathRevolutions = gMessageStringTable.getString("PathRevolutions");
 	_PREHASH_ClassifiedInfoReply = gMessageStringTable.getString("ClassifiedInfoReply");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 0da2e02f83989d85ff6fef04d81720bed1c440dd..63e23237f559a10433ef9fad6c7f82a6c2535453 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -489,7 +489,6 @@ extern char * _PREHASH_NVPair;
 extern char * _PREHASH_ObjectSpinStart;
 extern char * _PREHASH_UseEstateSun;
 extern char * _PREHASH_LogoutBlock;
-extern char * _PREHASH_RelayLogControl;
 extern char * _PREHASH_RegionID;
 extern char * _PREHASH_Creator;
 extern char * _PREHASH_ProposalText;
@@ -1294,7 +1293,6 @@ extern char * _PREHASH_AssetBlock;
 extern char * _PREHASH_AcceptNotices;
 extern char * _PREHASH_SetGroupAcceptNotices;
 extern char * _PREHASH_CloseCircuit;
-extern char * _PREHASH_LogControl;
 extern char * _PREHASH_TeleportFinish;
 extern char * _PREHASH_PathRevolutions;
 extern char * _PREHASH_ClassifiedInfoReply;
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index c02be6bb8dca9a31e41333f20eb3fff30e9c584c..ffa9262e21671fd7e081983488af43cc80d67cf9 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -584,7 +584,7 @@ void LLButton::draw()
 		else
 		{
 			// no image
-			llalerts << "No image for button " << mName << llendl;
+			llwarns << "No image for button " << mName << llendl;
 			// draw it in pink so we can find it
 			gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE);
 		}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index cf80a72282036b9565005e0954d3ba86af62f4f2..4ff07e997645a54c15c4845781ff9b76369de9af 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -28,6 +28,7 @@
 #include "llcrypto.h"
 #include "lldir.h"
 #include "lleconomy.h"
+#include "llerrorcontrol.h"
 #include "llfiltersd2xmlrpc.h"
 #include "llfocusmgr.h"
 #include "imageids.h"
@@ -421,7 +422,6 @@ BOOL idle_startup()
 								  invalid_message_callback,
 								  NULL);
 
-			gErrorStream.setUTCTimestamp(gLogUTC);
 			if (gSavedSettings.getBOOL("LogMessages") || gLogMessages)
 			{
 				llinfos << "Message logging activated!" << llendl;
@@ -1679,7 +1679,7 @@ BOOL idle_startup()
 			// Move the progress view in front of the UI
 			gViewerWindow->moveProgressViewToFront();
 
-			gErrorStream.setFixedBuffer(gDebugView->mDebugConsolep);
+			LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
 			// set initial visibility of debug console
 			gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
 			gDebugView->mStatViewp->setVisible(gSavedSettings.getBOOL("ShowDebugStats"));
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 7ef1fd82c63892fb73c38688ddf358f8b9ecfed3..49578b186d79ac2c24f79bf922b6565074ef3d9c 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -430,8 +430,6 @@ void handle_dump_image_list(void*);
 void handle_fullscreen_debug(void*);
 void handle_crash(void*);
 void handle_dump_followcam(void*);
-void handle_viewer_enable_circuit_log(void*);
-void handle_viewer_disable_circuit_log(void*);
 void handle_viewer_enable_message_log(void*);
 void handle_viewer_disable_message_log(void*);
 void handle_send_postcard(void*);
@@ -818,10 +816,6 @@ void init_client_menu(LLMenuGL* menu)
 		LLMenuGL* sub = NULL;
 		sub = new LLMenuGL("Network");
 
-		sub->append(new LLMenuItemCallGL("Enable Circuit Log",  
-			&handle_viewer_enable_circuit_log,  NULL));
-		sub->append(new LLMenuItemCallGL("Disable Circuit Log", 
-			&handle_viewer_disable_circuit_log, NULL));
 		sub->append(new LLMenuItemCallGL("Enable Message Log",  
 			&handle_viewer_enable_message_log,  NULL));
 		sub->append(new LLMenuItemCallGL("Disable Message Log", 
@@ -1307,11 +1301,6 @@ void init_server_menu(LLMenuGL* menu)
 			&handle_normal_llinfo_log, &enable_god_customer_service));
 
 		sub_menu->appendSeparator();
-		sub_menu->append(new LLMenuItemCallGL("Enable Circuit Log",  
-			&handle_sim_enable_circuit_log,  &enable_god_customer_service));
-		sub_menu->append(new LLMenuItemCallGL("Disable Circuit Log", 
-			&handle_sim_disable_circuit_log, &enable_god_customer_service));
-		sub_menu->appendSeparator();
 		sub_menu->append(new LLMenuItemCallGL("Enable Message Log",  
 			&handle_sim_enable_message_log,  &enable_god_customer_service));
 		sub_menu->append(new LLMenuItemCallGL("Disable Message Log", 
@@ -6375,24 +6364,6 @@ void handle_dump_followcam(void*)
 	LLFollowCamMgr::dump();
 }
 
-void handle_viewer_enable_circuit_log(void*)
-{
-	llinfos << "Showing circuit information every " << gMessageSystem->mCircuitPrintFreq << " seconds" << llendl;
-	gErrorStream.setLevel( LLErrorStream::DEBUG );
-	gErrorStream.setDebugFlag( LLERR_CIRCUIT_INFO );
-	// and dump stuff out immediately
-	gMessageSystem->dumpCircuitInfo();
-}
-
-void handle_viewer_disable_circuit_log(void*)
-{
-	llinfos << "Hiding circuit information" << llendl;
-#if !LL_DEBUG
-	gErrorStream.setLevel( LLErrorStream::INFO );
-#endif
-	gErrorStream.clearDebugFlag( LLERR_CIRCUIT_INFO );
-}
-
 void handle_viewer_enable_message_log(void*)
 {
 	gMessageSystem->startLogging();
diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h
index a2ef97fc6bcfc744578445b5eb0fc38ff8362df1..50b84babd130b66d33bb849390b82c1639dc61a6 100644
--- a/indra/newview/llviewerprecompiledheaders.h
+++ b/indra/newview/llviewerprecompiledheaders.h
@@ -63,8 +63,6 @@
 #include "lldqueueptr.h"
 #include "llendianswizzle.h"
 #include "llerror.h"
-#include "llerrorbuffer.h"
-#include "llerrorstream.h"
 #include "llfasttimer.h"
 #include "llfixedbuffer.h"
 #include "llframetimer.h"
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index c2726997b20f02995a39aa11629445ff33997afc..cc8f955bc6c74001d3e9497f6d58f4f0c5a00d9f 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -324,9 +324,9 @@ bool LLXMLRPCTransaction::Impl::process()
 			if (curl_msg->data.result != CURLE_OK)
 			{
 				setCurlStatus(curl_msg->data.result);
-				llalerts << "LLXMLRPCTransaction CURL error "
+				llwarns << "LLXMLRPCTransaction CURL error "
 					<< mCurlCode << ": " << mCurlErrorBuffer << llendl;
-				llalerts << "LLXMLRPCTransaction request URI: "
+				llwarns << "LLXMLRPCTransaction request URI: "
 					<< mURI << llendl;
 					
 				return true;
@@ -360,11 +360,11 @@ bool LLXMLRPCTransaction::Impl::process()
 			{
 				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
 				
-				llalerts << "LLXMLRPCTransaction XMLRPC "
+				llwarns << "LLXMLRPCTransaction XMLRPC "
 					<< (hasError ? "error " : "fault ")
 					<< faultCode << ": "
 					<< faultString << llendl;
-				llalerts << "LLXMLRPCTransaction request URI: "
+				llwarns << "LLXMLRPCTransaction request URI: "
 					<< mURI << llendl;
 			}
 			
diff --git a/indra/test/llhttpclient_tut.cpp b/indra/test/llhttpclient_tut.cpp
index 98f24c1bdd0bddd772ca98e8d540892e76555a39..40cde1fd6c21864c71ebea3f41522be14abd4ace 100644
--- a/indra/test/llhttpclient_tut.cpp
+++ b/indra/test/llhttpclient_tut.cpp
@@ -16,6 +16,7 @@
 #include "lltut.h"
 
 #include "llhttpclient.h"
+#include "llformat.h"
 #include "llpipeutil.h"
 #include "llpumpio.h"
 
diff --git a/indra/test/llpipeutil.cpp b/indra/test/llpipeutil.cpp
index 56789cfae8ae3d2f641a6b04b6dbd6f4dcf7398e..3a15bfdb7edf992c213fdc960b3913132f1e37b2 100644
--- a/indra/test/llpipeutil.cpp
+++ b/indra/test/llpipeutil.cpp
@@ -12,6 +12,7 @@
 #include <stdlib.h>
 
 #include "llbufferstream.h"
+#include "lldefs.h"
 #include "llframetimer.h"
 #include "llpumpio.h"
 #include "llrand.h"
diff --git a/indra/test/lltut.cpp b/indra/test/lltut.cpp
index 96aad3da587c10b3c9e81df8b9f6ca0d269599ef..592d61137d3e641749921df1f3648064c25e11bc 100644
--- a/indra/test/lltut.cpp
+++ b/indra/test/lltut.cpp
@@ -9,6 +9,8 @@
  */
 
 #include "lltut.h"
+
+#include "llformat.h"
 #include "llsd.h"
 
 namespace tut
@@ -135,6 +137,20 @@ namespace tut
 		}
 	}
 
+	void ensure_ends_with(const std::string& msg,
+		const std::string& actual, const std::string& expectedEnd)
+	{
+		if( actual.size() < expectedEnd.size()
+			|| actual.rfind(expectedEnd)
+				!= (actual.size() - expectedEnd.size()) )
+		{
+			std::stringstream ss;
+			ss << msg << ": " << "expected to find " << expectedEnd
+				<< " at end of actual " << actual;
+			throw failure(ss.str().c_str());
+		}
+	}
+
 	void ensure_contains(const std::string& msg,
 		const std::string& actual, const std::string& expectedSubString)
 	{
@@ -146,4 +162,16 @@ namespace tut
 			throw failure(ss.str().c_str());
 		}
 	}
+
+	void ensure_does_not_contain(const std::string& msg,
+		const std::string& actual, const std::string& expectedSubString)
+	{
+		if( actual.find(expectedSubString, 0) != std::string::npos )
+		{
+			std::stringstream ss;
+			ss << msg << ": " << "expected not to find " << expectedSubString
+				<< " in actual " << actual;
+			throw failure(ss.str().c_str());
+		}
+	}
 }
diff --git a/indra/test/lltut.h b/indra/test/lltut.h
index c750a99b8d2df1c65226596db150a9e59bc0014b..c2ec50485707274ba5ed6382d887bd601362b83f 100644
--- a/indra/test/lltut.h
+++ b/indra/test/lltut.h
@@ -68,8 +68,14 @@ namespace tut
 	void ensure_starts_with(const std::string& msg,
 		const std::string& actual, const std::string& expectedStart);
 
+	void ensure_ends_with(const std::string& msg,
+		const std::string& actual, const std::string& expectedEnd);
+
 	void ensure_contains(const std::string& msg,
 		const std::string& actual, const std::string& expectedSubString);
+
+	void ensure_does_not_contain(const std::string& msg,
+		const std::string& actual, const std::string& expectedSubString);
 }
 
 
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 2d727daaa5cac0bb3c8c9f7d35513b1702000665..312c52dc771050c98c7f29301ce7b624a0c3a23a 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "linden_common.h"
+#include "llerrorcontrol.h"
 #include "lltut.h"
 
 #include <apr-1/apr_pools.h>
@@ -159,8 +160,18 @@ void stream_groups(std::ostream& s, const char* app)
 	}
 }
 
+void wouldHaveCrashed(const std::string& message)
+{
+	tut::fail("llerrs message: " + message);
+}
+
 int main(int argc, char **argv)
 {
+	LLError::initForApplication(".");
+	LLError::setFatalFunction(wouldHaveCrashed);
+	LLError::setDefaultLevel(LLError::LEVEL_ERROR);
+		// *FIX: should come from error config file
+	
 #ifdef CTYPE_WORKAROUND
 	ctype_workaround();
 #endif