PageRenderTime 24ms CodeModel.GetById 11ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

C++ Header | 458 lines | 98 code | 53 blank | 307 comment | 0 complexity | 7ce9937b4e95a576537fb732b78372d3 MD5 | raw file
  2//  GTMLogger.h
  4//  Copyright 2007-2008 Google Inc.
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 19// Key Abstractions
 20// ----------------
 22// This file declares multiple classes and protocols that are used by the 
 23// GTMLogger logging system. The 4 main abstractions used in this file are the
 24// following:
 26//   * logger (GTMLogger) - The main logging class that users interact with. It
 27//   has methods for logging at different levels and uses a log writer, a log
 28//   formatter, and a log filter to get the job done.
 30//   * log writer (GTMLogWriter) - Writes a given string to some log file, where
 31//   a "log file" can be a physical file on disk, a POST over HTTP to some URL,
 32//   or even some in-memory structure (e.g., a ring buffer).
 34//   * log formatter (GTMLogFormatter) - Given a format string and arguments as
 35//   a va_list, returns a single formatted NSString. A "formatted string" could
 36//   be a string with the date prepended, a string with values in a CSV format,
 37//   or even a string of XML.
 39//   * log filter (GTMLogFilter) - Given a formatted log message as an NSString
 40//   and the level at which the message is to be logged, this class will decide
 41//   whether the given message should be logged or not. This is a flexible way
 42//   to filter out messages logged at a certain level, messages that contain
 43//   certain text, or filter nothing out at all. This gives the caller the
 44//   flexibility to dynamically enable debug logging in Release builds.
 46// This file also declares some classes to handle the common log writer, log
 47// formatter, and log filter cases. Callers can also create their own writers, 
 48// formatters, and filters and they can even build them on top of the ones
 49// declared here. Keep in mind that your custom writer/formatter/filter may be
 50// called from multiple threads, so it must be thread-safe.
 52#import <Foundation/Foundation.h>
 53#import "GTMDefines.h"
 55// Predeclaration of used protocols that are declared later in this file.
 56@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter;
 59#define CHECK_FORMAT_NSSTRING(a, b) __attribute__((format(__NSString__, a, b)))
 61#define CHECK_FORMAT_NSSTRING(a, b)
 64// GTMLogger
 66// GTMLogger is the primary user-facing class for an object-oriented logging
 67// system. It is built on the concept of log formatters (GTMLogFormatter), log
 68// writers (GTMLogWriter), and log filters (GTMLogFilter). When a message is
 69// sent to a GTMLogger to log a message, the message is formatted using the log
 70// formatter, then the log filter is consulted to see if the message should be
 71// logged, and if so, the message is sent to the log writer to be written out.
 73// GTMLogger is intended to be a flexible and thread-safe logging solution. Its
 74// flexibility comes from the fact that GTMLogger instances can be customized
 75// with user defined formatters, filters, and writers. And these writers,
 76// filters, and formatters can be combined, stacked, and customized in arbitrary
 77// ways to suit the needs at hand. For example, multiple writers can be used at
 78// the same time, and a GTMLogger instance can even be used as another
 79// GTMLogger's writer. This allows for arbitrarily deep logging trees.
 81// A standard GTMLogger uses a writer that sends messages to standard out, a
 82// formatter that smacks a timestamp and a few other bits of interesting
 83// information on the message, and a filter that filters out debug messages from
 84// release builds. Using the standard log settings, a log message will look like
 85// the following:
 87//   2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] foo=<Foo: 0x123>
 89// The output contains the date and time of the log message, the name of the
 90// process followed by its process ID/thread ID, the log level at which the
 91// message was logged (in the previous example the level was 1:
 92// kGTMLoggerLevelDebug), and finally, the user-specified log message itself (in
 93// this case, the log message was @"foo=%@", foo).
 95// Multiple instances of GTMLogger can be created, each configured their own
 96// way.  Though GTMLogger is not a singleton (in the GoF sense), it does provide
 97// access to a shared (i.e., globally accessible) GTMLogger instance. This makes
 98// it convenient for all code in a process to use the same GTMLogger instance.
 99// The shared GTMLogger instance can also be configured in an arbitrary, and
