summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorOz Linden <oz@lindenlab.com>2018-08-29 16:43:45 -0400
committerOz Linden <oz@lindenlab.com>2018-08-29 16:43:45 -0400
commitf1d4e788e73857f14c016d13b6c879d86bd5b692 (patch)
tree8a08182a4dd259a971ea669f733d95b0e99fae92 /indra/llcommon
parent735b53d7245db4c874e6bbc3f17eb36835c0077b (diff)
SL-967 simplify viewer log file field syntax
MAINT-8991: only escape log message characters once, add unit test remove extra log line created by LL_ERRS document that tags may not contain spaces
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llerror.cpp109
-rw-r--r--indra/llcommon/llerror.h17
-rw-r--r--indra/llcommon/llprocessor.cpp2
-rw-r--r--indra/llcommon/tests/llerror_test.cpp291
4 files changed, 301 insertions, 118 deletions
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 29de79dc64..06c7aef8ab 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -40,6 +40,7 @@
# include <unistd.h>
#endif // !LL_WINDOWS
#include <vector>
+#include "string.h"
#include "llapp.h"
#include "llapr.h"
@@ -530,21 +531,16 @@ namespace LLError
mTags(new const char* [tag_count]),
mTagCount(tag_count)
{
- for (int i = 0; i < tag_count; i++)
- {
- mTags[i] = tags[i];
- }
-
switch (mLevel)
{
- case LEVEL_DEBUG: mLevelString = "DEBUG:"; break;
- case LEVEL_INFO: mLevelString = "INFO:"; break;
- case LEVEL_WARN: mLevelString = "WARNING:"; break;
- case LEVEL_ERROR: mLevelString = "ERROR:"; break;
- default: mLevelString = "XXX:"; break;
+ case LEVEL_DEBUG: mLevelString = "DEBUG"; break;
+ case LEVEL_INFO: mLevelString = "INFO"; break;
+ case LEVEL_WARN: mLevelString = "WARNING"; break;
+ case LEVEL_ERROR: mLevelString = "ERROR"; break;
+ default: mLevelString = "XXX"; break;
};
- mLocationString = llformat("%s(%d) :", abbreviateFile(mFile).c_str(), mLine);
+ mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine);
#if LL_WINDOWS
// DevStudio: __FUNCTION__ already includes the full class name
#else
@@ -558,13 +554,23 @@ namespace LLError
mFunctionString = className(mClassInfo) + "::";
}
#endif
- mFunctionString += std::string(mFunction) + ":";
- const std::string tag_hash("#");
+ mFunctionString += std::string(mFunction);
+
+ for (int i = 0; i < tag_count; i++)
+ {
+ if (strchr(tags[i], ' '))
+ {
+ LL_ERRS() << "Space is not allowed in a log tag at " << mLocationString << LL_ENDL;
+ }
+ mTags[i] = tags[i];
+ }
+
+ mTagString.append("#");
+ // always construct a tag sequence; will be just a single # if no tag
for (size_t i = 0; i < mTagCount; i++)
{
- mTagString.append(tag_hash);
mTagString.append(mTags[i]);
- mTagString.append((i == mTagCount - 1) ? ";" : ",");
+ mTagString.append("#");
}
}
@@ -899,7 +905,46 @@ namespace LLError
namespace
{
- void writeToRecorders(const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)
+ void addEscapedMessage(std::ostream& out, const std::string& message)
+ {
+ size_t written_out = 0;
+ size_t all_content = message.length();
+ size_t escape_char_index; // always relative to start of message
+ // Use find_first_of to find the next character in message that needs escaping
+ for ( escape_char_index = message.find_first_of("\\\n\r");
+ escape_char_index != std::string::npos && written_out < all_content;
+ // record what we've written this iteration, scan for next char that needs escaping
+ written_out = escape_char_index + 1, escape_char_index = message.find_first_of("\\\n\r", written_out)
+ )
+ {
+ // found a character that needs escaping, so write up to that with the escape prefix
+ // note that escape_char_index is relative to the start, not to the written_out offset
+ out << message.substr(written_out, escape_char_index - written_out) << '\\';
+
+ // write out the appropriate second character in the escape sequence
+ char found = message[escape_char_index];
+ switch ( found )
+ {
+ case '\\':
+ out << '\\';
+ break;
+ case '\n':
+ out << 'n';
+ break;
+ case '\r':
+ out << 'r';
+ break;
+ }
+ }
+
+ if ( written_out < all_content ) // if the loop above didn't write everything
+ {
+ // write whatever was left
+ out << message.substr(written_out, std::string::npos);
+ }
+ }
+
+ void writeToRecorders(const LLError::CallSite& site, const std::string& escaped_message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)
{
LLError::ELevel level = site.mLevel;
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
@@ -912,32 +957,37 @@ namespace
std::ostringstream message_stream;
- if (show_time && r->wantsTime() && s->mTimeFunction != NULL)
+ if (r->wantsTime() && s->mTimeFunction != NULL)
{
- message_stream << s->mTimeFunction() << " ";
+ message_stream << s->mTimeFunction();
}
-
+ message_stream << " ";
+
if (show_level && r->wantsLevel())
{
- message_stream << site.mLevelString << " ";
+ message_stream << site.mLevelString;
}
+ message_stream << " ";
- if (show_tags && r->wantsTags())
+ if (r->wantsTags())
{
message_stream << site.mTagString;
}
+ message_stream << " ";
- if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation))
+ if (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)
{
- message_stream << site.mLocationString << " ";
+ message_stream << site.mLocationString;
}
+ message_stream << " ";
if (show_function && r->wantsFunctionName())
{
- message_stream << site.mFunctionString << " ";
+ message_stream << site.mFunctionString;
}
+ message_stream << " : ";
- message_stream << message;
+ message_stream << escaped_message;
r->recordMessage(level, message_stream.str());
}
@@ -1180,11 +1230,6 @@ namespace LLError
delete out;
}
- if (site.mLevel == LEVEL_ERROR)
- {
- writeToRecorders(site, "error", true, true, true, false, false);
- }
-
std::ostringstream message_stream;
if (site.mPrintOnce)
@@ -1210,8 +1255,8 @@ namespace LLError
}
}
- message_stream << message;
-
+ addEscapedMessage(message_stream, message);
+
writeToRecorders(site, message_stream.str());
if (site.mLevel == LEVEL_ERROR && s->mCrashFunction)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index ceb1fd2c5f..0a78229555 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -146,11 +146,22 @@ const int LL_ERR_NOERR = 0;
will result in messages like:
- WARN: LLFoo::doSomething: called with a big value for i: 283
+ WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283
+ the syntax is:
+ <timestamp> SPACE <level> SPACE <tags> SPACE <location> SPACE <function> SPACE COLON SPACE <message>
+
+ where each SPACE is a single space character; note that if a field is empty (such as when no
+ tags are specified), all the SPACEs are still present.
+
+ The tags must be a single word (may not contain a space); if more than one tag is specified,
+ they are all surrounded by '#' ( #FooTag#BarTag# ).
+
Which messages are logged and which are suppressed can be controlled at run
- time from the live file logcontrol.xml based on function, class and/or
- source file. See etc/logcontrol-dev.xml for details.
+ time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml
+ A copy of that file named logcontrol-dev.xml can be made in the users personal settings
+ directory; that will override the installed default file. See the logcontrol.xml
+ file or http://wiki.secondlife.com/wiki/Logging_System_Overview for configuration 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
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 446c312ca9..a618a1cc70 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -610,7 +610,7 @@ private:
value = (uint64_t)(( uint8_t *)&value);
else
{
- LL_WARNS("Unknown type returned from sysctl!") << LL_ENDL;
+ LL_WARNS() << "Unknown type returned from sysctl" << LL_ENDL;
}
}
diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp
index 20de205454..ce0dbce075 100644
--- a/indra/llcommon/tests/llerror_test.cpp
+++ b/indra/llcommon/tests/llerror_test.cpp
@@ -36,6 +36,26 @@
#include "../test/lltut.h"
+enum LogFieldIndex
+{
+ TIME_FIELD,
+ LEVEL_FIELD,
+ TAGS_FIELD,
+ LOCATION_FIELD,
+ FUNCTION_FIELD,
+ MSG_FIELD
+};
+
+static const char* FieldName[] =
+{
+ "TIME",
+ "LEVEL",
+ "TAGS",
+ "LOCATION",
+ "FUNCTION",
+ "MSG"
+};
+
namespace
{
#ifdef __clang__
@@ -58,7 +78,7 @@ namespace tut
class TestRecorder : public LLError::Recorder
{
public:
- TestRecorder() { mWantsTime = false; }
+ TestRecorder() { mWantsTime = false; mWantsTags = true; }
virtual ~TestRecorder() { }
virtual void recordMessage(LLError::ELevel level,
@@ -133,13 +153,64 @@ namespace tut
ensure_equals("message count", countMessages(), expectedCount);
}
- void ensure_message_contains(int n, const std::string& expectedText)
- {
- std::ostringstream test_name;
- test_name << "testing message " << n;
-
- ensure_contains(test_name.str(), message(n), expectedText);
- }
+ std::string message_field(int msgnum, LogFieldIndex fieldnum)
+ {
+ std::ostringstream test_name;
+ test_name << "testing message " << msgnum << ", not enough messages";
+ tut::ensure(test_name.str(), msgnum < countMessages());
+
+ std::string msg(message(msgnum));
+
+ std::string field_value;
+
+ // find the start of the field; fields are separated by a single space
+ size_t scan = 0;
+ int on_field = 0;
+ while ( scan < msg.length() && on_field < fieldnum )
+ {
+ // fields are delimited by one space
+ if ( ' ' == msg[scan] )
+ {
+ if ( on_field < FUNCTION_FIELD )
+ {
+ on_field++;
+ }
+ // except function, which may have embedded spaces so ends with " : "
+ else if ( ( on_field == FUNCTION_FIELD )
+ && ( ':' == msg[scan+1] && ' ' == msg[scan+2] )
+ )
+ {
+ on_field++;
+ scan +=2;
+ }
+ }
+ scan++;
+ }
+ size_t start_field = scan;
+ size_t fieldlen = 0;
+ if ( fieldnum < FUNCTION_FIELD )
+ {
+ fieldlen = msg.find(' ', start_field) - start_field;
+ }
+ else if ( fieldnum == FUNCTION_FIELD )
+ {
+ fieldlen = msg.find(" : ", start_field) - start_field;
+ }
+ else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end
+ {
+ fieldlen = msg.length() - start_field;
+ }
+
+ return msg.substr(start_field, fieldlen);
+ }
+
+ void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText)
+ {
+ std::ostringstream test_name;
+ test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum) << "\"\n ";
+
+ ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText);
+ }
void ensure_message_does_not_contain(int n, const std::string& expectedText)
{
@@ -162,8 +233,8 @@ namespace tut
LL_INFOS() << "test" << LL_ENDL;
LL_INFOS() << "bob" << LL_ENDL;
- ensure_message_contains(0, "test");
- ensure_message_contains(1, "bob");
+ ensure_message_field_equals(0, MSG_FIELD, "test");
+ ensure_message_field_equals(1, MSG_FIELD, "bob");
}
}
@@ -171,11 +242,10 @@ namespace
{
void writeSome()
{
- LL_DEBUGS() << "one" << LL_ENDL;
- LL_INFOS() << "two" << LL_ENDL;
- LL_WARNS() << "three" << LL_ENDL;
- // fatal messages write out an additional "error" message
- LL_ERRS() << "four" << LL_ENDL;
+ LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL;
+ LL_INFOS("WriteTag") << "two" << LL_ENDL;
+ LL_WARNS("WriteTag") << "three" << LL_ENDL;
+ LL_ERRS("WriteTag") << "four" << LL_ENDL;
}
};
@@ -187,37 +257,41 @@ namespace tut
{
LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
writeSome();
- ensure_message_contains(0, "one");
- ensure_message_contains(1, "two");
- ensure_message_contains(2, "three");
- ensure_message_contains(3, "error");
- ensure_message_contains(4, "four");
- ensure_message_count(5);
+ ensure_message_field_equals(0, MSG_FIELD, "one");
+ ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG");
+ ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#");
+ ensure_message_field_equals(1, MSG_FIELD, "two");
+ ensure_message_field_equals(1, LEVEL_FIELD, "INFO");
+ ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#");
+ ensure_message_field_equals(2, MSG_FIELD, "three");
+ ensure_message_field_equals(2, LEVEL_FIELD, "WARNING");
+ ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#");
+ ensure_message_field_equals(3, MSG_FIELD, "four");
+ ensure_message_field_equals(3, LEVEL_FIELD, "ERROR");
+ ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#");
+ ensure_message_count(4);
LLError::setDefaultLevel(LLError::LEVEL_INFO);
writeSome();
- ensure_message_contains(5, "two");
- ensure_message_contains(6, "three");
- ensure_message_contains(7, "error");
- ensure_message_contains(8, "four");
- ensure_message_count(9);
+ ensure_message_field_equals(4, MSG_FIELD, "two");
+ ensure_message_field_equals(5, MSG_FIELD, "three");
+ ensure_message_field_equals(6, MSG_FIELD, "four");
+ ensure_message_count(7);
LLError::setDefaultLevel(LLError::LEVEL_WARN);
writeSome();
- ensure_message_contains(9, "three");
- ensure_message_contains(10, "error");
- ensure_message_contains(11, "four");
- ensure_message_count(12);
+ ensure_message_field_equals(7, MSG_FIELD, "three");
+ ensure_message_field_equals(8, MSG_FIELD, "four");
+ ensure_message_count(9);
LLError::setDefaultLevel(LLError::LEVEL_ERROR);
writeSome();
- ensure_message_contains(12, "error");
- ensure_message_contains(13, "four");
- ensure_message_count(14);
+ ensure_message_field_equals(9, MSG_FIELD, "four");
+ ensure_message_count(10);
LLError::setDefaultLevel(LLError::LEVEL_NONE);
writeSome();
- ensure_message_count(14);
+ ensure_message_count(10);
}
template<> template<>
@@ -225,12 +299,11 @@ namespace tut
// error type string in output
{
writeSome();
- ensure_message_contains(0, "DEBUG: ");
- ensure_message_contains(1, "INFO: ");
- ensure_message_contains(2, "WARNING: ");
- ensure_message_does_not_contain(3, "ERROR");
- ensure_message_contains(4, "ERROR: ");
- ensure_message_count(5);
+ ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG");
+ ensure_message_field_equals(1, LEVEL_FIELD, "INFO");
+ ensure_message_field_equals(2, LEVEL_FIELD, "WARNING");
+ ensure_message_field_equals(3, LEVEL_FIELD, "ERROR");
+ ensure_message_count(4);
}
template<> template<>
@@ -280,7 +353,7 @@ namespace
{
std::ostringstream location;
location << LLError::abbreviateFile(__FILE__)
- << "(" << line << ") : ";
+ << "(" << line << ")";
return location.str();
}
@@ -321,7 +394,7 @@ namespace tut
writeReturningLocation();
ensure_message_does_not_contain(0, location);
- ensure_message_contains(1, location);
+ ensure_message_field_equals(1, LOCATION_FIELD, location);
ensure_message_does_not_contain(2, location);
}
}
@@ -496,13 +569,13 @@ namespace tut
void ErrorTestObject::test<7>()
{
outerLogger();
- ensure_message_contains(0, "inside");
- ensure_message_contains(1, "outside(moo)");
+ ensure_message_field_equals(0, MSG_FIELD, "inside");
+ ensure_message_field_equals(1, MSG_FIELD, "outside(moo)");
ensure_message_count(2);
metaLogger();
- ensure_message_contains(2, "logging");
- ensure_message_contains(3, "meta(baz)");
+ ensure_message_field_equals(2, MSG_FIELD, "logging");
+ ensure_message_field_equals(3, MSG_FIELD, "meta(baz)");
ensure_message_count(4);
}
@@ -513,9 +586,9 @@ namespace tut
LLError::setPrintLocation(false);
std::string location = errorReturningLocation();
- ensure_message_contains(0, location + "error");
- ensure_message_contains(1, "die");
- ensure_message_count(2);
+ ensure_message_field_equals(0, LOCATION_FIELD, location);
+ ensure_message_field_equals(0, MSG_FIELD, "die");
+ ensure_message_count(1);
ensure("fatal callback called", fatalWasCalled);
}
@@ -544,13 +617,13 @@ namespace tut
setWantsTime(false);
ufoSighting();
- ensure_message_contains(0, "ufo");
+ ensure_message_field_equals(0, MSG_FIELD, "ufo");
ensure_message_does_not_contain(0, roswell());
setWantsTime(true);
ufoSighting();
- ensure_message_contains(1, "ufo");
- ensure_message_contains(1, roswell());
+ ensure_message_field_equals(1, MSG_FIELD, "ufo");
+ ensure_message_field_equals(1, TIME_FIELD, roswell());
}
template<> template<>
@@ -564,9 +637,9 @@ namespace tut
function;
writeReturningLocationAndFunction(location, function);
- ensure_equals("order is time location type function message",
+ ensure_equals("order is time level tags location function message",
message(0),
- roswell() + " INFO: " + location + function + ": apple");
+ roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple");
}
template<> template<>
@@ -578,7 +651,7 @@ namespace tut
LL_INFOS() << "boo" << LL_ENDL;
- ensure_message_contains(0, "boo");
+ ensure_message_field_equals(0, MSG_FIELD, "boo");
ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1);
ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo");
@@ -637,14 +710,12 @@ namespace tut
TestAlpha::doAll();
TestBeta::doAll();
- ensure_message_contains(0, "aim west");
- ensure_message_contains(1, "error");
- ensure_message_contains(2, "ate eels");
- ensure_message_contains(3, "buy iron");
- ensure_message_contains(4, "bad word");
- ensure_message_contains(5, "error");
- ensure_message_contains(6, "big easy");
- ensure_message_count(7);
+ ensure_message_field_equals(0, MSG_FIELD, "aim west");
+ ensure_message_field_equals(1, MSG_FIELD, "ate eels");
+ ensure_message_field_equals(2, MSG_FIELD, "buy iron");
+ ensure_message_field_equals(3, MSG_FIELD, "bad word");
+ ensure_message_field_equals(4, MSG_FIELD, "big easy");
+ ensure_message_count(5);
}
template<> template<>
@@ -657,8 +728,8 @@ namespace tut
LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE);
TestBeta::doAll();
- ensure_message_contains(0, "buy iron");
- ensure_message_contains(1, "bad word");
+ ensure_message_field_equals(0, MSG_FIELD, "buy iron");
+ ensure_message_field_equals(1, MSG_FIELD, "bad word");
ensure_message_count(2);
}
@@ -678,9 +749,9 @@ namespace tut
TestAlpha::doAll();
TestBeta::doAll();
- ensure_message_contains(0, "any idea");
- ensure_message_contains(1, "aim west");
- ensure_message_contains(2, "bad word");
+ ensure_message_field_equals(0, MSG_FIELD, "any idea");
+ ensure_message_field_equals(1, MSG_FIELD, "aim west");
+ ensure_message_field_equals(2, MSG_FIELD, "bad word");
ensure_message_count(3);
}
@@ -718,14 +789,13 @@ namespace tut
// configuration from LLSD
void ErrorTestObject::test<16>()
{
- std::string this_file = LLError::abbreviateFile(__FILE__);
LLSD config;
config["print-location"] = true;
config["default-level"] = "DEBUG";
LLSD set1;
set1["level"] = "WARN";
- set1["files"][0] = this_file;
+ set1["files"][0] = LLError::abbreviateFile(__FILE__);
LLSD set2;
set2["level"] = "INFO";
@@ -744,10 +814,9 @@ namespace tut
TestAlpha::doAll();
TestBeta::doAll();
- ensure_message_contains(0, "any idea");
- ensure_message_contains(0, this_file);
- ensure_message_contains(1, "aim west");
- ensure_message_contains(2, "bad word");
+ ensure_message_field_equals(0, MSG_FIELD, "any idea");
+ ensure_message_field_equals(1, MSG_FIELD, "aim west");
+ ensure_message_field_equals(2, MSG_FIELD, "bad word");
ensure_message_count(3);
// make sure reconfiguring works
@@ -758,15 +827,73 @@ namespace tut
TestAlpha::doAll();
TestBeta::doAll();
- ensure_message_contains(3, "aim west");
- ensure_message_does_not_contain(3, this_file);
- ensure_message_contains(4, "error");
- ensure_message_contains(5, "ate eels");
- ensure_message_contains(6, "bad word");
- ensure_message_contains(7, "error");
- ensure_message_contains(8, "big easy");
- ensure_message_count(9);
+ ensure_message_field_equals(3, MSG_FIELD, "aim west");
+ ensure_message_field_equals(4, MSG_FIELD, "ate eels");
+ ensure_message_field_equals(5, MSG_FIELD, "bad word");
+ ensure_message_field_equals(6, MSG_FIELD, "big easy");
+ ensure_message_count(7);
+ }
+}
+
+namespace
+{
+ void writeMsgNeedsEscaping()
+ {
+ LL_DEBUGS("WriteTag") << "backslash\\" << LL_ENDL;
+ LL_INFOS("WriteTag") << "newline\nafternewline" << LL_ENDL;
+ LL_WARNS("WriteTag") << "return\rafterreturn" << LL_ENDL;
+
+ LL_DEBUGS("WriteTag") << "backslash\\backslash\\" << LL_ENDL;
+ LL_INFOS("WriteTag") << "backslash\\newline\nanothernewline\nafternewline" << LL_ENDL;
+ LL_WARNS("WriteTag") << "backslash\\returnnewline\r\n\\afterbackslash" << LL_ENDL;
+ }
+};
+
+namespace tut
+{
+ template<> template<>
+ void ErrorTestObject::test<17>()
+ // backslash, return, and newline are escaped with backslashes
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ writeMsgNeedsEscaping();
+ ensure_message_field_equals(0, MSG_FIELD, "backslash\\\\");
+ ensure_message_field_equals(1, MSG_FIELD, "newline\\nafternewline");
+ ensure_message_field_equals(2, MSG_FIELD, "return\\rafterreturn");
+ ensure_message_field_equals(3, MSG_FIELD, "backslash\\\\backslash\\\\");
+ ensure_message_field_equals(4, MSG_FIELD, "backslash\\\\newline\\nanothernewline\\nafternewline");
+ ensure_message_field_equals(5, MSG_FIELD, "backslash\\\\returnnewline\\r\\n\\\\afterbackslash");
+ ensure_message_count(6);
+ }
+}
+
+namespace
+{
+ std::string writeTagWithSpaceReturningLocation()
+ {
+ LL_DEBUGS("Write Tag") << "not allowed" << LL_ENDL; int this_line = __LINE__;
+
+ std::ostringstream location;
+ location << LLError::abbreviateFile(__FILE__).c_str() << "(" << this_line << ")";
+ return location.str();
}
+};
+
+namespace tut
+{
+ template<> template<>
+ void ErrorTestObject::test<18>()
+ // space character is not allowed in a tag
+ {
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ fatalWasCalled = false;
+
+ std::string location = writeTagWithSpaceReturningLocation();
+ std::string expected = "Space is not allowed in a log tag at " + location;
+ ensure_message_field_equals(0, LEVEL_FIELD, "ERROR");
+ ensure_message_field_equals(0, MSG_FIELD, expected);
+ ensure("fatal callback called", fatalWasCalled);
+ }
}
/* Tests left: