llcrashlogger.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:11k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1.  /** 
  2. * @file llcrashlogger.cpp
  3. * @brief Crash logger implementation
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewergpl$
  6. * Copyright (c) 2003-2010, Linden Research, Inc.
  7. * Second Life Viewer Source Code
  8. * The source code in this file ("Source Code") is provided by Linden Lab
  9. * to you under the terms of the GNU General Public License, version 2.0
  10. * ("GPL"), unless you have obtained a separate licensing agreement
  11. * ("Other License"), formally executed by you and Linden Lab.  Terms of
  12. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  13. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  14. * There are special exceptions to the terms and conditions of the GPL as
  15. * it is applied to this Source Code. View the full text of the exception
  16. * in the file doc/FLOSS-exception.txt in this software distribution, or
  17. * online at
  18. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  19. * By copying, modifying or distributing this software, you acknowledge
  20. * that you have read and understood your obligations described above,
  21. * and agree to abide by those obligations.
  22. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  23. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  24. * COMPLETENESS OR PERFORMANCE.
  25. * $/LicenseInfo$
  26. */
  27. #include <cstdio>
  28. #include <cstdlib>
  29. #include <sstream>
  30. #include <map>
  31. #include "llcrashlogger.h"
  32. #include "linden_common.h"
  33. #include "llstring.h"
  34. #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
  35. #include "llerror.h"
  36. #include "lltimer.h"
  37. #include "lldir.h"
  38. #include "llsdserialize.h"
  39. #include "lliopipe.h"
  40. #include "llpumpio.h"
  41. #include "llhttpclient.h"
  42. #include "llsdserialize.h"
  43. LLPumpIO* gServicePump;
  44. BOOL gBreak = false;
  45. BOOL gSent = false;
  46. class LLCrashLoggerResponder : public LLHTTPClient::Responder
  47. {
  48. public:
  49. LLCrashLoggerResponder() 
  50. {
  51. }
  52. virtual void error(U32 status, const std::string& reason)
  53. {
  54. gBreak = true;
  55. }
  56. virtual void result(const LLSD& content)
  57. {
  58. gBreak = true;
  59. gSent = true;
  60. }
  61. };
  62. bool LLCrashLoggerText::mainLoop()
  63. {
  64. std::cout << "Entering main loop" << std::endl;
  65. sendCrashLogs();
  66. return true;
  67. }
  68. void LLCrashLoggerText::updateApplication(const std::string& message)
  69. {
  70. LLCrashLogger::updateApplication(message);
  71. std::cout << message << std::endl;
  72. }
  73. LLCrashLogger::LLCrashLogger() :
  74. mCrashBehavior(CRASH_BEHAVIOR_ASK),
  75. mCrashInPreviousExec(false),
  76. mCrashSettings("CrashSettings"),
  77. mSentCrashLogs(false),
  78. mCrashHost("")
  79. {
  80. // Set up generic error handling
  81. setupErrorHandling();
  82. }
  83. LLCrashLogger::~LLCrashLogger()
  84. {
  85. }
  86. // TRIM_SIZE must remain larger than LINE_SEARCH_SIZE.
  87. const int TRIM_SIZE = 128000;
  88. const int LINE_SEARCH_DIST = 500;
  89. const std::string SKIP_TEXT = "n ...Skipping... n";
  90. void trimSLLog(std::string& sllog)
  91. {
  92. if(sllog.length() > TRIM_SIZE * 2)
  93. {
  94. std::string::iterator head = sllog.begin() + TRIM_SIZE;
  95. std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE;
  96. std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, 'n');
  97. if(new_head != head - LINE_SEARCH_DIST)
  98. {
  99. head = new_head;
  100. }
  101. std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, 'n');
  102. if(new_tail != tail + LINE_SEARCH_DIST)
  103. {
  104. tail = new_tail;
  105. }
  106. sllog.erase(head, tail);
  107. sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end());
  108. }
  109. }
  110. std::string getStartupStateFromLog(std::string& sllog)
  111. {
  112. std::string startup_state = "STATE_FIRST";
  113. std::string startup_token = "Startup state changing from ";
  114. int index = sllog.rfind(startup_token);
  115. if (index < 0 || index + startup_token.length() > sllog.length()) {
  116. return startup_state;
  117. }
  118. // find new line
  119. char cur_char = sllog[index + startup_token.length()];
  120. std::string::size_type newline_loc = index + startup_token.length();
  121. while(cur_char != 'n' && newline_loc < sllog.length())
  122. {
  123. newline_loc++;
  124. cur_char = sllog[newline_loc];
  125. }
  126. // get substring and find location of " to "
  127. std::string state_line = sllog.substr(index, newline_loc - index);
  128. std::string::size_type state_index = state_line.find(" to ");
  129. startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4);
  130. return startup_state;
  131. }
  132. void LLCrashLogger::gatherFiles()
  133. {
  134. /*
  135. //TODO:This function needs to be reimplemented somewhere in here...
  136. if(!previous_crash && is_crash_log)
  137. {
  138. // Make sure the file isn't too old.
  139. double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec);
  140. // llinfos << "age is " << age << llendl;
  141. if(age > 60.0)
  142. {
  143. // The file was last modified more than 60 seconds before the crash reporter was launched.  Assume it's stale.
  144. llwarns << "File " << mFilename << " is too old!" << llendl;
  145. return;
  146. }
  147. }
  148. */
  149. updateApplication("Gathering logs...");
  150. // Figure out the filename of the debug log
  151. std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
  152. std::ifstream debug_log_file(db_file_name.c_str());
  153. // Look for it in the debug_info.log file
  154. if (debug_log_file.is_open())
  155. {
  156. LLSDSerialize::fromXML(mDebugLog, debug_log_file);
  157. mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean();
  158. mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
  159. mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
  160. if(mDebugLog.has("CAFilename"))
  161. {
  162. LLCurl::setCAFile(mDebugLog["CAFilename"].asString());
  163. }
  164. else
  165. {
  166. LLCurl::setCAFile(gDirUtilp->getCAFile());
  167. }
  168. llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl;
  169. llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl;
  170. }
  171. else
  172. {
  173. // Figure out the filename of the second life log
  174. LLCurl::setCAFile(gDirUtilp->getCAFile());
  175. mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
  176. mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
  177. }
  178. #if !LL_DARWIN
  179. if(mCrashInPreviousExec)
  180. #else
  181. #endif
  182. {
  183. // Replace the log file ext with .old, since the 
  184. // instance that launched this process has overwritten
  185. // SecondLife.log
  186. std::string log_filename = mFileMap["SecondLifeLog"];
  187. log_filename.replace(log_filename.size() - 4, 4, ".old");
  188. mFileMap["SecondLifeLog"] = log_filename;
  189. }
  190. gatherPlatformSpecificFiles();
  191. //Use the debug log to reconstruct the URL to send the crash report to
  192. if(mDebugLog.has("CurrentSimHost"))
  193. {
  194. mCrashHost = "https://";
  195. mCrashHost += mDebugLog["CurrentSimHost"].asString();
  196. mCrashHost += ":12043/crash/report";
  197. }
  198. else if(mDebugLog.has("GridName"))
  199. {
  200. // This is a 'little' hacky, but its the best simple solution.
  201. std::string grid_host = mDebugLog["GridName"].asString();
  202. LLStringUtil::toLower(grid_host);
  203. mCrashHost = "https://login.";
  204. mCrashHost += grid_host;
  205. mCrashHost += ".lindenlab.com:12043/crash/report";
  206. }
  207. // Use login servers as the alternate, since they are already load balanced and have a known name
  208. mAltCrashHost = "https://login.agni.lindenlab.com:12043/crash/report";
  209. mCrashInfo["DebugLog"] = mDebugLog;
  210. mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
  211. mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
  212. updateApplication("Encoding files...");
  213. for(std::map<std::string, std::string>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
  214. {
  215. std::ifstream f((*itr).second.c_str());
  216. if(!f.is_open())
  217. {
  218. std::cout << "Can't find file " << (*itr).second << std::endl;
  219. continue;
  220. }
  221. std::stringstream s;
  222. s << f.rdbuf();
  223. std::string crash_info = s.str();
  224. if(itr->first == "SecondLifeLog")
  225. {
  226. if(!mCrashInfo["DebugLog"].has("StartupState"))
  227. {
  228. mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info);
  229. }
  230. trimSLLog(crash_info);
  231. }
  232. mCrashInfo[(*itr).first] = rawstr_to_utf8(crash_info);
  233. }
  234. }
  235. LLSD LLCrashLogger::constructPostData()
  236. {
  237. LLSD ret;
  238. return mCrashInfo;
  239. }
  240. S32 LLCrashLogger::loadCrashBehaviorSetting()
  241. {
  242. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
  243. mCrashSettings.loadFromFile(filename);
  244. S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
  245. if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK;
  246. return value;
  247. }
  248. bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior)
  249. {
  250. if (crash_behavior != CRASH_BEHAVIOR_ASK && crash_behavior != CRASH_BEHAVIOR_ALWAYS_SEND) return false;
  251. mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior);
  252. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
  253. mCrashSettings.saveToFile(filename, FALSE);
  254. return true;
  255. }
  256. bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout)
  257. {
  258. gBreak = false;
  259. std::string status_message;
  260. for(int i = 0; i < retries; ++i)
  261. {
  262. status_message = llformat("%s, try %d...", msg.c_str(), i+1);
  263. LLHTTPClient::post(host, data, new LLCrashLoggerResponder(), timeout);
  264. while(!gBreak)
  265. {
  266. updateApplication(status_message);
  267. }
  268. if(gSent)
  269. {
  270. return gSent;
  271. }
  272. }
  273. return gSent;
  274. }
  275. bool LLCrashLogger::sendCrashLogs()
  276. {
  277. gatherFiles();
  278. LLSD post_data;
  279. post_data = constructPostData();
  280. updateApplication("Sending reports...");
  281. std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
  282.    "SecondLifeCrashReport");
  283. std::string report_file = dump_path + ".log";
  284. std::ofstream out_file(report_file.c_str());
  285. LLSDSerialize::toPrettyXML(post_data, out_file);
  286. out_file.close();
  287. bool sent = false;
  288. //*TODO: Translate
  289. if(mCrashHost != "")
  290. {
  291. sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3, 5);
  292. }
  293. if(!sent)
  294. {
  295. sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3, 5);
  296. }
  297. mSentCrashLogs = sent;
  298. return true;
  299. }
  300. void LLCrashLogger::updateApplication(const std::string& message)
  301. {
  302. gServicePump->pump();
  303.     gServicePump->callback();
  304. }
  305. bool LLCrashLogger::init()
  306. {
  307. // We assume that all the logs we're looking for reside on the current drive
  308. gDirUtilp->initAppDirs("SecondLife");
  309. // Default to the product name "Second Life" (this is overridden by the -name argument)
  310. mProductName = "Second Life";
  311. mCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes "
  312. "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)");
  313. llinfos << "Loading crash behavior setting" << llendl;
  314. mCrashBehavior = loadCrashBehaviorSetting();
  315. // If user doesn't want to send, bail out
  316. if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND)
  317. {
  318. llinfos << "Crash behavior is never_send, quitting" << llendl;
  319. return false;
  320. }
  321. gServicePump = new LLPumpIO(gAPRPoolp);
  322. gServicePump->prime(gAPRPoolp);
  323. LLHTTPClient::setPump(*gServicePump);
  324. //If we've opened the crash logger, assume we can delete the marker file if it exists
  325. if( gDirUtilp )
  326. {
  327. std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker");
  328. LLAPRFile::remove( marker_file );
  329. }
  330. return true;
  331. }