PageRenderTime 97ms CodeModel.GetById 15ms app.highlight 78ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/common/mac/GTMLogger.m

http://github.com/tomahawk-player/tomahawk
Objective C | 445 lines | 331 code | 81 blank | 33 comment | 43 complexity | d79998b5af8c9d0036ed8a6a94a8b6c3 MD5 | raw file
  1//
  2//  GTMLogger.m
  3//
  4//  Copyright 2007-2008 Google Inc.
  5//
  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
  9// 
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11// 
 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.
 17//
 18
 19#import "GTMLogger.h"
 20#import "GTMGarbageCollection.h"
 21#import <fcntl.h>
 22#import <unistd.h>
 23#import <stdlib.h>
 24#import <pthread.h>
 25
 26
 27// Define a trivial assertion macro to avoid dependencies
 28#ifdef DEBUG
 29  #define GTMLOGGER_ASSERT(expr) assert(expr)
 30#else
 31  #define GTMLOGGER_ASSERT(expr)
 32#endif
 33
 34
 35@interface GTMLogger (PrivateMethods)
 36
 37- (void)logInternalFunc:(const char *)func
 38                 format:(NSString *)fmt
 39                 valist:(va_list)args 
 40                  level:(GTMLoggerLevel)level;
 41
 42@end
 43
 44
 45// Reference to the shared GTMLogger instance. This is not a singleton, it's 
 46// just an easy reference to one shared instance.
 47static GTMLogger *gSharedLogger = nil;
 48
 49
 50@implementation GTMLogger
 51
 52// Returns a pointer to the shared logger instance. If none exists, a standard 
 53// logger is created and returned.
 54+ (id)sharedLogger {
 55  @synchronized(self) {
 56    if (gSharedLogger == nil) {
 57      gSharedLogger = [[self standardLogger] retain];
 58    }
 59    GTMLOGGER_ASSERT(gSharedLogger != nil);
 60  }
 61  return [[gSharedLogger retain] autorelease];
 62}
 63
 64+ (void)setSharedLogger:(GTMLogger *)logger {
 65  @synchronized(self) {
 66    [gSharedLogger autorelease];
 67    gSharedLogger = [logger retain];
 68  }
 69}
 70
 71+ (id)standardLogger {
 72  id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
 73  id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] autorelease];
 74  id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
 75  return [self loggerWithWriter:writer formatter:fr filter:filter];
 76}
 77
 78+ (id)standardLoggerWithStderr {
 79  id me = [self standardLogger];
 80  [me setWriter:[NSFileHandle fileHandleWithStandardError]];
 81  return me;
 82}
 83
 84+ (id)standardLoggerWithPath:(NSString *)path {
 85  NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
 86  if (fh == nil) return nil;
 87  id me = [self standardLogger];
 88  [me setWriter:fh];
 89  return me;
 90}
 91
 92+ (id)loggerWithWriter:(id<GTMLogWriter>)writer
 93             formatter:(id<GTMLogFormatter>)formatter
 94                filter:(id<GTMLogFilter>)filter {
 95  return [[[self alloc] initWithWriter:writer
 96                             formatter:formatter
 97                                filter:filter] autorelease];
 98}
 99