100// these configuration changes will affect all code that logs through the shared
101// instance.
104// Log Levels
105// ----------
106// GTMLogger has 3 different log levels: Debug, Info, and Error. GTMLogger
107// doesn't take any special action based on the log level; it simply forwards
108// this information on to formatters, filters, and writers, each of which may
109// optionally take action based on the level. Since log level filtering is
110// performed at runtime, log messages are typically not filtered out at compile
111// time.  The exception to this rule is that calls to the GTMLoggerDebug() macro
112// *ARE* filtered out of non-DEBUG builds. This is to be backwards compatible
113// with behavior that many developers are currently used to. Note that this
114// means that GTMLoggerDebug(@"hi") will be compiled out of Release builds, but
115// [[GTMLogger sharedLogger] logDebug:@"hi"] will NOT be compiled out.
117// Standard loggers are created with the GTMLogLevelFilter log filter, which
118// filters out certain log messages based on log level, and some other settings.
120// In addition to the -logDebug:, -logInfo:, and -logError: methods defined on
121// GTMLogger itself, there are also C macros that make usage of the shared
122// GTMLogger instance very convenient. These macros are:
124//   GTMLoggerDebug(...)
125//   GTMLoggerInfo(...)
126//   GTMLoggerError(...)
128// Again, a notable feature of these macros is that GTMLogDebug() calls *will be
129// compiled out of non-DEBUG builds*.
131// Standard Loggers
132// ----------------
133// GTMLogger has the concept of "standard loggers". A standard logger is simply
134// a logger that is pre-configured with some standard/common writer, formatter,
135// and filter combination. Standard loggers are created using the creation
136// methods beginning with "standard". The alternative to a standard logger is a
137// regular logger, which will send messages to stdout, with no special
138// formatting, and no filtering.
140// How do I use GTMLogger?
141// ----------------------
142// The typical way you will want to use GTMLogger is to simply use the
143// GTMLogger*() macros for logging from code. That way we can easily make
144// changes to the GTMLogger class and simply update the macros accordingly. Only
145// your application startup code (perhaps, somewhere in main()) should use the
146// GTMLogger class directly in order to configure the shared logger, which all
147// of the code using the macros will be using. Again, this is just the typical
148// situation.
150// To be complete, there are cases where you may want to use GTMLogger directly,
151// or even create separate GTMLogger instances for some reason. That's fine,
152// too.
154// Examples
155// --------
156// The following show some common GTMLogger use cases.
158// 1. You want to log something as simply as possible. Also, this call will only
159//    appear in debug builds. In non-DEBUG builds it will be completely removed.
161//      GTMLoggerDebug(@"foo = %@", foo);
163// 2. The previous example is similar to the following. The major difference is 
164//    that the previous call (example 1) will be compiled out of Release builds
165//    but this statement will not be compiled out.
167//      [[GTMLogger sharedLogger] logDebug:@"foo = %@", foo];
169// 3. Send all logging output from the shared logger to a file. We do this by
170//    creating an NSFileHandle for writing associated with a file, and setting 
171//    that file handle as the logger's writer.
173//      NSFileHandle *f = [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log"
174//                                                          create:YES];
175//      [[GTMLogger sharedLogger] setWriter:f];
176//      GTMLoggerError(@"hi");  // This will be sent to /tmp/f.log
178// 4. Create a new GTMLogger that will log to a file. This example differs from
179//    the previous one because here we create a new GTMLogger that is different
180//    from the shared logger.
182//      GTMLogger *logger = [GTMLogger standardLoggerWithPath:@"/tmp/temp.log"];
183//      [logger logInfo:@"hi temp log file"];
185// 5. Create a logger that writes to stdout and does NOT do any formatting to
186//    the log message. This might be useful, for example, when writing a help
187//    screen for a command-line tool to standard output.
189//      GTMLogger *logger = [GTMLogger logger];
190//      [logger logInfo:@"%@ version 0.1 usage", progName];
192// 6. Send log output to stdout AND to a log file. The trick here is that 
193//    NSArrays function as composite log writers, which means when an array is 
194//    set as the log writer, it forwards all logging messages to all of its
195//    contained GTMLogWriters.
197//      // Create array of GTMLogWriters
198//      NSArray *writers = [NSArray arrayWithObjects:
199//          [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" create:YES],
200//          [NSFileHandle fileHandleWithStandardOutput], nil];
202//      GTMLogger *logger = [GTMLogger standardLogger];
203//      [logger setWriter:writers];
204//      [logger logInfo:@"hi"];  // Output goes to stdout and /tmp/f.log
206// For futher details on log writers, formatters, and filters, see the
207// documentation below.
209// NOTE: GTMLogger is application level logging.  By default it does nothing
210// with _GTMDevLog/_GTMDevAssert (see GTMDefines.h).  An application can choose
211// to bridge _GTMDevLog/_GTMDevAssert to GTMLogger by providing macro
212// definitions in its prefix header (see GTMDefines.h for how one would do
213// that).
215@interface GTMLogger : NSObject {
216 @private
217  id<GTMLogWriter> writer_;
218  id<GTMLogFormatter> formatter_;
219  id<GTMLogFilter> filter_;
223// Accessors for the shared logger instance
226// Returns a shared/global standard GTMLogger instance. Callers should typically
227// use this method to get a GTMLogger instance, unless they explicitly want
228// their own instance to configure for their own needs. This is the only method
229// that returns a shared instance; all the rest return new GTMLogger instances.
230+ (id)sharedLogger;
232// Sets the shared logger instance to |logger|. Future calls to +sharedLogger
233// will return |logger| instead.
234+ (void)setSharedLogger:(GTMLogger *)logger;
237// Creation methods
240// Returns a new autoreleased GTMLogger instance that will log to stdout, using
241// the GTMLogStandardFormatter, and the GTMLogLevelFilter filter.
242+ (id)standardLogger;
244// Same as +standardLogger, but logs to stderr.
245+ (id)standardLoggerWithStderr;
247// Returns a new standard GTMLogger instance with a log writer that will
248// write to the file at |path|, and will use the GTMLogStandardFormatter and
249// GTMLogLevelFilter classes. If |path| does not exist, it will be created.
250+ (id)standardLoggerWithPath:(NSString *)path;
252// Returns an autoreleased GTMLogger instance that will use the specified
253// |writer|, |formatter|, and |filter|.
254+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
255             formatter:(id<GTMLogFormatter>)formatter
256                filter:(id<GTMLogFilter>)filter;
258// Returns an autoreleased GTMLogger instance that logs to stdout, with the
259// basic formatter, and no filter. The returned logger differs from the logger
260// returned by +standardLogger because this one does not do any filtering and
261// does not do any special log formatting; this is the difference between a
262// "regular" logger and a "standard" logger.
263+ (id)logger;
265// Designated initializer. This method returns a GTMLogger initialized with the
266// specified |writer|, |formatter|, and |filter|. See the setter methods below
267// for what values will be used if nil is passed for a parameter.
268- (id)initWithWriter:(id<GTMLogWriter>)writer
269           formatter:(id<GTMLogFormatter>)formatter
270              filter:(id<GTMLogFilter>)filter;
273// Logging  methods
276// Logs a message at the debug level (kGTMLoggerLevelDebug).
277- (void)logDebug:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
278// Logs a message at the info level (kGTMLoggerLevelInfo).
279- (void)logInfo:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
280// Logs a message at the error level (kGTMLoggerLevelError).
281- (void)logError:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
282// Logs a message at the assert level (kGTMLoggerLevelAssert).
283- (void)logAssert:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
287// Accessors
290// Accessor methods for the log writer. If the log writer is set to nil,  
291// [NSFileHandle fileHandleWithStandardOutput] is used.
292- (id<GTMLogWriter>)writer;
293- (void)setWriter:(id<GTMLogWriter>)writer;
295// Accessor methods for the log formatter. If the log formatter is set to nil,
296// GTMLogBasicFormatter is used. This formatter will format log messages in a
297// plain printf style.
298- (id<GTMLogFormatter>)formatter;
299- (void)setFormatter:(id<GTMLogFormatter>)formatter;
301// Accessor methods for the log filter. If the log filter is set to nil,
302// GTMLogNoFilter is used, which allows all log messages through.
303- (id<GTMLogFilter>)filter;
304- (void)setFilter:(id<GTMLogFilter>)filter;
306@end  // GTMLogger
309// Helper functions that are used by the convenience GTMLogger*() macros that 
310// enable the logging of function names.
311@interface GTMLogger (GTMLoggerMacroHelpers)
312- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ...
314- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ...
316- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ...
318- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ...
320@end  // GTMLoggerMacroHelpers
323// Convenience macros that log to the shared GTMLogger instance. These macros
324// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug()
325// calls will be compiled out of non-Debug builds.
326#define GTMLoggerDebug(...)  \
327  [[GTMLogger sharedLogger] logFuncDebug:__func__ msg:__VA_ARGS__]
328#define GTMLoggerInfo(...)   \
329  [[GTMLogger sharedLogger] logFuncInfo:__func__ msg:__VA_ARGS__]
330#define GTMLoggerError(...)  \
331  [[GTMLogger sharedLogger] logFuncError:__func__ msg:__VA_ARGS__]
332#define GTMLoggerAssert(...) \
333  [[GTMLogger sharedLogger] logFuncAssert:__func__ msg:__VA_ARGS__]
335// If we're not in a debug build, remove the GTMLoggerDebug statements. This
336// makes calls to GTMLoggerDebug "compile out" of Release builds
337#ifndef DEBUG
338#undef GTMLoggerDebug
339#define GTMLoggerDebug(...) do {} while(0)
342// Log levels.
343typedef enum {
344  kGTMLoggerLevelUnknown,
345  kGTMLoggerLevelDebug,
346  kGTMLoggerLevelInfo,
347  kGTMLoggerLevelError,
348  kGTMLoggerLevelAssert,
349} GTMLoggerLevel;
353//   Log Writers
356// Protocol to be implemented by a GTMLogWriter instance.
357@protocol GTMLogWriter <NSObject>
358// Writes the given log message to where the log writer is configured to write.
359- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level;
360@end  // GTMLogWriter
363// Simple category on NSFileHandle that makes NSFileHandles valid log writers.
364// This is convenient because something like, say, +fileHandleWithStandardError
365// now becomes a valid log writer. Log messages are written to the file handle
366// with a newline appended.
367@interface NSFileHandle (GTMFileHandleLogWriter) <GTMLogWriter>
368// Opens the file at |path| in append mode, and creates the file with |mode| 
369// if it didn't previously exist.
370+ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode;
371@end  // NSFileHandle
374// This category makes NSArray a GTMLogWriter that can be composed of other
375// GTMLogWriters. This is the classic Composite GoF design pattern. When the
376// GTMLogWriter -logMessage:level: message is sent to the array, the array
377// forwards the message to all of its elements that implement the GTMLogWriter
378// protocol.
380// This is useful in situations where you would like to send log output to
381// multiple log writers at the same time. Simply create an NSArray of the log
382// writers you wish to use, then set the array as the "writer" for your 
383// GTMLogger instance.
384@interface NSArray (GTMArrayCompositeLogWriter) <GTMLogWriter>
385@end  // GTMArrayCompositeLogWriter
388// This category adapts the GTMLogger interface so that it can be used as a log
389// writer; it's an "adapter" in the GoF Adapter pattern sense.
391// This is useful when you want to configure a logger to log to a specific
392// writer with a specific formatter and/or filter. But you want to also compose
393// that with a different log writer that may have its own formatter and/or 
394// filter.
395@interface GTMLogger (GTMLoggerLogWriter) <GTMLogWriter>
396@end  // GTMLoggerLogWriter
400//   Log Formatters
403// Protocol to be implemented by a GTMLogFormatter instance.
404@protocol GTMLogFormatter <NSObject>
405// Returns a formatted string using the format specified in |fmt| and the va
406// args specified in |args|.
407- (NSString *)stringForFunc:(NSString *)func
408                 withFormat:(NSString *)fmt
409                     valist:(va_list)args
410                      level:(GTMLoggerLevel)level;
411@end  // GTMLogFormatter
414// A basic log formatter that formats a string the same way that NSLog (or 
415// printf) would. It does not do anything fancy, nor does it add any data of its
416// own.
417@interface GTMLogBasicFormatter : NSObject <GTMLogFormatter>
418@end  // GTMLogBasicFormatter
421// A log formatter that formats the log string like the basic formatter, but
422// also prepends a timestamp and some basic process info to the message, as
423// shown in the following sample output.
424//   2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] log mesage here
425@interface GTMLogStandardFormatter : GTMLogBasicFormatter {
426 @private
427  NSDateFormatter *dateFormatter_;  // yyyy-MM-dd HH:mm:ss.SSS
428  NSString *pname_;
429  pid_t pid_;
431@end  // GTMLogStandardFormatter
435//   Log Filters
438// Protocol to be imlemented by a GTMLogFilter instance.
439@protocol GTMLogFilter <NSObject>
440// Returns YES if |msg| at |level| should be filtered out; NO otherwise.
441- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level;
442@end  // GTMLogFilter
445// A log filter that filters messages at the kGTMLoggerLevelDebug level out of
446// non-debug builds. Messages at the kGTMLoggerLevelInfo level are also filtered
447// out of non-debug builds unless GTMVerboseLogging is set in the environment or
448// the processes's defaults. Messages at the kGTMLoggerLevelError level are
449// never filtered.
450@interface GTMLogLevelFilter : NSObject <GTMLogFilter>
451@end  // GTMLogLevelFilter
454// A simple log filter that does NOT filter anything out;
455// -filterAllowsMessage:level will always return YES. This can be a convenient
456// way to enable debug-level logging in release builds (if you so desire).
457@interface GTMLogNoFilter : NSObject <GTMLogFilter>
458@end  // GTMLogNoFilter