summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorEric Tulla <tulla@lindenlab.com>2008-05-14 21:37:13 +0000
committerEric Tulla <tulla@lindenlab.com>2008-05-14 21:37:13 +0000
commite77de5d685ae441f72920f0e04d9887ee958745a (patch)
treeb3736831042b20be198dc9994ba68db1e8be2a14 /indra/llcommon
parent41e1ed5b4153019b07d97f54751db53fa248d8d4 (diff)
Result of svn merge -r 87455:87538 $SVN/branches/tulla/vc3-merge .
Passed QA as part of QAR-491.
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llapr.cpp12
-rw-r--r--indra/llcommon/llerror.cpp69
-rw-r--r--indra/llcommon/llerror.h82
-rw-r--r--indra/llcommon/lltimer.cpp5
-rw-r--r--indra/llcommon/lltimer.h4
5 files changed, 130 insertions, 42 deletions
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 5e6dfd975e..5be3919898 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -54,7 +54,7 @@ void ll_init_apr()
void ll_cleanup_apr()
{
- llinfos << "Cleaning up APR" << llendl;
+ LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
if (gLogMutexp)
{
@@ -118,7 +118,7 @@ bool ll_apr_warn_status(apr_status_t status)
if(APR_SUCCESS == status) return false;
#ifndef LL_WINDOWS
char buf[MAX_STRING]; /* Flawfinder: ignore */
- llwarns << "APR: " << apr_strerror(status, buf, MAX_STRING) << llendl;
+ LL_WARNS_ONCE("APR") << "APR: " << apr_strerror(status, buf, MAX_STRING) << LL_ENDL;
#endif
return true;
}
@@ -294,7 +294,7 @@ bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool)
s = apr_file_remove(filename.c_str(), pool);
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_file_remove failed on file: " << filename << llendl;
+ LL_DEBUGS("APR") << "ll_apr_file_remove failed on file: " << filename << LL_ENDL;
ll_apr_warn_status(s);
return false;
}
@@ -308,7 +308,7 @@ bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_p
s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_file_rename failed on file: " << filename << llendl;
+ LL_DEBUGS("APR") << "ll_apr_file_rename failed on file: " << filename << LL_ENDL;
ll_apr_warn_status(s);
return false;
}
@@ -365,7 +365,7 @@ bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool)
s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_dir_make failed on file: " << dirname << llendl;
+ LL_DEBUGS("APR") << "ll_apr_dir_make failed on file: " << dirname << LL_ENDL;
ll_apr_warn_status(s);
return false;
}
@@ -379,7 +379,7 @@ bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool)
s = apr_file_remove(dirname.c_str(), pool);
if (s != APR_SUCCESS)
{
- lldebugs << "ll_apr_dir_remove failed on file: " << dirname << llendl;
+ LL_DEBUGS("APR") << "ll_apr_dir_remove failed on file: " << dirname << LL_ENDL;
ll_apr_warn_status(s);
return false;
}
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 13bf368334..e635011941 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -408,6 +408,8 @@ namespace LLError
LevelMap functionLevelMap;
LevelMap classLevelMap;
LevelMap fileLevelMap;
+ LevelMap tagLevelMap;
+ std::map<std::string, unsigned int> uniqueLogMessages;
LLError::FatalFunction crashFunction;
LLError::TimeFunction timeFunction;
@@ -494,11 +496,17 @@ namespace LLError
namespace LLError
{
CallSite::CallSite(ELevel level,
- const char* file, int line,
- const std::type_info& class_info, const char* function)
+ const char* file,
+ int line,
+ const std::type_info& class_info,
+ const char* function,
+ const char* broadTag,
+ const char* narrowTag,
+ bool printOnce)
: mLevel(level), mFile(file), mLine(line),
mClassInfo(class_info), mFunction(function),
- mCached(false), mShouldLog(false)
+ mCached(false), mShouldLog(false),
+ mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce)
{ }
@@ -552,6 +560,15 @@ namespace
#endif
LogControlFile& e = LogControlFile::fromDirectory(dir);
+
+ // NOTE: We want to explicitly load the file before we add it to the event timer
+ // that checks for changes to the file. Else, we're not actually loading the file yet,
+ // and most of the initialization happens without any attention being paid to the
+ // log control file. Not to mention that when it finally gets checked later,
+ // all log statements that have been evaluated already become dirty and need to be
+ // evaluated for printing again. So, make sure to call checkAndReload()
+ // before addToEventTimer().
+ e.checkAndReload();
e.addToEventTimer();
}
}
@@ -625,6 +642,14 @@ namespace LLError
g.invalidateCallSites();
s.fileLevelMap[file_name] = level;
}
+
+ void setTagLevel(const std::string& tag_name, ELevel level)
+ {
+ Globals& g = Globals::get();
+ Settings& s = Settings::get();
+ g.invalidateCallSites();
+ s.tagLevelMap[tag_name] = level;
+ }
}
namespace {
@@ -674,6 +699,8 @@ namespace LLError
s.functionLevelMap.clear();
s.classLevelMap.clear();
s.fileLevelMap.clear();
+ s.tagLevelMap.clear();
+ s.uniqueLogMessages.clear();
setPrintLocation(config["print-location"]);
setDefaultLevel(decodeLevel(config["default-level"]));
@@ -689,6 +716,7 @@ namespace LLError
setLevels(s.functionLevelMap, entry["functions"], level);
setLevels(s.classLevelMap, entry["classes"], level);
setLevels(s.fileLevelMap, entry["files"], level);
+ setLevels(s.tagLevelMap, entry["tags"], level);
}
}
}
@@ -850,7 +878,7 @@ namespace {
return false;
}
- level = i->second;
+ level = i->second;
return true;
}
@@ -929,9 +957,15 @@ namespace LLError
ELevel compareLevel = s.defaultLevel;
- checkLevelMap(s.functionLevelMap, function_name, compareLevel)
+ // The most specific match found will be used as the log level,
+ // since the computation short circuits.
+ // So, in increasing order of importance:
+ // Default < Broad Tag < File < Class < Function < Narrow Tag
+ ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false)
+ || checkLevelMap(s.functionLevelMap, function_name, compareLevel)
|| checkLevelMap(s.classLevelMap, class_name, compareLevel)
- || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel);
+ || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel)
+ || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false);
site.mCached = true;
g.addCallSite(site);
@@ -1018,6 +1052,29 @@ namespace LLError
#endif
prefix << site.mFunction << ": ";
}
+
+ if (site.mPrintOnce)
+ {
+ std::map<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message);
+ if (messageIter != s.uniqueLogMessages.end())
+ {
+ messageIter->second++;
+ unsigned int num_messages = messageIter->second;
+ if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0)
+ {
+ prefix << "ONCE (" << num_messages << "th time seen): ";
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ prefix << "ONCE: ";
+ s.uniqueLogMessages[message] = 1;
+ }
+ }
prefix << message;
message = prefix.str();
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index ae41cd5244..13fb2bcebe 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -45,23 +45,23 @@
Code can log messages with constuctions like this:
- llinfos << "request to fizzbip agent " << agent_id
- << " denied due to timeout" << llendl;
+ LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
+ << " denied due to timeout" << LL_ENDL;
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
+ LL_DEBUGS("StringTag") - debug messages that are normally supressed
+ LL_INFOS("StringTag") - informational messages that are normall shown
+ LL_WARNS("StringTag") - warning messages that singal a problem
+ LL_ERRS("StringTag") - error messages that are major, unrecoverable failures
- The later (llerrs) automatically crashes the process after the message
+ The later (LL_ERRS("StringTag")) 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
+ * messages written to them MUST be terminated with LL_ENDL
* between the opening and closing, the << operator is indeed
writing onto a std::ostream, so all conversions and stream
formating are available
@@ -85,7 +85,7 @@
{
if (i > 100)
{
- llwanrs << "called with a big value for i: " << i << llendl;
+ LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL;
}
...
}
@@ -100,7 +100,7 @@
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,
+ #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds,
even release. Which means you can use them to help debug even when deployed
to a real grid.
*/
@@ -144,7 +144,7 @@ namespace LLError
// intended for public use.
public:
CallSite(ELevel, const char* file, int line,
- const std::type_info& class_info, const char* function);
+ const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce);
bool shouldLog()
{ return mCached ? mShouldLog : Log::shouldLog(*this); }
@@ -156,9 +156,12 @@ namespace LLError
// these describe the call site and never change
const ELevel mLevel;
const char* const mFile;
- const int mLine;
- const std::type_info& mClassInfo;
+ const int mLine;
+ const std::type_info& mClassInfo;
const char* const mFunction;
+ const char* const mBroadTag;
+ const char* const mNarrowTag;
+ const bool mPrintOnce;
// these implement a cache of the call to shouldLog()
bool mCached;
@@ -200,39 +203,66 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
See top of file for common usage.
*/
-#define lllog(level) \
+#define lllog(level, broadTag, narrowTag, once) \
{ \
static LLError::CallSite _site( \
- level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\
+ level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
if (_site.shouldLog()) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
(*_out)
-
+
+// DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro
#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)
-
+// DEPRECATED: Use the new macros that allow tags and *look* like macros.
+#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
+#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false)
+#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false)
+#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
#define llcont (*_out)
+
+// NEW Macros for debugging, allow the passing of a string tag
+
+// One Tag
+#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
+#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
+#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
+#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
+// Two Tags
+#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
+#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
+#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
+#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
+
+// Only print the log message once (good for warnings or infos that would otherwise
+// spam the log file over and over, such as tighter loops).
+#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
+#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
+#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
+#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
+#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
+#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
+
+#define LL_ENDL llendl
+#define LL_CONT (*_out)
+
/*
Use this construct if you need to do computation in the middle of a
message:
- llinfos << "the agent " << agend_id;
+ LL_INFOS("AgentGesture") << "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;
+ case FOP_SHRUGS: LL_CONT << "shrugs"; break;
+ case FOP_TAPS: LL_CONT << "points at " << who; break;
+ case FOP_SAYS: LL_CONT << "says " << message; break;
}
- llcont << " for " << t << " seconds" << llendl;
+ LL_CONT << " for " << t << " seconds" << LL_ENDL;
Such computation is done iff the message will be logged.
*/
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index cf984e4fe2..af89a09d2f 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -334,7 +334,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
+ (U64)((F32)(expiration * gClockFrequency));
}
-F32 LLTimer::getRemainingTimeF32()
+F32 LLTimer::getRemainingTimeF32() const
{
U64 cur_ticks = get_clock_count();
if (cur_ticks > mExpirationTicks)
@@ -359,7 +359,7 @@ BOOL LLTimer::checkExpirationAndReset(F32 expiration)
}
-BOOL LLTimer::hasExpired()
+BOOL LLTimer::hasExpired() const
{
return (get_clock_count() >= mExpirationTicks)
? TRUE : FALSE;
@@ -561,3 +561,4 @@ void LLEventTimer::updateClass()
}
}
+
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index 113eb1e9e3..57f9e23e7a 100644
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -87,11 +87,11 @@ public:
void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time
void setTimerExpirySec(F32 expiration);
BOOL checkExpirationAndReset(F32 expiration);
- BOOL hasExpired();
+ BOOL hasExpired() const;
F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
F64 getElapsedTimeAndResetF64();
- F32 getRemainingTimeF32();
+ F32 getRemainingTimeF32() const;
static BOOL knownBadTimer();