1 /** \file logstream.hxx
2  * Stream based logging mechanism.
3  */
4 
5 // Written by Bernie Bright, 1998
6 //
7 // Copyright (C) 1998  Bernie Bright - bbright@c031.aone.net.au
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 // $Id$
24 
25 #ifndef _LOGSTREAM_H
26 #define _LOGSTREAM_H
27 
28 #include <simgear/compiler.h>
29 #include <simgear/debug/debug_types.h>
30 
31 #include <sstream>
32 #include <vector>
33 #include <memory>
34 
35 // forward decls
36 class SGPath;
37 
38 namespace simgear
39 {
40 
41 class LogCallback;
42 /**
43  * Helper force a console on platforms where it might optional, when
44  * we need to show a console. This basically means Windows at the
45  * moment - on other plaforms it's a no-op
46  */
47 void requestConsole();
48 
49 void shutdownLogging();
50 
51 } // of namespace simgear
52 
53 /**
54  * Class to manage the debug logging stream.
55  */
56 class logstream
57 {
58 public:
59     ~logstream();
60 
61     static void initGlobalLogstream();
62 
63     /**
64      * Helper force a console on platforms where it might optional, when
65      * we need to show a console. This basically means Windows at the
66      * moment - on other plaforms it's a no-op
67      */
68     void requestConsole();
69 
70     /**
71      * Set the global log class and priority level.
72      * @param c debug class
73      * @param p priority
74      */
75     void setLogLevels( sgDebugClass c, sgDebugPriority p );
76 
77     bool would_log(  sgDebugClass c, sgDebugPriority p ) const;
78 
79     void logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p );
80 
81     void set_log_priority( sgDebugPriority p);
82 
83     void set_log_classes( sgDebugClass c);
84 
85     sgDebugClass get_log_classes() const;
86 
87     sgDebugPriority get_log_priority() const;
88 
89     /**
90         @brief convert a string value to a log prioirty.
91         throws std::invalid_argument if the string is not valid
92      */
93     static sgDebugPriority priorityFromString(const std::string& s);
94     /**
95      * set developer mode on/off. In developer mode, SG_DEV_WARN messags
96      * are treated as warnings. In normal (non-developer) mode they are
97      * treated as SG_DEBUG.
98      */
99     void setDeveloperMode(bool devMode);
100 
101     /**
102      * set output of file:line mode on/off. If on, all log messages are
103      * prefixed by the file:line of the caller of SG_LOG().
104      */
105     void setFileLine(bool fileLine);
106 
107     /**
108      * the core logging method
109      */
110     void log( sgDebugClass c, sgDebugPriority p,
111             const char* fileName, int line, const std::string& msg);
112 
113     // overload of above, which can transfer ownership of the file-name.
114     // this is unecesary overhead when logging from C++, since __FILE__ points
115     // to constant data, but it's needed when the filename is Nasal data (for
116     // example) since during shutdown the filename is freed by Nasal GC
117     // asynchronously with the logging thread.
118     void logCopyingFilename( sgDebugClass c, sgDebugPriority p,
119              const char* fileName, int line, const std::string& msg);
120 
121     /**
122     * output formatted hex dump of memory block
123     */
124     void hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const void *mem, unsigned int len, unsigned int columns = 16);
125 
126 
127     /**
128      * support for the SG_POPUP logging class
129      * set the content of the popup message
130      */
131     void popup( const std::string& msg);
132 
133     /**
134      * retrieve the contents of the popup message and clear it's internal
135      * content. The return value may be an empty string.
136      */
137     std::string get_popup();
138 
139     /**
140      * return true if a new popup message is available. false otherwise.
141      */
142     bool has_popup();
143 
144    /**
145     * \relates logstream
146     * Return the one and only logstream instance.
147     * We use a function instead of a global object so we are assured that cerr
148     * has been initialised.
149     * @return current logstream
150     */
151     friend logstream& sglog();
152 
153     /**
154      * register a logging callback. Note callbacks are run in a
155      * dedicated thread, so callbacks which pass data to other threads
156      * must use appropriate locking.
157      */
158     void addCallback(simgear::LogCallback* cb);
159 
160     void removeCallback(simgear::LogCallback* cb);
161 
162     void removeCallbacks();
163 
164     /**
165      * optionally record all entries and submit them to new log callbacks that
166      * are added. This allows simplified logging configuration, but still including
167      * early startup information in all logs.
168      */
169     void setStartupLoggingEnabled(bool enabled);
170 
171     /**
172      * Set up the logstream for running in test mode.  For example the callbacks
173      * will be unregistered and the behaviour of the would_log() function
174      * sanitized.
175      */
176     void setTestingMode(bool testMode);
177 
178 private:
179     // constructor
180     logstream();
181 
182     class LogStreamPrivate;
183 
184     std::unique_ptr<LogStreamPrivate> d;
185 };
186 
187 logstream& sglog();
188 
189 
190 
191 /** \def SG_LOG(C,P,M)
192  * Log a message.
193  * @param C debug class
194  * @param P priority
195  * @param M message
196  */
197 # define SG_LOGX(C,P,M) \
198     do { if(sglog().would_log(C,P)) {                         \
199         std::ostringstream os; os << M;                  \
200         sglog().log(C, P, __FILE__, __LINE__, os.str()); \
201         if ((P) == SG_POPUP) sglog().popup(os.str());    \
202     } } while(0)
203 #ifdef FG_NDEBUG
204 # define SG_LOG(C,P,M)	do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0)
205 # define SG_LOG_NAN(C,P,M) SG_LOG(C,P,M)
206 # define SG_HEXDUMP(C,P,MEM,LEN)
207 #else
208 # define SG_LOG(C,P,M)	SG_LOGX(C,P,M)
209 # define SG_LOG_NAN(C,P,M) do { SG_LOGX(C,P,M); throw std::overflow_error(M); } while(0)
210 # define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN)
211 #endif
212 
213 #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__)
214 
215 #endif // _LOGSTREAM_H
216 
217