toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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 //
    19 #import "GTMLogger.h"
    20 #import "GTMGarbageCollection.h"
    21 #import <fcntl.h>
    22 #import <unistd.h>
    23 #import <stdlib.h>
    24 #import <pthread.h>
    27 #if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
    28 // Some versions of GCC (4.2 and below AFAIK) aren't great about supporting
    29 // -Wmissing-format-attribute
    30 // when the function is anything more complex than foo(NSString *fmt, ...).
    31 // You see the error inside the function when you turn ... into va_args and
    32 // attempt to call another function (like vsprintf for example).
    33 // So we just shut off the warning for this file. We reenable it at the end.
    34 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
    35 #endif  // !__clang__
    37 // Reference to the shared GTMLogger instance. This is not a singleton, it's
    38 // just an easy reference to one shared instance.
    39 static GTMLogger *gSharedLogger = nil;
    42 @implementation GTMLogger
    44 // Returns a pointer to the shared logger instance. If none exists, a standard
    45 // logger is created and returned.
    46 + (id)sharedLogger {
    47   @synchronized(self) {
    48     if (gSharedLogger == nil) {
    49       gSharedLogger = [[self standardLogger] retain];
    50     }
    51   }
    52   return [[gSharedLogger retain] autorelease];
    53 }
    55 + (void)setSharedLogger:(GTMLogger *)logger {
    56   @synchronized(self) {
    57     [gSharedLogger autorelease];
    58     gSharedLogger = [logger retain];
    59   }
    60 }
    62 + (id)standardLogger {
    63   // Don't trust NSFileHandle not to throw
    64   @try {
    65     id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
    66     id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init]
    67                                  autorelease];
    68     id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
    69     return [[[self alloc] initWithWriter:writer
    70                                formatter:fr
    71                                   filter:filter] autorelease];
    72   }
    73   @catch (id e) {
    74     // Ignored
    75   }
    76   return nil;
    77 }
    79 + (id)standardLoggerWithStderr {
    80   // Don't trust NSFileHandle not to throw
    81   @try {
    82     id me = [self standardLogger];
    83     [me setWriter:[NSFileHandle fileHandleWithStandardError]];
    84     return me;
    85   }
    86   @catch (id e) {
    87     // Ignored
    88   }
    89   return nil;
    90 }
    92 + (id)standardLoggerWithStdoutAndStderr {
    93   // We're going to take advantage of the GTMLogger to GTMLogWriter adaptor
    94   // and create a composite logger that an outer "standard" logger can use
    95   // as a writer. Our inner loggers should apply no formatting since the main
    96   // logger does that and we want the caller to be able to change formatters
    97   // or add writers without knowing the inner structure of our composite.
    99   // Don't trust NSFileHandle not to throw
   100   @try {
   101     GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init] 
   102                                           autorelease];
   103     GTMLogger *stdoutLogger =
   104         [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput]
   105                      formatter:formatter
   106                         filter:[[[GTMLogMaximumLevelFilter alloc]
   107                                   initWithMaximumLevel:kGTMLoggerLevelInfo]
   108                                       autorelease]];
   109     GTMLogger *stderrLogger =
   110         [self loggerWithWriter:[NSFileHandle fileHandleWithStandardError]
   111                      formatter:formatter
   112                         filter:[[[GTMLogMininumLevelFilter alloc]
   113                                   initWithMinimumLevel:kGTMLoggerLevelError]
   114                                       autorelease]];
   115     GTMLogger *compositeWriter =
   116         [self loggerWithWriter:[NSArray arrayWithObjects:
   117                                    stdoutLogger, stderrLogger, nil]
   118                      formatter:formatter
   119                         filter:[[[GTMLogNoFilter alloc] init] autorelease]];
   120     GTMLogger *outerLogger = [self standardLogger];
   121     [outerLogger setWriter:compositeWriter];
   122     return outerLogger;
   123   }
   124   @catch (id e) {
   125     // Ignored
   126   }
   127   return nil;
   128 }
   130 + (id)standardLoggerWithPath:(NSString *)path {
   131   @try {
   132     NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
   133     if (fh == nil) return nil;
   134     id me = [self standardLogger];
   135     [me setWriter:fh];
   136     return me;
   137   }
   138   @catch (id e) {
   139     // Ignored
   140   }
   141   return nil;
   142 }
   144 + (id)loggerWithWriter:(id<GTMLogWriter>)writer
   145              formatter:(id<GTMLogFormatter>)formatter
   146                 filter:(id<GTMLogFilter>)filter {
   147   return [[[self alloc] initWithWriter:writer
   148                              formatter:formatter
   149                                 filter:filter] autorelease];
   150 }
   152 + (id)logger {
   153   return [[[self alloc] init] autorelease];
   154 }
   156 - (id)init {
   157   return [self initWithWriter:nil formatter:nil filter:nil];
   158 }
   160 - (id)initWithWriter:(id<GTMLogWriter>)writer
   161            formatter:(id<GTMLogFormatter>)formatter
   162               filter:(id<GTMLogFilter>)filter {
   163   if ((self = [super init])) {
   164     [self setWriter:writer];
   165     [self setFormatter:formatter];
   166     [self setFilter:filter];
   167   }
   168   return self;
   169 }
   171 - (void)dealloc {
   172   // Unlikely, but |writer_| may be an NSFileHandle, which can throw
   173   @try {
   174     [formatter_ release];
   175     [filter_ release];
   176     [writer_ release];
   177   }
   178   @catch (id e) {
   179     // Ignored
   180   }
   181   [super dealloc];
   182 }
   184 - (id<GTMLogWriter>)writer {
   185   return [[writer_ retain] autorelease];
   186 }
   188 - (void)setWriter:(id<GTMLogWriter>)writer {
   189   @synchronized(self) {
   190     [writer_ autorelease];
   191     writer_ = nil;
   192     if (writer == nil) {
   193       // Try to use stdout, but don't trust NSFileHandle
   194       @try {
   195         writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
   196       }
   197       @catch (id e) {
   198         // Leave |writer_| nil
   199       }
   200     } else {
   201       writer_ = [writer retain];
   202     }
   203   }
   204 }
   206 - (id<GTMLogFormatter>)formatter {
   207   return [[formatter_ retain] autorelease];
   208 }
   210 - (void)setFormatter:(id<GTMLogFormatter>)formatter {
   211   @synchronized(self) {
   212     [formatter_ autorelease];
   213     formatter_ = nil;
   214     if (formatter == nil) {
   215       @try {
   216         formatter_ = [[GTMLogBasicFormatter alloc] init];
   217       }
   218       @catch (id e) {
   219         // Leave |formatter_| nil
   220       }
   221     } else {
   222       formatter_ = [formatter retain];
   223     }
   224   }
   225 }
   227 - (id<GTMLogFilter>)filter {
   228   return [[filter_ retain] autorelease];
   229 }
   231 - (void)setFilter:(id<GTMLogFilter>)filter {
   232   @synchronized(self) {
   233     [filter_ autorelease];
   234     filter_ = nil;
   235     if (filter == nil) {
   236       @try {
   237         filter_ = [[GTMLogNoFilter alloc] init];
   238       }
   239       @catch (id e) {
   240         // Leave |filter_| nil
   241       }
   242     } else {
   243       filter_ = [filter retain];
   244     }
   245   }
   246 }
   248 - (void)logDebug:(NSString *)fmt, ... {
   249   va_list args;
   250   va_start(args, fmt);
   251   [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug];
   252   va_end(args);
   253 }
   255 - (void)logInfo:(NSString *)fmt, ... {
   256   va_list args;
   257   va_start(args, fmt);
   258   [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo];
   259   va_end(args);
   260 }
   262 - (void)logError:(NSString *)fmt, ... {
   263   va_list args;
   264   va_start(args, fmt);
   265   [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError];
   266   va_end(args);
   267 }
   269 - (void)logAssert:(NSString *)fmt, ... {
   270   va_list args;
   271   va_start(args, fmt);
   272   [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert];
   273   va_end(args);
   274 }
   276 @end  // GTMLogger
   278 @implementation GTMLogger (GTMLoggerMacroHelpers)
   280 - (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
   281   va_list args;
   282   va_start(args, fmt);
   283   [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug];
   284   va_end(args);
   285 }
   287 - (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... {
   288   va_list args;
   289   va_start(args, fmt);
   290   [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo];
   291   va_end(args);
   292 }
   294 - (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... {
   295   va_list args;
   296   va_start(args, fmt);
   297   [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError];
   298   va_end(args);
   299 }
   301 - (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... {
   302   va_list args;
   303   va_start(args, fmt);
   304   [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert];
   305   va_end(args);
   306 }
   308 @end  // GTMLoggerMacroHelpers
   310 @implementation GTMLogger (PrivateMethods)
   312 - (void)logInternalFunc:(const char *)func
   313                  format:(NSString *)fmt
   314                  valist:(va_list)args
   315                   level:(GTMLoggerLevel)level {
   316   // Primary point where logging happens, logging should never throw, catch
   317   // everything.
   318   @try {
   319     NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
   320     NSString *msg = [formatter_ stringForFunc:fname
   321                                    withFormat:fmt
   322                                        valist:args
   323                                         level:level];
   324     if (msg && [filter_ filterAllowsMessage:msg level:level])
   325       [writer_ logMessage:msg level:level];
   326   }
   327   @catch (id e) {
   328     // Ignored
   329   }
   330 }
   332 @end  // PrivateMethods
   335 @implementation NSFileHandle (GTMFileHandleLogWriter)
   337 + (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode {
   338   int fd = -1;
   339   if (path) {
   340     int flags = O_WRONLY | O_APPEND | O_CREAT;
   341     fd = open([path fileSystemRepresentation], flags, mode);
   342   }
   343   if (fd == -1) return nil;
   344   return [[[self alloc] initWithFileDescriptor:fd
   345                                 closeOnDealloc:YES] autorelease];
   346 }
   348 - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
   349   @synchronized(self) {
   350     // Closed pipes should not generate exceptions in our caller. Catch here
   351     // as well [GTMLogger logInternalFunc:...] so that an exception in this
   352     // writer does not prevent other writers from having a chance.
   353     @try {
   354       NSString *line = [NSString stringWithFormat:@"%@\n", msg];
   355       [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
   356     }
   357     @catch (id e) {
   358       // Ignored
   359     }
   360   }
   361 }
   363 @end  // GTMFileHandleLogWriter
   366 @implementation NSArray (GTMArrayCompositeLogWriter)
   368 - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
   369   @synchronized(self) {
   370     id<GTMLogWriter> child = nil;
   371     GTM_FOREACH_OBJECT(child, self) {
   372       if ([child conformsToProtocol:@protocol(GTMLogWriter)])
   373         [child logMessage:msg level:level];
   374     }
   375   }
   376 }
   378 @end  // GTMArrayCompositeLogWriter
   381 @implementation GTMLogger (GTMLoggerLogWriter)
   383 - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
   384   switch (level) {
   385     case kGTMLoggerLevelDebug:
   386       [self logDebug:@"%@", msg];
   387       break;
   388     case kGTMLoggerLevelInfo:
   389       [self logInfo:@"%@", msg];
   390       break;
   391     case kGTMLoggerLevelError:
   392       [self logError:@"%@", msg];
   393       break;
   394     case kGTMLoggerLevelAssert:
   395       [self logAssert:@"%@", msg];
   396       break;
   397     default:
   398       // Ignore the message.
   399       break;
   400   }
   401 }
   403 @end  // GTMLoggerLogWriter
   406 @implementation GTMLogBasicFormatter
   408 - (NSString *)prettyNameForFunc:(NSString *)func {
   409   NSString *name = [func stringByTrimmingCharactersInSet:
   410                      [NSCharacterSet whitespaceAndNewlineCharacterSet]];
   411   NSString *function = @"(unknown)";
   412   if ([name length]) {
   413     if (// Objective C __func__ and __PRETTY_FUNCTION__
   414         [name hasPrefix:@"-["] || [name hasPrefix:@"+["] ||
   415         // C++ __PRETTY_FUNCTION__ and other preadorned formats
   416         [name hasSuffix:@")"]) {
   417       function = name;
   418     } else {
   419       // Assume C99 __func__
   420       function = [NSString stringWithFormat:@"%@()", name];
   421     }
   422   }
   423   return function;
   424 }
   426 - (NSString *)stringForFunc:(NSString *)func
   427                  withFormat:(NSString *)fmt
   428                      valist:(va_list)args
   429                       level:(GTMLoggerLevel)level {
   430   // Performance note: We may want to do a quick check here to see if |fmt|
   431   // contains a '%', and if not, simply return 'fmt'.
   432   if (!(fmt && args)) return nil;
   433   return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease];
   434 }
   436 @end  // GTMLogBasicFormatter
   439 @implementation GTMLogStandardFormatter
   441 - (id)init {
   442   if ((self = [super init])) {
   443     dateFormatter_ = [[NSDateFormatter alloc] init];
   444     [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4];
   445     [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
   446     pname_ = [[[NSProcessInfo processInfo] processName] copy];
   447     pid_ = [[NSProcessInfo processInfo] processIdentifier];
   448     if (!(dateFormatter_ && pname_)) {
   449       [self release];
   450       return nil;
   451     }
   452   }
   453   return self;
   454 }
   456 - (void)dealloc {
   457   [dateFormatter_ release];
   458   [pname_ release];
   459   [super dealloc];
   460 }
   462 - (NSString *)stringForFunc:(NSString *)func
   463                  withFormat:(NSString *)fmt
   464                      valist:(va_list)args
   465                       level:(GTMLoggerLevel)level {
   466   NSString *tstamp = nil;
   467   @synchronized (dateFormatter_) {
   468     tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
   469   }
   470   return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
   471            tstamp, pname_, pid_, pthread_self(),
   472            level, [self prettyNameForFunc:func],
   473            // |super| has guard for nil |fmt| and |args|
   474            [super stringForFunc:func withFormat:fmt valist:args level:level]];
   475 }
   477 @end  // GTMLogStandardFormatter
   480 @implementation GTMLogLevelFilter
   482 // Check the environment and the user preferences for the GTMVerboseLogging key
   483 // to see if verbose logging has been enabled. The environment variable will
   484 // override the defaults setting, so check the environment first.
   485 // COV_NF_START
   486 static BOOL IsVerboseLoggingEnabled(void) {
   487   static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
   488   NSString *value = [[[NSProcessInfo processInfo] environment]
   489                         objectForKey:kVerboseLoggingKey];
   490   if (value) {
   491     // Emulate [NSString boolValue] for pre-10.5
   492     value = [value stringByTrimmingCharactersInSet:
   493                 [NSCharacterSet whitespaceAndNewlineCharacterSet]];
   494     if ([[value uppercaseString] hasPrefix:@"Y"] ||
   495         [[value uppercaseString] hasPrefix:@"T"] ||
   496         [value intValue]) {
   497       return YES;
   498     } else {
   499       return NO;
   500     }
   501   }
   502   return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
   503 }
   504 // COV_NF_END
   506 // In DEBUG builds, log everything. If we're not in a debug build we'll assume
   507 // that we're in a Release build.
   508 - (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
   509 #if DEBUG
   510   return YES;
   511 #endif
   513   BOOL allow = YES;
   515   switch (level) {
   516     case kGTMLoggerLevelDebug:
   517       allow = NO;
   518       break;
   519     case kGTMLoggerLevelInfo:
   520       allow = IsVerboseLoggingEnabled();
   521       break;
   522     case kGTMLoggerLevelError:
   523       allow = YES;
   524       break;
   525     case kGTMLoggerLevelAssert:
   526       allow = YES;
   527       break;
   528     default:
   529       allow = YES;
   530       break;
   531   }
   533   return allow;
   534 }
   536 @end  // GTMLogLevelFilter
   539 @implementation GTMLogNoFilter
   541 - (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
   542   return YES;  // Allow everything through
   543 }
   545 @end  // GTMLogNoFilter
   548 @implementation GTMLogAllowedLevelFilter
   550 // Private designated initializer
   551 - (id)initWithAllowedLevels:(NSIndexSet *)levels {
   552   self = [super init];
   553   if (self != nil) {
   554     allowedLevels_ = [levels retain];
   555     // Cap min/max level
   556     if (!allowedLevels_ ||
   557         // NSIndexSet is unsigned so only check the high bound, but need to
   558         // check both first and last index because NSIndexSet appears to allow
   559         // wraparound.
   560         ([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) ||
   561         ([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) {
   562       [self release];
   563       return nil;
   564     }
   565   }
   566   return self;
   567 }
   569 - (id)init {
   570   // Allow all levels in default init
   571   return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
   572              NSMakeRange(kGTMLoggerLevelUnknown,
   573                  (kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]];
   574 }
   576 - (void)dealloc {
   577   [allowedLevels_ release];
   578   [super dealloc];
   579 }
   581 - (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
   582   return [allowedLevels_ containsIndex:level];
   583 }
   585 @end  // GTMLogAllowedLevelFilter
   588 @implementation GTMLogMininumLevelFilter
   590 - (id)initWithMinimumLevel:(GTMLoggerLevel)level {
   591   return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
   592              NSMakeRange(level,
   593                          (kGTMLoggerLevelAssert - level + 1))]];
   594 }
   596 @end  // GTMLogMininumLevelFilter
   599 @implementation GTMLogMaximumLevelFilter
   601 - (id)initWithMaximumLevel:(GTMLoggerLevel)level {
   602   return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
   603              NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]];
   604 }
   606 @end  // GTMLogMaximumLevelFilter
   608 #if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
   609 // See comment at top of file.
   610 #pragma GCC diagnostic error "-Wmissing-format-attribute"
   611 #endif  // !__clang__

mercurial