OLD | NEW |
| (Empty) |
1 // Copyright 2003-2009 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 // | |
16 // logging.h | |
17 // | |
18 // Tracing and logging system. | |
19 // Allows filtering of the log messages based on logging categories and levels. | |
20 | |
21 #ifndef OMAHA_BASE_LOGGING_H_ | |
22 #define OMAHA_BASE_LOGGING_H_ | |
23 | |
24 #include "omaha/base/constants.h" | |
25 #include "omaha/base/synchronized.h" | |
26 #include "omaha/base/time.h" | |
27 | |
28 #ifdef LOGGING | |
29 | |
30 // Logging levels. | |
31 enum LogLevel { | |
32 LEVEL_FATALERROR = -3, // crashing fatal error | |
33 LEVEL_ERROR = -2, // errors - recoverable but shouldn't happen | |
34 LE = -2, | |
35 LEVEL_WARNING = -1, // warnings | |
36 LW = -1, | |
37 L1 = 1, // for aprox. 10 logs per run | |
38 L2, // for aprox. 100 logs per run | |
39 L3, // for aprox. 1,000 logs per run | |
40 L4, // for aprox. 10,000 logs per run | |
41 L5, // for aprox. 100,000 logs per run | |
42 L6, // for > 1,000,000 logs per run | |
43 | |
44 // add above | |
45 LEVEL_ALL // all errors | |
46 }; | |
47 | |
48 #endif | |
49 | |
50 namespace omaha { | |
51 | |
52 #define kDefaultLoggingEnabled 1 | |
53 #define kLogConfigFileName MAIN_EXE_BASE_NAME _T(".ini") | |
54 #define kDefaultLogFileName MAIN_EXE_BASE_NAME _T(".log") | |
55 #define kDefaultLogFileWide 1 | |
56 #define kDefaultShowTime 1 | |
57 #define kDefaultAppendToFile 1 | |
58 | |
59 #ifdef _DEBUG | |
60 #define kDefaultMaxLogFileSize 0xFFFFFFFF // 4GB | |
61 #define kDefaultLogToFile 1 | |
62 #define kDefaultLogToOutputDebug 1 | |
63 #define kDefaultLogLevel L3 | |
64 #else | |
65 #define kDefaultMaxLogFileSize 10000000 // 10MB | |
66 #define kDefaultLogToFile 0 | |
67 #define kDefaultLogToOutputDebug 0 | |
68 #define kDefaultLogLevel L1 | |
69 #endif | |
70 | |
71 // Truncates the log file when the size of the log file is this many | |
72 // times over the MaxLogFileSize to prevent disk overfill. | |
73 #define kStopGapLogFileSizeFactor 10 | |
74 | |
75 // config file sections | |
76 #define kConfigSectionLoggingLevel L"LoggingLevel" | |
77 #define kConfigSectionLoggingSettings L"LoggingSettings" | |
78 | |
79 // config file attributes | |
80 #define kConfigAttrEnableLogging L"EnableLogging" | |
81 #define kConfigAttrShowTime L"ShowTime" | |
82 #define kConfigAttrLogToFile L"LogToFile" | |
83 #define kConfigAttrLogFilePath L"LogFilePath" | |
84 #define kConfigAttrLogFileWide L"LogFileWide" | |
85 #define kConfigAttrLogToOutputDebug L"LogToOutputDebug" | |
86 #define kConfigAttrAppendToFile L"AppendToFile" | |
87 #define kConfigAttrMaxLogFileSize L"MaxLogFileSize" | |
88 | |
89 #define kLoggingMutexName kLockPrefix L"logging_mutex" | |
90 #define kMaxMutexWaitTimeMs 500 | |
91 | |
92 // Does not allow messages bigger than 1 MB. | |
93 #define kMaxLogMessageSize (1024 * 1024) | |
94 | |
95 #define kLogSettingsCheckInterval (5 * kSecsTo100ns) | |
96 | |
97 #define kStartOfLogMessage \ | |
98 L"********************* NEW LOG *********************" | |
99 #define kEndOfLogMessage \ | |
100 L"********************* END LOG *********************" | |
101 | |
102 // TODO(omaha): Allow these defaults to be overriden in the config file. | |
103 #define kMaxLevelToStoreInLogHistory L2 | |
104 #define kMaxHistoryBufferSize 1024 | |
105 | |
106 #ifdef LOGGING | |
107 | |
108 #define LC_LOG(cat, level, msg) \ | |
109 do { \ | |
110 omaha::Logging* logger = omaha::GetLogging(); \ | |
111 if (logger) { \ | |
112 omaha::LoggingHelper(logger, cat, level, \ | |
113 logger->IsCatLevelEnabled(cat, level)) msg; \ | |
114 } \ | |
115 } while (0) | |
116 | |
117 #define LC_LOG_OPT(cat, level, msg) LC_LOG(cat, level, msg) | |
118 | |
119 #else | |
120 #define LC_LOG(cat, level, msg) ((void)0) | |
121 #endif | |
122 | |
123 #ifdef _DEBUG | |
124 #define LC_LOG_DEBUG(cat, level, msg) LC_LOG(cat, level, msg) | |
125 #else | |
126 #define LC_LOG_DEBUG(cat, level, msg) ((void)0) | |
127 #endif | |
128 | |
129 // Shortcuts for different logging categories - no need to specify the category. | |
130 #define CORE_LOG(x, y) LC_LOG_DEBUG(omaha::LC_CORE, x, y) | |
131 #define NET_LOG(x, y) LC_LOG_DEBUG(omaha::LC_NET, x, y) | |
132 #define PLUGIN_LOG(x, y) LC_LOG_DEBUG(omaha::LC_PLUGIN, x, y) | |
133 #define SERVICE_LOG(x, y) LC_LOG_DEBUG(omaha::LC_SERVICE, x, y) | |
134 #define SETUP_LOG(x, y) LC_LOG_DEBUG(omaha::LC_SETUP, x, y) | |
135 #define SHELL_LOG(x, y) LC_LOG_DEBUG(omaha::LC_SHELL, x, y) | |
136 #define UTIL_LOG(x, y) LC_LOG_DEBUG(omaha::LC_UTIL, x, y) | |
137 | |
138 #define OPT_LOG(x, y) LC_LOG_OPT(omaha::LC_OPT, x, y) | |
139 #define REPORT_LOG(x, y) LC_LOG_OPT(omaha::LC_REPORT, x, y) | |
140 | |
141 #ifdef LOGGING | |
142 | |
143 // Logging components. | |
144 // Maximum 32 categories unless mask is increased to 64 bits. | |
145 enum LogCategory { | |
146 LC_LOGGING = 0, | |
147 | |
148 // ADD BELOW - AND REMEMBER: | |
149 // - Add a line to the LogCategoryNames table in logging.cc!!! | |
150 // - Add to C:\GoogleUpdate.ini. | |
151 | |
152 LC_UTIL, | |
153 LC_SETUP, | |
154 LC_SHELL, | |
155 LC_CORE, | |
156 LC_JS, | |
157 LC_PLUGIN, | |
158 LC_SERVICE, | |
159 LC_OPT, | |
160 LC_NET, | |
161 LC_REPORT, | |
162 | |
163 // ADD ABOVE | |
164 | |
165 LC_MAX_CAT | |
166 }; | |
167 | |
168 #define kCatEnabledField L"Enabled" | |
169 #define kCatLevelField L"Level" | |
170 | |
171 struct CategoryInfo { | |
172 bool enabled; | |
173 LogLevel log_level; | |
174 }; | |
175 | |
176 // If you want to log anything else, add it to this structure. This structure | |
177 // basically says that each logged message is composed of two parts, and they | |
178 // are output one after the other. Intended to be used for a message "prefix" | |
179 // and the message itself (the prefix can contain the component name, the time, | |
180 // and any other logging system boilerplate, while the message is supplied by | |
181 // the component). (This basically saves having to copy a variable length - | |
182 // possibly very large - message just to tack it onto the end of the message | |
183 // prefix.) | |
184 struct OutputInfo { | |
185 LogCategory category; | |
186 LogLevel level; | |
187 const wchar_t* msg1; | |
188 const wchar_t* msg2; | |
189 | |
190 OutputInfo(LogCategory cat, LogLevel log_level, | |
191 const wchar_t* m1, const wchar_t* m2) | |
192 : category(cat), | |
193 level(log_level), | |
194 msg1(m1), | |
195 msg2(m2) {} | |
196 }; | |
197 | |
198 // The LogWriter - can decide whether to process message or not, then | |
199 // will process it. Actually, the message is processed if either a) the | |
200 // individual LogWriter wants to process it or b) it is marked as processable | |
201 // by settings in config ini. | |
202 // | |
203 // Included LogWriters: | |
204 // OutputDebugStringLogWriter - Logs to OutputDebugString() API | |
205 // FileLogWriter - Logs to a file | |
206 // OverrideConfigLogWriter - Overrides the level settings of a | |
207 // particular category, uses another writer to actually do the writing. | |
208 // Used, e.g., in installer to force SETUP_LOG messages to go to a file | |
209 // tr_setup_log.info even if the there is no trconfig.ini file. | |
210 // | |
211 // Not included LogWriters: | |
212 // StdLogWriter - Logs to stdout or stderr | |
213 // SubmitToGoogleLogWriter - When done logging submits the log file to | |
214 // Google's status-receiving server | |
215 class LogWriter { | |
216 protected: | |
217 LogWriter(); | |
218 virtual void Cleanup(); | |
219 public: | |
220 virtual ~LogWriter(); | |
221 | |
222 // Returns true if this Logging object wants to log even if the global | |
223 // "enable logging" flag is off. Useful for always creating a log, e.g., an | |
224 // install log, even without a GoogleUpdate.ini. | |
225 virtual bool WantsToLogRegardless() const; | |
226 | |
227 // Returns true if this Logging object wants to handle the message, | |
228 // regardless of other settings. | |
229 virtual bool IsCatLevelEnabled(LogCategory category, LogLevel level) const; | |
230 | |
231 virtual void OutputMessage(const OutputInfo* output_info); | |
232 | |
233 // Registers and unregisters this LogWriter with the Logging system. When | |
234 // registered, the Logging class assumes ownership. | |
235 bool Register(); | |
236 bool Unregister(); | |
237 | |
238 private: | |
239 DISALLOW_EVIL_CONSTRUCTORS(LogWriter); | |
240 }; | |
241 | |
242 // A LogWriter that writes to a named file. | |
243 class FileLogWriter : public LogWriter { | |
244 protected: | |
245 FileLogWriter(const wchar_t* file_name, bool append); | |
246 ~FileLogWriter(); | |
247 virtual void Cleanup(); | |
248 | |
249 public: | |
250 static FileLogWriter* Create(const wchar_t* file_name, bool append); | |
251 virtual void OutputMessage(const OutputInfo* output_info); | |
252 | |
253 private: | |
254 void Initialize(); | |
255 bool CreateLoggingMutex(); | |
256 bool CreateLoggingFile(); | |
257 bool ArchiveLoggingFile(); | |
258 bool TruncateLoggingFile(); | |
259 bool GetMutex(); | |
260 void ReleaseMutex(); | |
261 | |
262 // Returns true if archiving of the log file is pending a computer restart. | |
263 bool IsArchivePending(); | |
264 | |
265 // Returns the first position of str inside of a MULTI_SZ of count characters | |
266 // including the terminating zeros. | |
267 static int FindFirstInMultiString(const wchar_t* multi_str, | |
268 size_t count, | |
269 const wchar_t* str); | |
270 | |
271 uint32 max_file_size_; | |
272 bool initialized_; | |
273 bool valid_; | |
274 bool append_; | |
275 bool log_file_wide_; | |
276 CString log_file_mutex_name_; | |
277 HANDLE log_file_mutex_; | |
278 CString file_name_; | |
279 HANDLE log_file_; | |
280 CString proc_name_; | |
281 | |
282 friend class FileLogWriterTest; | |
283 | |
284 DISALLOW_EVIL_CONSTRUCTORS(FileLogWriter); | |
285 }; | |
286 | |
287 // A LogWriter that uses OutputDebugString() to write messages. | |
288 class OutputDebugStringLogWriter : public LogWriter { | |
289 protected: | |
290 OutputDebugStringLogWriter(); | |
291 ~OutputDebugStringLogWriter(); | |
292 public: | |
293 static OutputDebugStringLogWriter* Create(); | |
294 virtual void OutputMessage(const OutputInfo* info); | |
295 private: | |
296 DISALLOW_EVIL_CONSTRUCTORS(OutputDebugStringLogWriter); | |
297 }; | |
298 | |
299 // A LogWriter that overrides the settings in trconfig.ini and sends messages | |
300 // to another LogWriter. Takes ownership of the other LogWriter. | |
301 class OverrideConfigLogWriter : public LogWriter { | |
302 protected: | |
303 OverrideConfigLogWriter(LogCategory category, LogLevel level, | |
304 LogWriter* log_writer, bool force_logging_enabled); | |
305 virtual void Cleanup(); | |
306 public: | |
307 static OverrideConfigLogWriter* Create(LogCategory category, LogLevel level, | |
308 LogWriter* log_writer, bool force_logging_enabled); | |
309 virtual bool WantsToLogRegardless() const; | |
310 virtual bool IsCatLevelEnabled(LogCategory category, LogLevel level) const; | |
311 virtual void OutputMessage(const OutputInfo* output_info); | |
312 private: | |
313 LogCategory category_; | |
314 LogLevel level_; | |
315 LogWriter* log_writer_; | |
316 bool force_logging_enabled_; | |
317 DISALLOW_EVIL_CONSTRUCTORS(OverrideConfigLogWriter); | |
318 }; | |
319 | |
320 // This log writer outputs to Event Tracing for Windows. | |
321 class EtwLogWriter; | |
322 | |
323 // The Logging class - Singleton class | |
324 // Fine-grain logging based on categories and levels. | |
325 // Can log to a file, stdout or debugger. | |
326 class Logging { | |
327 public: | |
328 // constructor | |
329 Logging(); | |
330 | |
331 // destructor | |
332 ~Logging(); | |
333 | |
334 // Enables/disables the logging mechanism. Allows turning logging on/off | |
335 // in mid-run. Returns true for success (not for 'logging enabled'). | |
336 void EnableLogging(); | |
337 void DisableLogging(); | |
338 | |
339 // Checks if logging is enabled - and updates logging settings from the | |
340 // configuration file every kLogSettingsCheckInterval seconds | |
341 bool IsLoggingEnabled(); | |
342 | |
343 // Checks if logging is already enabled. It does not try to enable it. | |
344 bool IsLoggingAlreadyEnabled() const; | |
345 | |
346 // Overrides the config file settings for showing the time stamps. | |
347 void ForceShowTimestamp(bool force_show_time); | |
348 | |
349 // Checks if logging is enabled for a given category and level. | |
350 DWORD IsCatLevelEnabled(LogCategory category, LogLevel level); | |
351 LogLevel GetCatLevel(LogCategory category) const; | |
352 | |
353 // Logs a message. | |
354 void LogMessage(LogCategory cat, LogLevel level, const wchar_t* fmt, ...); | |
355 void LogMessageVA(LogCategory cat, LogLevel level, const wchar_t* fmt, | |
356 va_list args); | |
357 | |
358 // Retrieves the default location of the log directory. | |
359 CString GetDefaultLogDirectory() const; | |
360 | |
361 // Computes and returns the complete path of the log file. | |
362 CString GetLogFilePath() const; | |
363 | |
364 // Retrieves in-memory history buffer. | |
365 CString GetHistory(); | |
366 | |
367 // Returns the file path of the current GoogleUpdate.ini. | |
368 CString GetCurrentConfigurationFilePath() const; | |
369 | |
370 const CString& proc_name() const { return proc_name_; } | |
371 | |
372 bool IsCategoryEnabledForBuffering(LogCategory cat); | |
373 private: | |
374 bool InternalInitialize(); | |
375 void InternalLogMessageMaskedVA(DWORD writer_mask, | |
376 LogCategory cat, | |
377 LogLevel level, | |
378 CString* log_buffer, | |
379 CString* prefix, | |
380 const wchar_t* fmt, | |
381 va_list args); | |
382 | |
383 friend class LoggingHelper; | |
384 void LogMessageMaskedVA(DWORD writer_mask, LogCategory cat, LogLevel level, | |
385 const wchar_t* fmt, va_list args); | |
386 | |
387 // Stores log message in in-memory history buffer. | |
388 void StoreInHistory(const OutputInfo* output_info); | |
389 | |
390 // Appends string to in-memory history buffer. | |
391 void AppendToHistory(const wchar_t* msg); | |
392 | |
393 // Initializes the logging engine. Harmless to call multiple times. | |
394 bool InitializeLogging(); | |
395 | |
396 // Configures/unconfigures the log writers for the current settings. That | |
397 // is, given the current settings from GoogleUpdate.ini, either initializes | |
398 // and registers the file-out and debug-out logwriters, or unregisters them. | |
399 void ConfigureETWLogWriter(); | |
400 void ConfigureFileLogWriter(); | |
401 void ConfigureDebugOutLogWriter(); | |
402 bool ConfigureLogging(); | |
403 void UnconfigureLogging(); | |
404 | |
405 void UpdateCatAndLevel(const wchar_t* cat_name, LogCategory cat); | |
406 void ReadLoggingSettings(); | |
407 | |
408 // Returns the primary file path of the GoogleUpdate.ini. | |
409 CString GetConfigurationFilePath() const; | |
410 | |
411 // Returns the alternate file path of the GoogleUpdate.ini. | |
412 CString GetAltConfigurationFilePath() const; | |
413 | |
414 public: | |
415 | |
416 // Passes the messages along to other OutputMessage() | |
417 void OutputMessage(DWORD writer_mask, LogCategory cat, LogLevel level, | |
418 const wchar_t* msg1, const wchar_t* msg2); | |
419 | |
420 // Broadcasts the message to each LogWriter. | |
421 // It should be private but the function we want to be able to use this, | |
422 // debugASSERT is extern "C" and thus can't be declared a friend of | |
423 // Logging. | |
424 void OutputMessage(DWORD writer_mask, const OutputInfo* output_info); | |
425 | |
426 private: | |
427 | |
428 CategoryInfo category_list_[LC_MAX_CAT]; | |
429 | |
430 // Checks if logging is initialized. | |
431 bool logging_initialized_; | |
432 | |
433 // Is logging in the process of initializing? | |
434 bool is_initializing_; | |
435 | |
436 // The logging process name including the calling module. | |
437 CString proc_name_; | |
438 | |
439 // Serializes changing logging init/uninit/enable/disable status. | |
440 LLock lock_; | |
441 | |
442 // Bunch of settings from the config .ini file. | |
443 bool logging_enabled_; // Checks if logging is enabled. | |
444 bool force_show_time_; | |
445 bool show_time_; | |
446 bool log_to_file_; | |
447 CString log_file_name_; | |
448 bool log_to_debug_out_; | |
449 bool append_to_file_; | |
450 | |
451 // Signals the logging system is shutting down. | |
452 bool logging_shutdown_; | |
453 | |
454 // Checkpoint time for dynamic category updates. | |
455 time64 g_last_category_check_time; | |
456 | |
457 // The file path of the optional ini file which defines the logging | |
458 // configuration. | |
459 CString config_file_path_; | |
460 | |
461 private: | |
462 bool InternalRegisterWriter(LogWriter* log_writer); | |
463 bool InternalUnregisterWriter(LogWriter* log_writer); | |
464 | |
465 public: | |
466 bool RegisterWriter(LogWriter* log_writer); | |
467 bool UnregisterWriter(LogWriter* log_writer); | |
468 enum { all_writers_mask = -1 }; | |
469 | |
470 private: | |
471 enum { max_writers = 15 }; | |
472 int num_writers_; | |
473 LogWriter* writers_[max_writers]; | |
474 | |
475 LogWriter* file_log_writer_; | |
476 LogWriter* debug_out_writer_; | |
477 LogWriter* etw_log_writer_; | |
478 | |
479 friend class HistoryTest; | |
480 | |
481 DISALLOW_EVIL_CONSTRUCTORS(Logging); | |
482 }; | |
483 | |
484 // In order to make the logging macro LC_LOG work out we need to pass a | |
485 // parameter (the mask of loggers to write to) (*) to the actual logging | |
486 // method. However, the last parameter to the macro LC_LOG has its own | |
487 // parenthesis - it encloses multiple expressions (a format string and | |
488 // arguments). So this function object is used as an intermediary in order to | |
489 // hold the writer mask. | |
490 // | |
491 // (*) The mask needs to be transferred separately because we want to keep the | |
492 // LC_LOG structure of asking if the message is going to be logged before | |
493 // evaluating the arguments, and we can't store it in the singleton Logging | |
494 // object - wouldn't be thread-safe. | |
495 | |
496 class LoggingHelper { | |
497 public: | |
498 LoggingHelper(Logging* logger, LogCategory cat, | |
499 LogLevel level, DWORD writer_mask) | |
500 : logger_(logger), | |
501 category_(cat), | |
502 level_(level), | |
503 writer_mask_(writer_mask) {} | |
504 | |
505 void operator()(const wchar_t* fmt, ...) { | |
506 va_list args; | |
507 va_start(args, fmt); | |
508 logger_->LogMessageMaskedVA(writer_mask_, category_, level_, fmt, args); | |
509 va_end(args); | |
510 } | |
511 | |
512 private: | |
513 Logging* logger_; | |
514 DWORD writer_mask_; | |
515 LogLevel level_; | |
516 LogCategory category_; | |
517 | |
518 DISALLOW_EVIL_CONSTRUCTORS(LoggingHelper); | |
519 }; | |
520 | |
521 // Getter for the Logging singleton class. | |
522 Logging* GetLogging(); | |
523 | |
524 #endif // LOGGING | |
525 | |
526 } // namespace omaha | |
527 | |
528 #endif // OMAHA_BASE_LOGGING_H_ | |
OLD | NEW |