Remove wide-strings as they are more trouble than they are worth

these were only ever wide strings because the BS API for windows had that. This is now written to XML.
master
Beq 2024-12-13 12:25:13 +00:00
parent efb249b6d4
commit 267512126d
4 changed files with 83 additions and 96 deletions

View File

@ -1,9 +1,8 @@
#include "bugsplatattributes.h"
#include "llstring.h"
#include <fstream>
#include <filesystem>
std::wstring BugSplatAttributes::mCrashContextFileName;
std::string BugSplatAttributes::mCrashContextFileName;
BugSplatAttributes& BugSplatAttributes::instance()
{
@ -15,46 +14,46 @@ BugSplatAttributes& BugSplatAttributes::instance()
#include <string>
#include <cctype>
std::wstring BugSplatAttributes::to_xml_token(const std::wstring& input)
std::string BugSplatAttributes::to_xml_token(const std::string& input)
{
// Example usage:
// std::wstring token = to_xml_token(L"Bandwidth (kbit/s)");
// The result should be: L"Bandwidth_kbit_per_s"
std::wstring result;
std::string result;
result.reserve(input.size() * 2); // Reserve some space, since we might insert more chars for "/"
for (wchar_t ch : input)
for (char ch : input)
{
if (ch == L'/')
if (ch == '/')
{
// Replace '/' with "_per_"
result.append(L"_per_");
result.append("_per_");
}
else if (std::iswalnum(ch) || ch == L'_' || ch == L'-')
else if (std::isalnum(ch) || ch == '_' || ch == '-')
{
// Letters, digits, underscore, and hyphen are okay
result.push_back(ch);
}
else if (ch == L' ' || ch == L'(' || ch == L')')
else if (ch == ' ' || ch == '(' || ch == ')')
{
// Replace spaces and parentheses with underscore
result.push_back(L'_');
result.push_back('_');
}
else
{
// Other characters map to underscore
result.push_back(L'_');
result.push_back('_');
}
}
// Ensure the first character is a letter or underscore:
// If not, prepend underscore.
if (result.empty() || !(std::iswalpha(result.front()) || result.front() == L'_'))
if (result.empty() || !(std::isalpha(result.front()) || result.front() == '_'))
{
result.insert(result.begin(), L'_');
result.insert(result.begin(), '_');
}
// trim trailing underscores
while (!result.empty() && result.back() == L'_')
while (!result.empty() && result.back() == '_')
{
result.pop_back();
}
@ -63,23 +62,14 @@ std::wstring BugSplatAttributes::to_xml_token(const std::wstring& input)
bool BugSplatAttributes::writeToFile(const std::wstring& file_path)
bool BugSplatAttributes::writeToFile(const std::string& file_path)
{
std::lock_guard<std::mutex> lock(mMutex);
// Write to a temporary file first
#ifdef LL_WINDOWS
std::wstring tmp_file = file_path + L".tmp";
#else // use non-wide characters for Linux and Mac
std::string tmp_file = ll_convert_wide_to_string(file_path) + ".tmp";
#endif
std::string tmp_file = file_path + ".tmp";
{
#ifdef LL_WINDOWS
std::wofstream ofs(tmp_file, std::ios::out | std::ios::trunc);
#else // use non-wide characters for Linux and Mac
std::ofstream ofs(tmp_file, std::ios::out | std::ios::trunc);
#endif
if (!ofs.good())
{
return false;
@ -89,21 +79,21 @@ bool BugSplatAttributes::writeToFile(const std::wstring& file_path)
ofs << L"<XmlCrashContext>\n";
// First, write out attributes that have an empty category (top-level)
auto empty_category_it = mAttributes.find(L"");
auto empty_category_it = mAttributes.find("");
if (empty_category_it != mAttributes.end())
{
for (const auto& kv : empty_category_it->second)
{
const std::wstring& key = kv.first;
const std::wstring& val = kv.second;
ofs << L" <" << key << L">" << val << L"</" << key << L">\n";
const std::string& key = kv.first;
const std::string& val = kv.second;
ofs << " <" << key << ">" << val << "</" << key << ">\n";
}
}
// Write out all other categories
for (const auto& cat_pair : mAttributes)
{
const std::wstring& category = cat_pair.first;
const std::string& category = cat_pair.first;
// Skip empty category since we already handled it above
if (category.empty())
@ -111,17 +101,17 @@ bool BugSplatAttributes::writeToFile(const std::wstring& file_path)
continue;
}
ofs << L" <" << category << L">\n";
ofs << " <" << category << ">\n";
for (const auto& kv : cat_pair.second)
{
const std::wstring& key = kv.first;
const std::wstring& val = kv.second;
ofs << L" <" << key << L">" << val << L"</" << key << L">\n";
const std::string& key = kv.first;
const std::string& val = kv.second;
ofs << " <" << key << ">" << val << "</" << key << ">\n";
}
ofs << L" </" << category << L">\n";
ofs << " </" << category << ">\n";
}
ofs << L"</XmlCrashContext>\n";
ofs << "</XmlCrashContext>\n";
// Close the file before renaming
ofs.close();

View File

@ -14,57 +14,55 @@ public:
static BugSplatAttributes& instance();
template<typename T>
void setAttribute(const std::wstring& key, const T& value, const std::wstring& category = L"FS")
void setAttribute(const std::string& key, const T& value, const std::string& category = "FS")
{
std::lock_guard<std::mutex> lock(mMutex);
const auto& xml_key = to_xml_token(key);
if constexpr (std::is_same_v<T, std::wstring>)
if constexpr (std::is_same_v<T, std::string>)
{
// Already wide string
mAttributes[category][xml_key] = value;
}
else if constexpr (std::is_same_v<T, const wchar_t*> || std::is_array_v<T>)
else if constexpr (std::is_same_v<T, std::wstring>)
{
// Handle wide string literals and arrays (which includes string literals)
mAttributes[category][xml_key] = std::wstring(value);
// Wide to narrow
mAttributes[category][xml_key] = ll_convert_wide_to_string(value);
}
else if constexpr (std::is_same_v<T, std::string>)
else if constexpr (std::is_same_v<T, const char*> || std::is_array_v<T>)
{
// Convert narrow to wide
std::wstring wide_value(value.begin(), value.end());
mAttributes[category][xml_key] = wide_value;
// Handle string literals and arrays (which includes string literals)
mAttributes[category][xml_key] = std::string(value);
}
else if constexpr (std::is_same_v<T, bool>)
{
// Convert boolean to "true"/"false"
mAttributes[category][xml_key] = value ? L"true" : L"false";
mAttributes[category][xml_key] = value ? "true" : "false";
}
else if constexpr (std::is_arithmetic_v<T>)
{
// Convert arithmetic types (int, float, double, etc.) to wstring
mAttributes[category][xml_key] = std::to_wstring(value);
mAttributes[category][xml_key] = std::to_string(value);
}
else
{
static_assert(!sizeof(T*), "No known conversion for this type to std::wstring.");
static_assert(!sizeof(T*), "No known conversion for this type to std::string.");
}
}
// Returns true on success, false on failure.
bool writeToFile(const std::wstring& file_path);
const static std::wstring& getCrashContextFileName() { return mCrashContextFileName; }
static void setCrashContextFileName(const std::wstring& file_name) { mCrashContextFileName = file_name; }
bool writeToFile(const std::string& file_path);
const static std::string& getCrashContextFileName() { return mCrashContextFileName; }
static void setCrashContextFileName(const std::string& file_name) { mCrashContextFileName = file_name; }
private:
BugSplatAttributes() = default;
~BugSplatAttributes() = default;
BugSplatAttributes(const BugSplatAttributes&) = delete;
BugSplatAttributes& operator=(const BugSplatAttributes&) = delete;
std::wstring to_xml_token(const std::wstring& input);
std::string to_xml_token(const std::string& input);
// Internal structure to hold attributes by category
// For example:
// attributes_["RuntimeProperties"]["CrashGUID"] = L"649F57B7EE6E92A0_0000"
std::unordered_map<std::wstring, std::unordered_map<std::wstring, std::wstring>> mAttributes;
// mAttributes["RuntimeProperties"]["CrashGUID"] = "649F57B7EE6E92A0_0000"
std::unordered_map<std::string, std::unordered_map<std::string, std::string>> mAttributes;
std::mutex mMutex;
static std::wstring mCrashContextFileName;
static std::string mCrashContextFileName;
};
#endif // LL_BUGSPLAT

View File

@ -767,9 +767,8 @@ LLAppViewer::LLAppViewer()
// MAINT-8917: don't create a dump directory just for the
// static_debug_info.log file
std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
// <FS:Beq> Improve Bugsplat tracking by using attribu
std::wstring wlogdir(logdir.begin(), logdir.end());
BugSplatAttributes::setCrashContextFileName(wlogdir + L"crash-context.xml");
// <FS:Beq> Improve Bugsplat tracking by using attributes
BugSplatAttributes::setCrashContextFileName(logdir + "crash-context.xml");
// </FS:Beq>
# else // ! LL_BUGSPLAT
// write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.

View File

@ -165,7 +165,7 @@ namespace
flavor = "oss";
#endif
sBugSplatSender->setDefaultUserEmail( WCSTR(STRINGIZE(LLOSInfo::instance().getOSStringSimple() << " (" << ADDRESS_SIZE << "-bit, flavor " << flavor <<")")));
// BugSplatAttributes::instance().setAttribute(L"Flavor", flavor);
BugSplatAttributes::instance().setAttribute("Flavor", flavor);
// </FS:ND>
//<FS:ND/> Clear out username first, as we get some crashes that has the OS set as username, let's see if this fixes it. Use Crash.Linden as a usr can never have a "Linden"
@ -211,9 +211,9 @@ namespace
auto fatal_message = LLError::getFatalMessage();
sBugSplatSender->setDefaultUserDescription(WCSTR(fatal_message));
BugSplatAttributes::instance().setAttribute(L"FatalMessage", fatal_message); // <FS:Beq/> Store this additionally as an attribute in case user overwrites.
BugSplatAttributes::instance().setAttribute("FatalMessage", fatal_message); // <FS:Beq/> Store this additionally as an attribute in case user overwrites.
// App state
BugSplatAttributes::instance().setAttribute(L"AppState", LLStartUp::getStartupStateString());
BugSplatAttributes::instance().setAttribute("AppState", LLStartUp::getStartupStateString());
// Location
// </FS:Beq>
if (gAgent.getRegion())
@ -232,7 +232,7 @@ namespace
<< '/' << loc.mV[1]
<< '/' << loc.mV[2]);
sBugSplatSender->resetAppIdentifier(WCSTR(fullLocation));
BugSplatAttributes::instance().setAttribute(L"Location", std::string(fullLocation));
BugSplatAttributes::instance().setAttribute("Location", std::string(fullLocation));
// </FS:Beq>
}
// <FS:Beq> Improve bugsplat reporting with attributes
@ -655,51 +655,51 @@ void LLAppViewerWin32::bugsplatAddStaticAttributes(const LLSD& info)
{
write_statics = false;
auto multipleInstances = gDebugInfo["FoundOtherInstanceAtStartup"].asBoolean();
bugSplatMap.setAttribute(L"MultipleInstance", multipleInstances);
bugSplatMap.setAttribute("MultipleInstance", multipleInstances);
bugSplatMap.setAttribute(L"GPU", info["GRAPHICS_CARD"].asString());
bugSplatMap.setAttribute(L"GPU VRAM (MB)", info["GRAPHICS_CARD_MEMORY"].asInteger());
bugSplatMap.setAttribute(L"GPU VRAM Detected (MB)", info["GRAPHICS_CARD_MEMORY_DETECTED"].asInteger());
bugSplatMap.setAttribute(L"GPU VRAM (Budget)", info["VRAM_BUDGET_ENGLISH"].asInteger());
bugSplatMap.setAttribute("GPU", info["GRAPHICS_CARD"].asString());
bugSplatMap.setAttribute("GPU VRAM (MB)", info["GRAPHICS_CARD_MEMORY"].asInteger());
bugSplatMap.setAttribute("GPU VRAM Detected (MB)", info["GRAPHICS_CARD_MEMORY_DETECTED"].asInteger());
bugSplatMap.setAttribute("GPU VRAM (Budget)", info["VRAM_BUDGET_ENGLISH"].asInteger());
bugSplatMap.setAttribute(L"CPU", info["CPU"].asString());
bugSplatMap.setAttribute(L"Graphics Driver", info["GRAPHICS_DRIVER_VERSION"].asString());
bugSplatMap.setAttribute(L"CPU MHz", (S32)gSysCPU.getMHz()); //
bugSplatMap.setAttribute("CPU", info["CPU"].asString());
bugSplatMap.setAttribute("Graphics Driver", info["GRAPHICS_DRIVER_VERSION"].asString());
bugSplatMap.setAttribute("CPU MHz", (S32)gSysCPU.getMHz()); //
#ifdef USE_AVX2_OPTIMIZATION
bugSplatMap.setAttribute(L"SIMD", L"AVX2");
bugSplatMap.setAttribute("SIMD", "AVX2");
#elif USE_AVX_OPTIMIZATION
bugSplatMap.setAttribute(L"SIMD", L"AVX");
bugSplatMap.setAttribute("SIMD", "AVX");
#else
bugSplatMap.setAttribute(L"SIMD", L"SSE2");
bugSplatMap.setAttribute("SIMD", "SSE2");
#endif
// set physical ram integer as a string attribute
bugSplatMap.setAttribute(L"Physical RAM (KB)", LLMemory::getMaxMemKB().value());
bugSplatMap.setAttribute(L"OpenGL Version", info["OPENGL_VERSION"].asString());
bugSplatMap.setAttribute(L"libcurl Version", info["LIBCURL_VERSION"].asString());
bugSplatMap.setAttribute(L"J2C Decoder Version", info["J2C_VERSION"].asString());
bugSplatMap.setAttribute(L"Audio Driver Version", info["AUDIO_DRIVER_VERSION"].asString());
// bugSplatMap.setAttribute(L"CEF Info", info["LIBCEF_VERSION"].asString());
bugSplatMap.setAttribute(L"LibVLC Version", info["LIBVLC_VERSION"].asString());
bugSplatMap.setAttribute(L"Vivox Version", info["VOICE_VERSION"].asString());
bugSplatMap.setAttribute(L"RLVa", info["RLV_VERSION"].asString());
bugSplatMap.setAttribute(L"Mode", info["MODE"].asString());
bugSplatMap.setAttribute(L"Skin", llformat("%s (%s)", info["SKIN"].asString().c_str(), info["THEME"].asString().c_str()));
bugSplatMap.setAttribute("Physical RAM (KB)", LLMemory::getMaxMemKB().value());
bugSplatMap.setAttribute("OpenGL Version", info["OPENGL_VERSION"].asString());
bugSplatMap.setAttribute("libcurl Version", info["LIBCURL_VERSION"].asString());
bugSplatMap.setAttribute("J2C Decoder Version", info["J2C_VERSION"].asString());
bugSplatMap.setAttribute("Audio Driver Version", info["AUDIO_DRIVER_VERSION"].asString());
// bugSplatMap.setAttribute("CEF Info", info["LIBCEF_VERSION"].asString());
bugSplatMap.setAttribute("LibVLC Version", info["LIBVLC_VERSION"].asString());
bugSplatMap.setAttribute("Vivox Version", info["VOICE_VERSION"].asString());
bugSplatMap.setAttribute("RLVa", info["RLV_VERSION"].asString());
bugSplatMap.setAttribute("Mode", info["MODE"].asString());
bugSplatMap.setAttribute("Skin", llformat("%s (%s)", info["SKIN"].asString().c_str(), info["THEME"].asString().c_str()));
#if LL_DARWIN
bugSplatMap.setAttribute(L"HiDPI", info["HIDPI"].asBoolean() ? L"Enabled" : L"Disabled");
bugSplatMap.setAttribute("HiDPI", info["HIDPI"].asBoolean() ? "Enabled" : "Disabled");
#endif
}
// These attributes are potentially dynamic
bugSplatMap.setAttribute(L"Packets Lost", llformat("%.0f/%.0f (%.1f%%)", info["PACKETS_LOST"].asReal(), info["PACKETS_IN"].asReal(), info["PACKETS_PCT"].asReal()));
bugSplatMap.setAttribute(L"Window Size", llformat("%sx%s px", info["WINDOW_WIDTH"].asString().c_str(), info["WINDOW_HEIGHT"].asString().c_str()));
bugSplatMap.setAttribute(L"Draw Distance (m)", info["DRAW_DISTANCE"].asInteger());
bugSplatMap.setAttribute(L"Bandwidth (kbit/s)", info["BANDWIDTH"].asInteger());
bugSplatMap.setAttribute(L"LOD Factor", info["LOD"].asReal());
bugSplatMap.setAttribute(L"Render quality", info["RENDERQUALITY_FSDATA_ENGLISH"].asString());
bugSplatMap.setAttribute(L"Disk Cache", info["DISK_CACHE_INFO"].asString());
bugSplatMap.setAttribute("Packets Lost", llformat("%.0f/%.0f (%.1f%%)", info["PACKETS_LOST"].asReal(), info["PACKETS_IN"].asReal(), info["PACKETS_PCT"].asReal()));
bugSplatMap.setAttribute("Window Size", llformat("%sx%s px", info["WINDOW_WIDTH"].asString().c_str(), info["WINDOW_HEIGHT"].asString().c_str()));
bugSplatMap.setAttribute("Draw Distance (m)", info["DRAW_DISTANCE"].asInteger());
bugSplatMap.setAttribute("Bandwidth (kbit/s)", info["BANDWIDTH"].asInteger());
bugSplatMap.setAttribute("LOD Factor", info["LOD"].asReal());
bugSplatMap.setAttribute("Render quality", info["RENDERQUALITY_FSDATA_ENGLISH"].asString());
bugSplatMap.setAttribute("Disk Cache", info["DISK_CACHE_INFO"].asString());
bugSplatMap.setAttribute(L"GridName", gDebugInfo["GridName"].asString());
bugSplatMap.setAttribute(L"Available RAM (KB)", LLMemory::getAvailableMemKB().value());
bugSplatMap.setAttribute(L"Allocated RAM (KB)", LLMemory::getAllocatedMemKB().value());
bugSplatMap.setAttribute("GridName", gDebugInfo["GridName"].asString());
bugSplatMap.setAttribute("Available RAM (KB)", LLMemory::getAvailableMemKB().value());
bugSplatMap.setAttribute("Allocated RAM (KB)", LLMemory::getAllocatedMemKB().value());
if (bugSplatMap.writeToFile(BugSplatAttributes::getCrashContextFileName()))
{