File: LogOutput.h

package info (click to toggle)
spring 0.81.2.1%2Bdfsg1-6
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 28,496 kB
  • ctags: 37,096
  • sloc: cpp: 238,659; ansic: 13,784; java: 12,175; awk: 3,428; python: 1,159; xml: 738; perl: 405; sh: 297; makefile: 267; pascal: 228; objc: 192
file content (229 lines) | stat: -rw-r--r-- 6,330 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
LogOutput - global object to write log info to.
 Game UI elements that display log can subscribe to it to receive the log messages.
*/

#ifndef LOGOUTPUT_H
#define LOGOUTPUT_H

#include <stdarg.h>
#include <string>
#include <vector>
#include <sstream>

// format string error checking
#ifdef __GNUC__
#define FORMATSTRING(n) __attribute__((format(printf, n, n + 1)))
#else
#define FORMATSTRING(n)
#endif

class float3;


/**
 * @brief defines a logging subsystem
 *
 * Each logging subsystem can be independently enabled/disabled, this allows
 * for adding e.g. very detailed logging that's by default off, but can be
 * turned on when troubleshooting.  (example: the virtual file system)
 *
 * A logging subsystem should be defined as a global variable, so it can be
 * used as argument to logOutput.Print similarly to a simple enum constant:
 *
 *	static CLogSubsystem LOG_MYSUBSYS("mysubsystem");
 *
 * ...then, in the actual code of your engine subsystem, use:
 *
 *		logOutput.Print(LOG_MYSUBSYS, "blah");
 *
 * All subsystems are linked together in a global list, allowing CLogOutput
 * to enable/disable subsystems based on env var and configuration key.
 */
class CLogSubsystem
{
public:
	static CLogSubsystem* GetList() { return linkedList; }
	CLogSubsystem* GetNext() { return next; }

	CLogSubsystem(const char* name, bool enabled = false);

	const char* const name;
	CLogSubsystem* const next;

	bool enabled;

private:
	static CLogSubsystem* linkedList;
};

/**
 * @brief ostringstream-derivate for simple logging
 *
 * usage:
 * LogObject() << "Important message with value: " << myint;
 * LogObject(mySubsys) << "Message";
 */
class LogObject
{
public:
	LogObject(const CLogSubsystem& subsys);
	LogObject();

	~LogObject();

	template <typename T>
	LogObject& operator<<(const T& t)
	{
		str << t;
		return *this;
	};

private:
	const CLogSubsystem& subsys;
	std::ostringstream str;
};

/** @brief implement this interface to be able to observe CLogOutput */
class ILogSubscriber
{
public:
	// Notification of log messages to subscriber
	virtual void NotifyLogMsg(const CLogSubsystem& subsystem, const std::string& str) = 0;
	virtual void SetLastMsgPos(const float3& pos) {}
};


/** @brief logging class */
class CLogOutput
{
public:
	CLogOutput();
	~CLogOutput();

	void Print(CLogSubsystem& subsystem, const char* fmt, ...) FORMATSTRING(3);
	void Print(const char* fmt, ...) FORMATSTRING(2);
	void Print(const std::string& text);
	void Prints(const CLogSubsystem& subsystem, const std::string& text); // canno be named Print, would be  not unique
	void Printv(CLogSubsystem& subsystem, const char* fmt, va_list argp);
	static CLogSubsystem& GetDefaultLogSubsystem();

	void SetLastMsgPos(const float3& pos);

	// In case the InfoConsole and other in game subscribers
	// should not be used anymore (SDL shutdown)
	void RemoveAllSubscribers();
	// Close the output file, so the crash reporter can copy it
	void End();

	void AddSubscriber(ILogSubscriber* ls);
	void RemoveSubscriber(ILogSubscriber* ls);

	/**
	 * @brief set the log file
	 *
	 * Relative paths are relative to the writeable data-dir.
	 * This method may only be called as long as the logger is not yet
	 * initialized.
	 * @see Initialize()
	 */
	void SetFileName(std::string fileName);
	/**
	 * @brief returns the log file name (without path)
	 *
	 * Relative paths are relative to the writeable data-dir.
	 */
	const std::string& GetFileName() const;
	/**
	 * @brief returns the absolute path to the log file
	 *
	 * Relative paths are relative to the writeable data-dir.
	 * This method may only be called after the logger got initialzized.
	 * @see Initialize()
	 */
	const std::string& GetFilePath() const;

	/**
	 * @brief initialize logOutput
	 *
	 * Only after calling this method, logOutput starts writing to disk.
	 * The log file is written in the current directory so this may only be called
	 * after the engine chdir'ed to the correct directory.
	 */
	void Initialize();
	void Flush();

protected:
	/**
	 * @brief initialize the log subsystems
	 *
	 * This writes list of all available and all enabled subsystems to the log.
	 *
	 * Log subsystems can be enabled using the configuration key "LogSubsystems",
	 * or the environment variable "SPRING_LOG_SUBSYSTEMS".
	 *
	 * Both specify a comma separated list of subsystems that should be enabled.
	 * The lists from both sources are combined, there is no overriding.
	 *
	 * A subsystem that is by default enabled, can not be disabled.
	 */
	void InitializeSubsystems();
	/**
	 * @brief core log output method, used by all others
	 *
	 * Note that, when logOutput isn't initialized yet, the logging is done to the
	 * global std::vector preInitLog(), and is only written to disk in the call to
	 * Initialize().
	 *
	 * This method notifies all registered ILogSubscribers, calls OutputDebugString
	 * (for MSVC builds) and prints the message to stdout and the file log.
	 */
	void Output(const CLogSubsystem& subsystem, const std::string& str);

	void ToStdout(const CLogSubsystem& subsystem, const std::string message);
	void ToFile(const CLogSubsystem& subsystem, const std::string message);

private:
	/**
	 * @brief creates an absolute file path from a file name
	 *
	 * Will use the CWD, whihc should be the writeable data-dir format
	 * absoluteification.
	 */
	static std::string CreateFilePath(const std::string& fileName);

	/**
	 * @brief enable/disable log file rotation
	 *
	 * The default is determined by the config setting RotateLogFiles and
	 * whether this is a DEBUG build or not.
	 * RotateLogFiles defaults to "auto", and could be set to "never"
	 * or "always". On "auto", it will rotate logs only for debug builds.
	 * You may only call this as long as the logger did not yet get initialized.
	 */
	void SetLogFileRotating(bool enabled);
	bool IsLogFileRotating() const;
	/**
	 * @brief ff enabled, moves the log file of the last run
	 *
	 * Moves the log file of the last run, to preserve it,
	 * if log file rotation is enabled.
	 *
	 * By default, this is enabled only for DEBUG builds;
	 * ... (describe config file value here)
	 */
	void RotateLogFile() const;


	std::vector<ILogSubscriber*> subscribers;
	std::string fileName;
	std::string filePath;
	bool rotateLogFiles;
};


extern CLogOutput logOutput;

#undef FORMATSTRING

#endif // LOGOUTPUT_H