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