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
parent
efb249b6d4
commit
267512126d
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue