diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2019-10-28 17:15:40 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2020-03-25 19:05:17 -0400 |
commit | 07134aaee7a39f2141ee8f1e702aa0df989851df (patch) | |
tree | 86f7dbfc347881548e718a782c6567032041f46f /indra/llcommon | |
parent | f80b2da513b431b063c74a353d44ffc4a76fa24e (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.cpp | 118 |
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(); |