100+ (id)logger {
101  return [[[self alloc] init] autorelease];
102}
103
104- (id)init {
105  return [self initWithWriter:nil formatter:nil filter:nil];
106}
107
108- (id)initWithWriter:(id<GTMLogWriter>)writer
109           formatter:(id<GTMLogFormatter>)formatter
110              filter:(id<GTMLogFilter>)filter {
111  if ((self = [super init])) {
112    [self setWriter:writer];
113    [self setFormatter:formatter];
114    [self setFilter:filter];
115    GTMLOGGER_ASSERT(formatter_ != nil);
116    GTMLOGGER_ASSERT(filter_ != nil);
117    GTMLOGGER_ASSERT(writer_ != nil);
118  }
119  return self;
120}
121
122- (void)dealloc {
123  GTMLOGGER_ASSERT(writer_ != nil);
124  GTMLOGGER_ASSERT(formatter_ != nil);
125  GTMLOGGER_ASSERT(filter_ != nil);
126  [writer_ release];
127  [formatter_ release];
128  [filter_ release];
129  [super dealloc];
130}
131
132- (id<GTMLogWriter>)writer {
133  GTMLOGGER_ASSERT(writer_ != nil);
134  return [[writer_ retain] autorelease];
135}
136
137- (void)setWriter:(id<GTMLogWriter>)writer {
138  @synchronized(self) {
139    [writer_ autorelease];
140    if (writer == nil)
141      writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
142    else
143      writer_ = [writer retain];
144  }
145  GTMLOGGER_ASSERT(writer_ != nil);
146}
147
148- (id<GTMLogFormatter>)formatter {
149  GTMLOGGER_ASSERT(formatter_ != nil);
150  return [[formatter_ retain] autorelease];
151}
152
153- (void)setFormatter:(id<GTMLogFormatter>)formatter {
154  @synchronized(self) {
155    [formatter_ autorelease];
156    if (formatter == nil)
157      formatter_ = [[GTMLogBasicFormatter alloc] init];
158    else
159      formatter_ = [formatter retain];
160  }
161  GTMLOGGER_ASSERT(formatter_ != nil);
162}
163
164- (id<GTMLogFilter>)filter {
165  GTMLOGGER_ASSERT(filter_ != nil);
166  return [[filter_ retain] autorelease];
167}
168
169- (void)setFilter:(id<GTMLogFilter>)filter {
170  @synchronized(self) {
171    [filter_ autorelease];
172    if (filter == nil)
173      filter_ = [[GTMLogNoFilter alloc] init];
174    else
175      filter_ = [filter retain];
176  }
177  GTMLOGGER_ASSERT(filter_ != nil);
178}
179
180- (void)logDebug:(NSString *)fmt, ... {
181  va_list args;
182  va_start(args, fmt);
183  [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug];
184  va_end(args);
185}
186
187- (void)logInfo:(NSString *)fmt, ... {
188  va_list args;
189  va_start(args, fmt);
190  [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo];
191  va_end(args);
192}
193
194- (void)logError:(NSString *)fmt, ... {
195  va_list args;
196  va_start(args, fmt);
197  [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError];
198  va_end(args);
199}
200
201- (void)logAssert:(NSString *)fmt, ... {
202  va_list args;
203  va_start(args, fmt);
204  [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert];
205  va_end(args);
206}
207
208@end  // GTMLogger
209
210
211@implementation GTMLogger (GTMLoggerMacroHelpers)
212
213- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
214  va_list args;
215  va_start(args, fmt);
216  [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug];
217  va_end(args);
218}
219
220- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... {
221  va_list args;
222  va_start(args, fmt);
223  [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo];
224  va_end(args);
225}
226
227- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... {
228  va_list args;
229  va_start(args, fmt);
230  [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError];
231  va_end(args);
232}
233
234- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... {
235  va_list args;
236  va_start(args, fmt);
237  [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert];
238  va_end(args);
239}
240
241@end  // GTMLoggerMacroHelpers
242
243
244@implementation GTMLogger (PrivateMethods)
245
246- (void)logInternalFunc:(const char *)func
247                 format:(NSString *)fmt
248                 valist:(va_list)args 
249                  level:(GTMLoggerLevel)level {
250  GTMLOGGER_ASSERT(formatter_ != nil);
251  GTMLOGGER_ASSERT(filter_ != nil);
252  GTMLOGGER_ASSERT(writer_ != nil);
253  
254  NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
255  NSString *msg = [formatter_ stringForFunc:fname
256                                 withFormat:fmt
257                                     valist:args 
258                                      level:level];
259  if (msg && [filter_ filterAllowsMessage:msg level:level])
260    [writer_ logMessage:msg level:level];
261}
262
263@end  // PrivateMethods
264
265
266@implementation NSFileHandle (GTMFileHandleLogWriter)
267
268+ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode {
269  int fd = -1;
270  if (path) {
271    int flags = O_WRONLY | O_APPEND | O_CREAT;
272    fd = open([path fileSystemRepresentation], flags, mode);
273  }
274  if (fd == -1) return nil;
275  return [[[self alloc] initWithFileDescriptor:fd
276                                closeOnDealloc:YES] autorelease];
277}
278
279- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
280  @synchronized(self) {
281    NSString *line = [NSString stringWithFormat:@"%@\n", msg];
282    [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
283  }
284}
285
286@end  // GTMFileHandleLogWriter
287
288
289@implementation NSArray (GTMArrayCompositeLogWriter)
290
291- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
292  @synchronized(self) {
293    id<GTMLogWriter> child = nil;
294    GTM_FOREACH_OBJECT(child, self) {
295      if ([child conformsToProtocol:@protocol(GTMLogWriter)])
296        [child logMessage:msg level:level];
297    }
298  }
299}
300
301@end  // GTMArrayCompositeLogWriter
302
303
304@implementation GTMLogger (GTMLoggerLogWriter)
305
306- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
307  switch (level) {
308    case kGTMLoggerLevelDebug:
309      [self logDebug:@"%@", msg]; 
310      break;
311    case kGTMLoggerLevelInfo:
312      [self logInfo:@"%@", msg];
313      break;
314    case kGTMLoggerLevelError:   
315      [self logError:@"%@", msg];
316      break;
317    case kGTMLoggerLevelAssert:
318      [self logAssert:@"%@", msg];
319      break;
320    default: 
321      // Ignore the message.
322      break;
323  }
324}
325
326@end  // GTMLoggerLogWriter
327
328
329@implementation GTMLogBasicFormatter
330
331- (NSString *)stringForFunc:(NSString *)func
332                 withFormat:(NSString *)fmt
333                     valist:(va_list)args 
334                      level:(GTMLoggerLevel)level {
335  // Performance note: since we always have to create a new NSString from the 
336  // returned CFStringRef, we may want to do a quick check here to see if |fmt|
337  // contains a '%', and if not, simply return 'fmt'. 
338  CFStringRef cfmsg = NULL;  
339  cfmsg = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, 
340                                               NULL,  // format options
341                                               (CFStringRef)fmt, 
342                                               args);
343  return GTMCFAutorelease(cfmsg);
344}
345
346@end  // GTMLogBasicFormatter
347
348
349@implementation GTMLogStandardFormatter
350
351- (id)init {
352  if ((self = [super init])) {
353    dateFormatter_ = [[NSDateFormatter alloc] init];
354    [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4];
355    [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
356    pname_ = [[[NSProcessInfo processInfo] processName] copy];
357    pid_ = [[NSProcessInfo processInfo] processIdentifier];
358  }
359  return self;
360}
361
362- (void)dealloc {
363  [dateFormatter_ release];
364  [pname_ release];
365  [super dealloc];
366}
367
368- (NSString *)stringForFunc:(NSString *)func
369                 withFormat:(NSString *)fmt
370                     valist:(va_list)args 
371                      level:(GTMLoggerLevel)level {
372  GTMLOGGER_ASSERT(dateFormatter_ != nil);
373  NSString *tstamp = nil;
374  @synchronized (dateFormatter_) {
375    tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
376  }
377  return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
378          tstamp, pname_, pid_, pthread_self(),
379          level, (func ? func : @"(no func)"),
380          [super stringForFunc:func withFormat:fmt valist:args level:level]];
381}
382
383@end  // GTMLogStandardFormatter
384
385
386@implementation GTMLogLevelFilter
387
388// Check the environment and the user preferences for the GTMVerboseLogging key
389// to see if verbose logging has been enabled. The environment variable will
390// override the defaults setting, so check the environment first.
391// COV_NF_START
392static BOOL IsVerboseLoggingEnabled(void) {
393  static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
394  static char *env = NULL;
395  if (env == NULL)
396    env = getenv([kVerboseLoggingKey UTF8String]);
397  
398  if (env && env[0]) {
399    return (strtol(env, NULL, 10) != 0);
400  }
401
402  return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
403}
404// COV_NF_END
405
406// In DEBUG builds, log everything. If we're not in a debug build we'll assume
407// that we're in a Release build.
408- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
409#if DEBUG
410  return YES;
411#endif
412    
413  BOOL allow = YES;
414  
415  switch (level) {
416    case kGTMLoggerLevelDebug:
417      allow = NO;
418      break;
419    case kGTMLoggerLevelInfo:
420      allow = (IsVerboseLoggingEnabled() == YES);
421      break;
422    case kGTMLoggerLevelError:
423      allow = YES;
424      break;
425    case kGTMLoggerLevelAssert:
426      allow = YES;
427      break;
428    default:
429      allow = YES;
430      break;
431  }
432
433  return allow;
434}
435
436@end  // GTMLogLevelFilter
437
438
439@implementation GTMLogNoFilter
440
441- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
442  return YES;  // Allow everything through
443}
444
445@end  // GTMLogNoFilter