Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / misc / report.cpp
blob67dbff85f43bad814f159a20cc9158f3db0bfbdd
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 // Copyright (C) 2015 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdmisc.h"
23 #include <stdlib.h>
24 #include <sstream>
26 #include "nel/misc/common.h"
27 #include "nel/misc/ucstring.h"
29 #include "nel/misc/report.h"
30 #include "nel/misc/path.h"
31 #include "nel/misc/file.h"
32 #include "nel/misc/system_utils.h"
34 #ifdef DEBUG_NEW
35 #define new DEBUG_NEW
36 #endif
38 #define NL_REPORT_POST_URL_ENVVAR "NL_REPORT_POST_URL"
39 #ifdef NL_OS_WINDOWS
40 #define NL_CRASH_REPORT_TOOL "crash_report.exe"
41 #else
42 #define NL_CRASH_REPORT_TOOL "crash_report"
43 #endif
44 #define NL_DEBUG_REPORT 0
45 // Set to 1 if you want command line report tool
46 #define NL_REPORT_CONSOLE 0
47 // Set to 1 if you want command line report tool even when the debugger is present
48 #define NL_REPORT_CONSOLE_DEBUGGER 1
50 namespace NLMISC
53 void setReportPostUrl(const char *postUrl)
55 #if NL_DEBUG_REPORT
56 if (INelContext::isContextInitialised())
57 nldebug("Set report post url to '%s'", postUrl);
58 #endif
59 #ifdef NL_OS_WINDOWS
60 SetEnvironmentVariableA(NL_REPORT_POST_URL_ENVVAR, postUrl);
61 #else
62 setenv(NL_REPORT_POST_URL_ENVVAR, postUrl, 1);
63 #endif
66 inline const char *getReportPostURL()
68 #ifdef NL_OS_WINDOWS
69 static char buf[512];
70 buf[0] = '\0';
71 int res = GetEnvironmentVariableA(NL_REPORT_POST_URL_ENVVAR, buf, sizeof(buf));
72 if (res <= 0 || res > 511) return NULL;
73 if (buf[0] == '\0') return NULL;
74 return buf;
75 #else
76 char *res = getenv(NL_REPORT_POST_URL_ENVVAR);
77 if (res == NULL || res[0] == '\0') return NULL;
78 return res;
79 #endif
82 TReportResult report(const std::string &title, const std::string &subject, const std::string &body, const std::string &attachment, bool synchronous, bool sendReport, TReportResult defaultResult)
84 std::string reportPath;
85 if (!body.empty())
87 std::string reportFile = getLogDirectory() + NLMISC::toString("nel_report_%u.log", (uint)time(NULL));
88 reportPath = CFile::findNewFile(reportFile);
90 FILE *f = nlfopen(reportPath, "wb"); // write as binary so \n are preserved
92 if (!f)
94 #if NL_DEBUG_REPORT
95 if (INelContext::isContextInitialised())
96 nldebug("Failed to write report log to '%s'", reportPath.c_str());
97 #endif
98 reportPath.clear();
100 else
102 size_t written = fwrite(body.c_str(), 1, body.length(), f);
104 if (written != body.length())
106 nlwarning("Unable to write %u bytes to %s, only %u written", (uint)body.length(), reportPath.c_str(), (uint)written);
109 fclose(f);
113 if (((INelContext::isContextInitialised()
114 && INelContext::getInstance().isWindowedApplication())
115 || CSystemUtils::detectWindowedApplication())
116 && CFile::isExists(NL_CRASH_REPORT_TOOL))
118 std::string params;
120 if (!reportPath.empty())
121 params += NLMISC::toString(" -log \"%s\"", reportPath.c_str());
123 if (!subject.empty())
124 params += NLMISC::toString(" -attachment \"%s\"", attachment.c_str());
126 if (!title.empty())
127 params += NLMISC::toString(" -title \"%s\"", title.c_str());
129 if (!subject.empty())
130 params += NLMISC::toString(" -subject \"%s\"", subject.c_str());
132 const char *reportPostUrl = getReportPostURL();
133 if (reportPostUrl)
134 params += NLMISC::toString(" -host \"%s\"", reportPostUrl);
136 if (synchronous)
137 params += " -dev";
139 if (sendReport)
140 params += " -sendreport";
142 if (synchronous)
144 TReportResult result = (TReportResult)NLMISC::launchProgramAndWaitForResult(NL_CRASH_REPORT_TOOL, params);
146 if (result != ReportAlwaysIgnore
147 && result != ReportIgnore
148 && result != ReportAbort
149 && result != ReportBreak)
151 #if NL_DEBUG_REPORT
152 if (INelContext::isContextInitialised())
153 nldebug("Return default result, invalid return code %i", (int)result);
154 #endif
155 return defaultResult;
157 return result;
159 else
161 NLMISC::launchProgram(NL_CRASH_REPORT_TOOL, params,
162 NL_DEBUG_REPORT ? INelContext::isContextInitialised() : false); // Only log if required, avoid infinite loop
163 return defaultResult;
166 else
168 #if NL_DEBUG_REPORT
169 if (INelContext::isContextInitialised() && !CFile::isExists(NL_CRASH_REPORT_TOOL))
170 nldebug("Crash report tool '%s' does not exist", NL_CRASH_REPORT_TOOL);
171 #endif
172 #if defined(NL_OS_WINDOWS) && !FINAL_VERSION && !NL_REPORT_CONSOLE_DEBUGGER
173 if (IsDebuggerPresent())
175 return defaultResult;
177 else
178 #endif
179 if (synchronous)
181 #if NL_REPORT_CONSOLE
182 // An interactive console based report
183 printf("\n");
184 if (!title.empty())
185 printf("%s\n", title.c_str());
186 else
187 printf("NeL report\n");
188 printf("\n");
189 if (!subject.empty())
190 printf("\tsubject: '%s'\n", subject.c_str());
191 if (!body.empty())
192 printf("\tbody: '%s'\n", reportPath.c_str());
193 if (!attachment.empty())
194 printf("\tattachment: '%s'\n", attachment.c_str());
195 for (;;)
197 printf("\n");
198 printf("Always Ignore (S), Ignore (I), Abort (A), Break (B)?\n"); // S for Surpress
199 printf("> ");
200 int c = getchar();
201 getchar();
202 switch (c)
204 case 'S':
205 case 's':
206 return ReportAlwaysIgnore;
207 case 'I':
208 case 'i':
209 return ReportIgnore;
210 case 'A':
211 case 'a':
212 return ReportAbort;
213 case 'B':
214 case 'b':
215 return ReportBreak;
218 #else
219 return defaultResult;
220 #endif
222 else
224 return defaultResult;
229 } // NLMISC