xoreos  0.0.5
debugman.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 // Inspired by ScummVM's debug channels
22 
27 #include "src/version/version.h"
28 
29 #include "src/common/maths.h"
30 #include "src/common/util.h"
31 #include "src/common/strutil.h"
32 #include "src/common/filepath.h"
33 #include "src/common/debugman.h"
34 #include "src/common/configman.h"
35 #include "src/common/datetime.h"
36 
38 
39 namespace Common {
40 
41 static const char * const kDebugNames[kDebugChannelCount] = {
42  "GGraphics", "GSound", "GVideo", "GEvents", "GScripts",
43  "GGLAPI", "GGLWindow", "GGLShader", "GGL3rd", "GGLApp", "GGLOther",
44  "EGraphics", "ESound", "EVideo", "EEvents", "ELogic", "EScripts", "EActionScript"
45 };
46 
47 static const char * const kDebugDescriptions[kDebugChannelCount] = {
48  "Global graphics debug channel",
49  "Global sound debug channel",
50  "Global video (movies) debug channel",
51  "Global events debug channel",
52  "Global scripts debug channel",
53  "OpenGL debug message generated by the GL",
54  "OpenGL debug message generated by the windowing system",
55  "OpenGL debug message generated by the shader compiler",
56  "OpenGL debug message generated by third party middleware",
57  "OpenGL debug message generated by the application",
58  "OpenGL debug message generated by other sources",
59  "Engine graphics debug channel",
60  "Engine sound debug channel",
61  "Engine video debug channel",
62  "Engine events debug channel",
63  "Engine game logic debug channel",
64  "Engine scripts debug channel",
65  "Engine ActionScript debug channel",
66 };
67 
68 static const char * const kDebugGLTypes[kDebugGLTypeMAX] = {
69  "Error", "Deprecated", "Undefined", "Portability", "Performance", "Other"
70 };
71 
72 DebugManager::DebugManager() : _logFileStartLine(false), _changedConfig(false) {
73  for (size_t i = 0; i < kDebugChannelCount; i++) {
74  _channels[i].name = kDebugNames[i];
76  _channels[i].level = 0;
77 
78  for (size_t j = 0; j < kDebugGLTypeMAX; j++)
79  _channels[i].glTypeIDs[j] = 0;
80 
82  }
83 
85 }
86 
88  closeLogFile();
89 }
90 
91 void DebugManager::getDebugChannels(std::vector<UString> &names, std::vector<UString> &descriptions) const {
92  names.resize(kDebugChannelCount);
93  descriptions.resize(kDebugChannelCount);
94 
95  for (size_t i = 0; i < kDebugChannelCount; i++) {
96  names[i] = _channels[i].name;
97  descriptions[i] = _channels[i].description;
98  }
99 }
100 
102  if (channel == kDebugChannelAll) {
103  for (size_t i = 0; i < kDebugChannelCount; i++)
104  setVerbosityLevel((DebugChannel) i, level);
105 
106  return;
107  }
108 
109  if (channel >= kDebugChannelCount)
110  return;
111 
112  _channels[channel].level = MIN<uint32>(level, kMaxVerbosityLevel);
113 
114  for (size_t i = 0; i < kDebugGLTypeMAX; i++)
115  _channels[channel].glTypeIDs[i] = 0;
116 
117  _changedConfig = true;
118 }
119 
120 void DebugManager::setVerbosityLevel(const UString &channel, uint32 level) {
121  ChannelMap::iterator c = _channelMap.find(channel);
122  if (c == _channelMap.end())
123  return;
124 
125  setVerbosityLevel(c->second, level);
126 }
127 
129  if (channel >= kDebugChannelCount)
130  return 0;
131 
132  return _channels[channel].level;
133 }
134 
136  ChannelMap::const_iterator c = _channelMap.find(channel);
137  if (c == _channelMap.end())
138  return 0;
139 
140  return getVerbosityLevel(c->second);
141 }
142 
143 bool DebugManager::isEnabled(DebugChannel channel, uint32 level) const {
144  return getVerbosityLevel(channel) >= MIN<uint32>(level, kMaxVerbosityLevel);
145 }
146 
147 bool DebugManager::isEnabled(const UString &channel, uint32 level) const {
148  return getVerbosityLevel(channel) >= MIN<uint32>(level, kMaxVerbosityLevel);
149 }
150 
153 
154  std::vector<UString> debug;
155  UString::split(ConfigMan.getString("debug", ""), ',', debug);
156 
157  for (std::vector<UString>::const_iterator d = debug.begin(); d != debug.end(); ++d) {
158  std::vector<UString> config;
159  UString::split(*d, ':', config);
160 
161  if ((config.size() != 2) || config[0].empty())
162  continue;
163 
164  config[0].trim();
165  config[1].trim();
166 
167  uint32 level = 0;
168  try {
169  parseString(config[1], level);
170  } catch (...) {
171  }
172 
173  setVerbosityLevel(config[0], level);
174  }
175 
176  _changedConfig = false;
177 }
178 
180  if (!_changedConfig)
181  return;
182 
183  UString debug;
184 
185  for (size_t i = 0; i < kDebugChannelCount; i++) {
186  if (_channels[i].level == 0)
187  continue;
188 
189  if (!debug.empty())
190  debug += ',';
191 
192  debug += _channels[i].name + ":" + composeString(_channels[i].level);
193  }
194 
195  ConfigMan.setString("debug", debug, true);
196 }
197 
198 static bool isOpenGLDebugChannel(DebugChannel channel) {
199  return (channel >= kDebugGLAPI) && (channel <= kDebugGLOther);
200 }
201 
203  const char *msg) {
204 
205  if (!isOpenGLDebugChannel(channel) || !isEnabled(channel, level))
206  return;
207 
208  if (((uint32) type) >= kDebugGLTypeMAX)
209  type = kDebugGLTypeOther;
210 
211  // Suppress duplicates
212  if (_channels[channel].glTypeIDs[type] == id)
213  return;
214 
215  _channels[channel].glTypeIDs[type] = id;
216 
217  status("%s<%s,%u,%u>: %s", kDebugNames[channel], kDebugGLTypes[type], level, id, msg);
218 }
219 
221  closeLogFile();
222 
223  _logFileStartLine = true;
224 
225  // Create the directories in the path, if necessary
226  UString path = FilePath::canonicalize(file);
227 
228  try {
230  } catch (...) {
231  return false;
232  }
233 
234  if (!_logFile.open(path))
235  return false;
236 
238  logString("\n");
239 
240  return true;
241 }
242 
244  _logFile.close();
245 }
246 
248  if (!_logFile.isOpen())
249  return;
250 
251  // If we're at the start of a new line, write the timestamp
252  if (_logFileStartLine) {
253  UString tstamp;
254 
255  try {
256  tstamp = "[" + DateTime(DateTime::kUTC).formatDateTimeISO('T', '-', ':') + "] ";
257  } catch (...) {
258  tstamp = "[0000-00-00T00:00:00] ";
259  }
260 
261  _logFile.writeString(tstamp);
262  }
263 
264  _logFile.writeString(str);
265 
266  // Find out whether we just started a new line. If this fails, force one
267  try {
268  _logFileStartLine = !str.empty() && (*--str.end() == '\n');
269  } catch (...) {
270  _logFile.writeString("\n");
271  _logFileStartLine = true;
272  }
273 
274  if (_logFileStartLine)
275  _logFile.flush();
276 }
277 
278 void DebugManager::logCommandLine(const std::vector<UString> &argv) {
279  logString("Full command line:");
280  for (std::vector<UString>::const_iterator arg = argv.begin(); arg != argv.end(); ++arg) {
281  logString(" ");
282  logString(*arg);
283  }
284  logString("\n");
285 }
286 
288  // By default, put the log file into the user data directory
289  return FilePath::getUserDataDirectory() + "/xoreos.log";
290 }
291 
292 } // End of namespace Common
static UString getUserDataDirectory()
Return the OS-specific path of the user data directory.
Definition: filepath.cpp:379
"GGLAPI", OpenGL debug message generated by the GL.
Definition: debugman.h:48
Definition: 2dafile.h:39
static const uint32 kMaxVerbosityLevel
Definition: debugman.h:110
A class holding an UTF-8 string.
Definition: ustring.h:48
void writeString(const UString &str)
Write the given string to the stream, encoded as UTF-8.
Definition: writestream.cpp:94
void logString(const UString &str)
Log that string to the current log file.
Definition: debugman.cpp:247
The global config manager.
UString composeString(T value)
Convert any POD integer, float/double or bool type into a string.
Definition: strutil.cpp:276
A date/time object, storing a specific point in time.
Definition: datetime.h:36
uint32 glTypeIDs[kDebugGLTypeMAX]
Information about the last OpenGL message ID for this channel&#39;s types.
Definition: debugman.h:178
uint32 getVerbosityLevel(DebugChannel channel) const
Return the verbosity level of this channel (by ID).
Definition: debugman.cpp:128
bool isEnabled(DebugChannel channel, uint32 level) const
Is this channel ID enabled for this verbosity level?
Definition: debugman.cpp:143
Mathematical helpers.
ChannelMap _channelMap
Debug channels indexed by name.
Definition: debugman.h:184
UString description
The channel&#39;s description.
Definition: debugman.h:173
void setConfigToVerbosityLevels()
Sync verbosity levels to the ConfigManager.
Definition: debugman.cpp:179
static const char *const kDebugDescriptions[kDebugChannelCount]
Definition: debugman.cpp:47
static const char *const kDebugGLTypes[kDebugGLTypeMAX]
Definition: debugman.cpp:68
UString formatDateTimeISO(uint32 sep=0, uint32 sepDate=0, uint32 sepTime=0) const
Return a string representation of the date and time in ISO 8601 format.
Definition: datetime.cpp:79
static UString getDefaultLogFile()
Return the OS-specific default path of the log file.
Definition: debugman.cpp:287
Utility templates and functions for working with strings and streams.
void logDebugGL(DebugChannel channel, uint32 level, DebugGLType type, uint32 id, const char *msg)
Log (and print) an OpenGL debug message.
Definition: debugman.cpp:202
Utility functions for manipulating date and time.
The debug manager, managing debug channels.
Definition: debugman.h:108
WriteFile _logFile
Definition: debugman.h:186
bool open(const UString &fileName)
Try to open the file with the given fileName.
Definition: writefile.cpp:50
void closeLogFile()
Close the current log file.
Definition: debugman.cpp:243
The debug manager, managing debug channels.
#define ConfigMan
Shortcut for accessing the config manager.
Definition: configman.h:176
Utility templates and functions.
Special value to refer to all debug channel.
Definition: debugman.h:65
static bool isOpenGLDebugChannel(DebugChannel channel)
Definition: debugman.cpp:198
Basic xoreos version information.
void logCommandLine(const std::vector< UString > &argv)
Write the whole command line to the current log file.
Definition: debugman.cpp:278
#define DECLARE_SINGLETON(T)
Note that you need to use this macro from the global namespace.
Definition: singleton.h:122
bool isOpen() const
Checks if the object opened a file successfully.
Definition: writefile.cpp:79
DebugGLType
Types of OpenGL debug messages.
Definition: debugman.h:69
static UString canonicalize(const UString &p, bool resolveSymLinks=true)
Return the canonical, absolutized and normalized path.
Definition: filepath.cpp:230
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
For range checks.
Definition: debugman.h:77
void getDebugChannels(std::vector< UString > &names, std::vector< UString > &descriptions) const
Return the channel names alongside their descriptions.
Definition: debugman.cpp:91
static UString getDirectory(const UString &p)
Return a path&#39;s directory.
Definition: filepath.cpp:107
bool openLogFile(const UString &file)
Open a log file where all debug output will be written to.
Definition: debugman.cpp:220
void flush()
Commit any buffered data to the underlying channel or storage medium; unbuffered streams can use the ...
Definition: writefile.cpp:83
Total number of debug channels.
Definition: debugman.h:64
DebugChannel
All debug channels.
Definition: debugman.h:41
void close()
Close the file, if open.
Definition: writefile.cpp:69
const char * getProjectNameVersionFull()
Definition: version.cpp:96
"GGLOther", OpenGL debug message generated by other sources.
Definition: debugman.h:53
static bool createDirectories(const UString &path)
Create all directories in this path.
Definition: filepath.cpp:342
uint32_t uint32
Definition: types.h:204
uint32 level
The current level at which this debug channel is enabled.
Definition: debugman.h:175
Coordinated Universal Time (UTC).
Definition: datetime.h:39
Types of events that do not fit any of the ones listed above.
Definition: debugman.h:75
void status(const char *s,...)
Definition: util.cpp:52
Channel _channels[kDebugChannelCount]
All debug channels.
Definition: debugman.h:183
void setVerbosityLevelsFromConfig()
Sync verbosity levels from the ConfigManager.
Definition: debugman.cpp:151
void split(iterator splitPoint, UString &left, UString &right, bool remove=false) const
Definition: ustring.cpp:621
iterator end() const
Definition: ustring.cpp:257
void setVerbosityLevel(DebugChannel channel, uint32 level)
Set the verbosity level of this channel (by ID).
Definition: debugman.cpp:101
void parseString(const UString &str, T &value, bool allowEmpty)
Parse a string into any POD integer, float/double or bool type.
Definition: strutil.cpp:215
Utility class for manipulating file paths.
UString name
The channel&#39;s name.
Definition: debugman.h:172
static const char *const kDebugNames[kDebugChannelCount]
Definition: debugman.cpp:41