aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcrashlogger/llcrashlogger.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xlinden/indra/llcrashlogger/llcrashlogger.cpp602
1 files changed, 305 insertions, 297 deletions
diff --git a/linden/indra/llcrashlogger/llcrashlogger.cpp b/linden/indra/llcrashlogger/llcrashlogger.cpp
index d53e684..3823abf 100755
--- a/linden/indra/llcrashlogger/llcrashlogger.cpp
+++ b/linden/indra/llcrashlogger/llcrashlogger.cpp
@@ -1,7 +1,7 @@
1 /** 1 /**
2* @file llcrashlogger.cpp 2* @file llcrashlogger.cpp
3* @brief Crash logger implementation 3* @brief Crash logger implementation
4* 4*
5* $LicenseInfo:firstyear=2003&license=viewergpl$ 5* $LicenseInfo:firstyear=2003&license=viewergpl$
6* 6*
7* Copyright (c) 2003-2008, Linden Research, Inc. 7* Copyright (c) 2003-2008, Linden Research, Inc.
@@ -12,12 +12,12 @@
12* ("GPL"), unless you have obtained a separate licensing agreement 12* ("GPL"), unless you have obtained a separate licensing agreement
13* ("Other License"), formally executed by you and Linden Lab. Terms of 13* ("Other License"), formally executed by you and Linden Lab. Terms of
14* the GPL can be found in doc/GPL-license.txt in this distribution, or 14* the GPL can be found in doc/GPL-license.txt in this distribution, or
15* online at http://secondlife.com/developers/opensource/gplv2 15* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16* 16*
17* There are special exceptions to the terms and conditions of the GPL as 17* There are special exceptions to the terms and conditions of the GPL as
18* it is applied to this Source Code. View the full text of the exception 18* it is applied to this Source Code. View the full text of the exception
19* in the file doc/FLOSS-exception.txt in this software distribution, or 19* in the file doc/FLOSS-exception.txt in this software distribution, or
20* online at http://secondlife.com/developers/opensource/flossexception 20* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21* 21*
22* By copying, modifying or distributing this software, you acknowledge 22* By copying, modifying or distributing this software, you acknowledge
23* that you have read and understood your obligations described above, 23* that you have read and understood your obligations described above,
@@ -27,294 +27,302 @@
27* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, 27* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28* COMPLETENESS OR PERFORMANCE. 28* COMPLETENESS OR PERFORMANCE.
29* $/LicenseInfo$ 29* $/LicenseInfo$
30*/ 30*/
31#include <cstdio> 31#include <cstdio>
32#include <cstdlib> 32#include <cstdlib>
33#include <sstream> 33#include <sstream>
34#include <map> 34#include <map>
35 35
36#include "llcrashlogger.h" 36#include "llcrashlogger.h"
37#include "linden_common.h" 37#include "linden_common.h"
38#include "llstring.h" 38#include "llstring.h"
39#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME 39#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
40#include "llerror.h" 40#include "llerror.h"
41#include "lltimer.h" 41#include "lltimer.h"
42#include "lldir.h" 42#include "lldir.h"
43#include "llsdserialize.h" 43#include "llsdserialize.h"
44#include "lliopipe.h" 44#include "lliopipe.h"
45#include "llpumpio.h" 45#include "llpumpio.h"
46#include "llhttpclient.h" 46#include "llhttpclient.h"
47#include "llsdserialize.h" 47#include "llsdserialize.h"
48 48
49LLPumpIO* gServicePump; 49LLPumpIO* gServicePump;
50BOOL gBreak = false; 50BOOL gBreak = false;
51BOOL gSent = false; 51BOOL gSent = false;
52 52
53class LLCrashLoggerResponder : public LLHTTPClient::Responder 53class LLCrashLoggerResponder : public LLHTTPClient::Responder
54{ 54{
55public: 55public:
56 LLCrashLoggerResponder() 56 LLCrashLoggerResponder()
57 { 57 {
58 } 58 }
59 59
60 virtual void error(U32 status, const std::string& reason) 60 virtual void error(U32 status, const std::string& reason)
61 { 61 {
62 gBreak = true; 62 gBreak = true;
63 } 63 }
64 64
65 virtual void result(const LLSD& content) 65 virtual void result(const LLSD& content)
66 { 66 {
67 gBreak = true; 67 gBreak = true;
68 gSent = true; 68 gSent = true;
69 } 69 }
70}; 70};
71 71
72bool LLCrashLoggerText::mainLoop() 72bool LLCrashLoggerText::mainLoop()
73{ 73{
74 std::cout << "Entering main loop" << std::endl; 74 std::cout << "Entering main loop" << std::endl;
75 sendCrashLogs(); 75 sendCrashLogs();
76 return true; 76 return true;
77} 77}
78 78
79void LLCrashLoggerText::updateApplication(LLString message) 79void LLCrashLoggerText::updateApplication(LLString message)
80{ 80{
81 LLCrashLogger::updateApplication(message); 81 LLCrashLogger::updateApplication(message);
82 std::cout << message << std::endl; 82 std::cout << message << std::endl;
83} 83}
84 84
85LLCrashLogger::LLCrashLogger() : 85LLCrashLogger::LLCrashLogger() :
86mSentCrashLogs(false) 86mSentCrashLogs(false)
87{ 87{
88 88
89} 89}
90 90
91LLCrashLogger::~LLCrashLogger() 91LLCrashLogger::~LLCrashLogger()
92{ 92{
93 93
94} 94}
95 95
96void LLCrashLogger::gatherFiles() 96void LLCrashLogger::gatherFiles()
97{ 97{
98 98
99 /* 99 /*
100 //TODO:This function needs to be reimplemented somewhere in here... 100 //TODO:This function needs to be reimplemented somewhere in here...
101 if(!previous_crash && is_crash_log) 101 if(!previous_crash && is_crash_log)
102 { 102 {
103 // Make sure the file isn't too old. 103 // Make sure the file isn't too old.
104 double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec); 104 double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec);
105 105
106 // llinfos << "age is " << age << llendl; 106 // llinfos << "age is " << age << llendl;
107 107
108 if(age > 60.0) 108 if(age > 60.0)
109 { 109 {
110 // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale. 110 // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale.
111 llwarns << "File " << mFilename << " is too old!" << llendl; 111 llwarns << "File " << mFilename << " is too old!" << llendl;
112 return; 112 return;
113 } 113 }
114 } 114 }
115 */ 115 */
116 116
117 updateApplication("Gathering logs..."); 117 updateApplication("Gathering logs...");
118 118
119 // Figure out the filename of the debug log 119 // Figure out the filename of the debug log
120 LLString db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str(); 120 LLString db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log").c_str();
121 std::ifstream debug_log_file(db_file_name.c_str()); 121 std::ifstream debug_log_file(db_file_name.c_str());
122 122
123 // Look for it in the debug_info.log file 123 // Look for it in the debug_info.log file
124 if (debug_log_file.is_open()) 124 if (debug_log_file.is_open())
125 { 125 {
126 LLSDSerialize::fromXML(mDebugLog, debug_log_file); 126 LLSDSerialize::fromXML(mDebugLog, debug_log_file);
127 mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString(); 127 mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString();
128 mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString(); 128 mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString();
129 LLHTTPClient::setCABundle(mDebugLog["CAFilename"].asString()); 129 LLHTTPClient::setCABundle(mDebugLog["CAFilename"].asString());
130 llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl; 130 llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl;
131 llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl; 131 llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl;
132 } 132 }
133 else 133 else
134 { 134 {
135 // Figure out the filename of the second life log 135 // Figure out the filename of the second life log
136 LLHTTPClient::setCABundle(gDirUtilp->getCAFile()); 136 LLHTTPClient::setCABundle(gDirUtilp->getCAFile());
137 mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); 137 mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
138 mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml"); 138 mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml");
139 } 139 }
140 140
141 gatherPlatformSpecificFiles(); 141 gatherPlatformSpecificFiles();
142 142
143 //Use the debug log to reconstruct the URL to send the crash report to 143 //Use the debug log to reconstruct the URL to send the crash report to
144 mCrashHost = "https://"; 144 mCrashHost = "https://";
145 mCrashHost += mDebugLog["CurrentSimHost"].asString(); 145 mCrashHost += mDebugLog["CurrentSimHost"].asString();
146 mCrashHost += ":12043/crash/report"; 146 mCrashHost += ":12043/crash/report";
147 // Use login servers as the alternate, since they are already load balanced and have a known name 147 // Use login servers as the alternate, since they are already load balanced and have a known name
148 // First, check to see if we have a valid grid name. If not, use agni. 148 // First, check to see if we have a valid grid name. If not, use agni.
149 mAltCrashHost = "https://login."; 149 mAltCrashHost = "https://login.";
150 if(mDebugLog["GridName"].asString() != "") 150 if(mDebugLog["GridName"].asString() != "")
151 { 151 {
152 mAltCrashHost += mDebugLog["GridName"].asString(); 152 mAltCrashHost += mDebugLog["GridName"].asString();
153 } 153 }
154 else 154 else
155 { 155 {
156 mAltCrashHost += "agni"; 156 mAltCrashHost += "agni";
157 } 157 }
158 mAltCrashHost += ".lindenlab.com:12043/crash/report"; 158 mAltCrashHost += ".lindenlab.com:12043/crash/report";
159 159
160 mCrashInfo["DebugLog"] = mDebugLog; 160 mCrashInfo["DebugLog"] = mDebugLog;
161 mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log"); 161 mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
162 mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); 162 mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
163 163
164 updateApplication("Encoding files..."); 164 updateApplication("Encoding files...");
165 165
166 for(std::map<LLString, LLString>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr) 166 for(std::map<LLString, LLString>::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr)
167 { 167 {
168 std::ifstream f((*itr).second.c_str()); 168 std::ifstream f((*itr).second.c_str());
169 if(!f.is_open()) 169 if(!f.is_open())
170 { 170 {
171 std::cout << "Can't find file " << (*itr).second.c_str() << std::endl; 171 std::cout << "Can't find file " << (*itr).second.c_str() << std::endl;
172 continue; 172 continue;
173 } 173 }
174 std::stringstream s; 174 std::stringstream s;
175 s << f.rdbuf(); 175 s << f.rdbuf();
176 mCrashInfo[(*itr).first] = s.str(); 176 mCrashInfo[(*itr).first] = s.str();
177 } 177 }
178} 178}
179 179
180LLSD LLCrashLogger::constructPostData() 180LLSD LLCrashLogger::constructPostData()
181{ 181{
182 LLSD ret; 182 LLSD ret;
183 183
184 if(mCrashInPreviousExec) 184 if(mCrashInPreviousExec)
185 { 185 {
186 mCrashInfo["CrashInPreviousExecution"] = "Y"; 186 mCrashInfo["CrashInPreviousExecution"] = "Y";
187 } 187 }
188 188
189 return mCrashInfo; 189 return mCrashInfo;
190} 190}
191 191
192S32 LLCrashLogger::loadCrashBehaviorSetting() 192S32 LLCrashLogger::loadCrashBehaviorSetting()
193{ 193{
194 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); 194 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
195 195
196 mCrashSettings.loadFromFile(filename); 196 mCrashSettings.loadFromFile(filename);
197 197
198 S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); 198 S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
199 199
200 if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK; 200 if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK;
201 201
202 return value; 202 return value;
203} 203}
204 204
205bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior) 205bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior)
206{ 206{
207 if (crash_behavior < CRASH_BEHAVIOR_ASK) return false; 207 if (crash_behavior < CRASH_BEHAVIOR_ASK) return false;
208 if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false; 208 if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false;
209 209
210 mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior); 210 mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior);
211 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); 211 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
212 212
213 mCrashSettings.saveToFile(filename, FALSE); 213 mCrashSettings.saveToFile(filename, FALSE);
214 214
215 return true; 215 return true;
216} 216}
217 217
218bool LLCrashLogger::sendCrashLogs() 218bool LLCrashLogger::sendCrashLogs()
219{ 219{
220 gatherFiles(); 220 gatherFiles();
221 221
222 LLSD post_data; 222 LLSD post_data;
223 post_data = constructPostData(); 223 post_data = constructPostData();
224 224
225 updateApplication("Sending reports..."); 225 updateApplication("Sending reports...");
226 226
227 std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, 227 std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
228 "SecondLifeCrashReport"); 228 "SecondLifeCrashReport");
229 std::string report_file = dump_path + ".log"; 229 std::string report_file = dump_path + ".log";
230 230
231 std::ofstream out_file(report_file.c_str()); 231 std::ofstream out_file(report_file.c_str());
232 LLSDSerialize::toPrettyXML(post_data, out_file); 232 LLSDSerialize::toPrettyXML(post_data, out_file);
233 out_file.close(); 233 out_file.close();
234 LLHTTPClient::post(mCrashHost, post_data, new LLCrashLoggerResponder(), 5); 234 LLHTTPClient::post(mCrashHost, post_data, new LLCrashLoggerResponder(), 5);
235 235
236 gBreak = false; 236 gBreak = false;
237 while(!gBreak) 237 while(!gBreak)
238 { 238 {
239 updateApplication("Sending logs..."); 239 updateApplication("Sending logs...");
240 } 240 }
241 241
242 if(!gSent) 242 if(!gSent)
243 { 243 {
244 gBreak = false; 244 gBreak = false;
245 LLHTTPClient::post(mAltCrashHost, post_data, new LLCrashLoggerResponder(), 5); 245 LLHTTPClient::post(mAltCrashHost, post_data, new LLCrashLoggerResponder(), 5);
246 246
247 while(!gBreak) 247 while(!gBreak)
248 { 248 {
249 updateApplication("Sending logs to Alternate Server..."); 249 updateApplication("Sending logs to Alternate Server...");
250 } 250 }
251 } 251 }
252 252
253 253
254 mSentCrashLogs = gSent; 254 mSentCrashLogs = gSent;
255 255
256 return true; 256 return true;
257} 257}
258 258
259void LLCrashLogger::updateApplication(LLString message) 259void LLCrashLogger::updateApplication(LLString message)
260{ 260{
261 gServicePump->pump(); 261 gServicePump->pump();
262 gServicePump->callback(); 262 gServicePump->callback();
263} 263}
264 264
265bool LLCrashLogger::init() 265bool LLCrashLogger::init()
266{ 266{
267 // We assume that all the logs we're looking for reside on the current drive 267 // We assume that all the logs we're looking for reside on the current drive
268 gDirUtilp->initAppDirs("SecondLife"); 268 gDirUtilp->initAppDirs("SecondLife");
269 269
270 // Default to the product name "Second Life" (this is overridden by the -name argument) 270 // Default to the product name "Second Life" (this is overridden by the -name argument)
271 mProductName = "Second Life"; 271 mProductName = "Second Life";
272 272
273 mCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes " 273 mCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes "
274 "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)"); 274 "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)");
275 275
276 llinfos << "Loading crash behavior setting" << llendl; 276 llinfos << "Loading crash behavior setting" << llendl;
277 mCrashBehavior = loadCrashBehaviorSetting(); 277 mCrashBehavior = loadCrashBehaviorSetting();
278 278
279 //Run through command line options 279 //Run through command line options
280 if(getOption("previous").isDefined()) 280 if(getOption("previous").isDefined())
281 { 281 {
282 llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl; 282 llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl;
283 mCrashInPreviousExec = TRUE; 283 mCrashInPreviousExec = TRUE;
284 } 284 }
285 285
286 if(getOption("dialog").isDefined()) 286 if(getOption("dialog").isDefined())
287 { 287 {
288 llinfos << "Show the user dialog" << llendl; 288 llinfos << "Show the user dialog" << llendl;
289 mCrashBehavior = CRASH_BEHAVIOR_ASK; 289 mCrashBehavior = CRASH_BEHAVIOR_ASK;
290 } 290 }
291 291
292 LLSD server = getOption("user"); 292 LLSD server = getOption("user");
293 if(server.isDefined()) 293 if(server.isDefined())
294 { 294 {
295 mGridName = server.asString(); 295 mGridName = server.asString();
296 llinfos << "Got userserver " << mGridName << llendl; 296 llinfos << "Got userserver " << mGridName << llendl;
297 } 297 }
298 else 298 else
299 { 299 {
300 mGridName = "agni"; 300 mGridName = "agni";
301 } 301 }
302 302
303 LLSD name = getOption("name"); 303 LLSD name = getOption("name");
304 if(name.isDefined()) 304 if(name.isDefined())
305 { 305 {
306 mProductName = name.asString(); 306 mProductName = name.asString();
307 } 307 }
308 308
309 // If user doesn't want to send, bail out 309 // If user doesn't want to send, bail out
310 if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND) 310 if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND)
311 { 311 {
312 llinfos << "Crash behavior is never_send, quitting" << llendl; 312 llinfos << "Crash behavior is never_send, quitting" << llendl;
313 return false; 313 return false;
314 } 314 }
315 315
316 gServicePump = new LLPumpIO(gAPRPoolp); 316 gServicePump = new LLPumpIO(gAPRPoolp);
317 gServicePump->prime(gAPRPoolp); 317 gServicePump->prime(gAPRPoolp);
318 LLHTTPClient::setPump(*gServicePump); 318 LLHTTPClient::setPump(*gServicePump);
319 return true; 319
320} 320 //If we've opened the crash logger, assume we can delete the marker file if it exists
321 if( gDirUtilp )
322 {
323 LLString marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker");
324 ll_apr_file_remove( marker_file );
325 }
326
327 return true;
328}