summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-10-28 17:15:40 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-03-25 19:05:17 -0400
commit07134aaee7a39f2141ee8f1e702aa0df989851df (patch)
tree86f7dbfc347881548e718a782c6567032041f46f /indra/llcommon
parentf80b2da513b431b063c74a353d44ffc4a76fa24e (diff)
DRTVWR-476: Try to extend stderr redirection to Windows as well.
Make the LLError::Settings LLSingleton duplicate the file handle for stderr (usually 2) on construction. Make its destructor restore the original target for that file handle. Provide a getDupStderr() method to obtain the duplicate file handle. Move Settings declaration up to the top of the file so other code can reference it. Make RecordToFile (the Recorder subclass engaged by LLError::logToFile()), instead of duplicating stderr's file handle itself, capture the duplicate stderr file handle from Settings to revert stderr redirection on destruction. Make RecordToStderr (the Recorder subclass engaged by LLError::logToStderr()) use fdopen() to create an LLFILE* targeting the duplicate file handle from Settings. Write output to that instead of to stderr so logToStderr() continues to provide output for the user instead of duplicating each line into the log file.
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llerror.cpp118
1 files changed, 79 insertions, 39 deletions
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 6ef0fde886..a8e1481774 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -53,6 +53,46 @@
#include "llstl.h"
#include "lltimer.h"
+#if LL_WINDOWS
+#define fhclose _close
+#define fhdup _dup
+#define fhdup2 _dup2
+#define fhfdopen _fdopen
+#define fhfileno _fileno
+#else
+#define fhclose ::close
+#define fhdup ::dup
+#define fhdup2 ::dup2
+#define fhfdopen ::fdopen
+#define fhfileno ::fileno
+#endif
+
+namespace LLError
+{
+
+ class SettingsConfig;
+ typedef LLPointer<SettingsConfig> SettingsConfigPtr;
+
+ class Settings : public LLSingleton<Settings>
+ {
+ LLSINGLETON(Settings);
+ public:
+ SettingsConfigPtr getSettingsConfig();
+ ~Settings();
+
+ void reset();
+ SettingsStoragePtr saveAndReset();
+ void restore(SettingsStoragePtr pSettingsStorage);
+
+ int getDupStderr() const;
+
+ private:
+ SettingsConfigPtr mSettingsConfig;
+ int mDupStderr;
+ };
+
+} // namespace LLError
+
namespace {
#if LL_WINDOWS
void debugger_print(const std::string& s)
@@ -120,7 +160,8 @@ namespace {
public:
RecordToFile(const std::string& filename):
mName(filename),
- mFile(LLFile::fopen(filename, "a"))
+ mFile(LLFile::fopen(filename, "a")),
+ mSavedStderr(LLError::Settings::instance().getDupStderr())
{
if (!mFile)
{
@@ -128,25 +169,19 @@ namespace {
}
else
{
-#if LL_DARWIN || LL_LINUX
// We use a number of classic-C libraries, some of which write
// log output to stderr. The trouble with that is that unless
// you launch the viewer from a console, stderr output is
// lost. Redirect STDERR_FILENO to write into this log file.
- // But first, save the original stream in case we want it later.
- mSavedStderr = ::dup(STDERR_FILENO);
- ::dup2(::fileno(mFile), STDERR_FILENO);
-#endif
+ fhdup2(fhfileno(mFile), fhfileno(stderr));
}
}
~RecordToFile()
{
-#if LL_DARWIN || LL_LINUX
// restore stderr to its original fileno so any subsequent output
// to stderr goes to original stream
- ::dup2(mSavedStderr, STDERR_FILENO);
-#endif
+ fhdup2(mSavedStderr, fhfileno(stderr));
mFile.close();
}
@@ -166,7 +201,8 @@ namespace {
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
{
- fwrite(message.c_str(), sizeof(char), message.length(), mFile);
+ ::fwrite(message.c_str(), sizeof(char), message.length(), mFile);
+ ::fputc('\n', mFile);
if (LLError::getAlwaysFlush())
{
::fflush(mFile);
@@ -176,22 +212,26 @@ namespace {
private:
const std::string mName;
LLUniqueFile mFile;
- int mSavedStderr{0};
+ int mSavedStderr;
};
class RecordToStderr : public LLError::Recorder
{
public:
- RecordToStderr(bool timestamp) : mUseANSI(checkANSI())
+ RecordToStderr(bool timestamp) :
+ mUseANSI(checkANSI()),
+ // use duplicate stderr file handle so THIS output isn't affected
+ // by our internal redirection of all (other) stderr output
+ mStderr(fhfdopen(LLError::Settings::instance().getDupStderr(), "a"))
{
- this->showMultiline(true);
+ this->showMultiline(true);
+ }
+
+ virtual bool enabled() override
+ {
+ return LLError::getEnabledLogTypesMask() & 0x04;
}
-
- virtual bool enabled() override
- {
- return LLError::getEnabledLogTypesMask() & 0x04;
- }
virtual void recordMessage(LLError::ELevel level,
const std::string& message) override
@@ -214,17 +254,18 @@ namespace {
break;
}
}
- fprintf(stderr, "%s\n", message.c_str());
+ fprintf(mStderr, "%s\n", message.c_str());
if (mUseANSI) colorANSI("0"); // reset
}
-
+
private:
bool mUseANSI;
+ LLFILE* mStderr;
void colorANSI(const std::string color)
{
// ANSI color code escape sequence
- fprintf(stderr, "\033[%sm", color.c_str() );
+ fprintf(mStderr, "\033[%sm", color.c_str() );
};
static bool checkANSI(void)
@@ -233,7 +274,7 @@ namespace {
// Check whether it's okay to use ANSI; if stderr is
// a tty then we assume yes. Can be turned off with
// the LL_NO_ANSI_COLOR env var.
- return (0 != isatty(2)) &&
+ return (0 != isatty(fhfileno(stderr))) &&
(NULL == getenv("LL_NO_ANSI_COLOR"));
#endif // LL_LINUX
return false;
@@ -504,22 +545,6 @@ namespace LLError
SettingsConfig();
};
- typedef LLPointer<SettingsConfig> SettingsConfigPtr;
-
- class Settings : public LLSingleton<Settings>
- {
- LLSINGLETON(Settings);
- public:
- SettingsConfigPtr getSettingsConfig();
-
- void reset();
- SettingsStoragePtr saveAndReset();
- void restore(SettingsStoragePtr pSettingsStorage);
-
- private:
- SettingsConfigPtr mSettingsConfig;
- };
-
SettingsConfig::SettingsConfig()
: LLRefCount(),
mDefaultLevel(LLError::LEVEL_DEBUG),
@@ -543,8 +568,18 @@ namespace LLError
}
Settings::Settings():
- mSettingsConfig(new SettingsConfig())
+ mSettingsConfig(new SettingsConfig()),
+ // duplicate stderr file handle right away
+ mDupStderr(fhdup(fhfileno(stderr)))
+ {
+ }
+
+ Settings::~Settings()
{
+ // restore original stderr
+ fhdup2(mDupStderr, fhfileno(stderr));
+ // and close the duplicate
+ fhclose(mDupStderr);
}
SettingsConfigPtr Settings::getSettingsConfig()
@@ -572,6 +607,11 @@ namespace LLError
mSettingsConfig = newSettingsConfig;
}
+ int Settings::getDupStderr() const
+ {
+ return mDupStderr;
+ }
+
bool is_available()
{
return Settings::instanceExists() && Globals::instanceExists();