1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,612 @@ 1.4 +// 1.5 +// GTMLogger.m 1.6 +// 1.7 +// Copyright 2007-2008 Google Inc. 1.8 +// 1.9 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not 1.10 +// use this file except in compliance with the License. You may obtain a copy 1.11 +// of the License at 1.12 +// 1.13 +// http://www.apache.org/licenses/LICENSE-2.0 1.14 +// 1.15 +// Unless required by applicable law or agreed to in writing, software 1.16 +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 1.17 +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 1.18 +// License for the specific language governing permissions and limitations under 1.19 +// the License. 1.20 +// 1.21 + 1.22 +#import "GTMLogger.h" 1.23 +#import "GTMGarbageCollection.h" 1.24 +#import <fcntl.h> 1.25 +#import <unistd.h> 1.26 +#import <stdlib.h> 1.27 +#import <pthread.h> 1.28 + 1.29 + 1.30 +#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) 1.31 +// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting 1.32 +// -Wmissing-format-attribute 1.33 +// when the function is anything more complex than foo(NSString *fmt, ...). 1.34 +// You see the error inside the function when you turn ... into va_args and 1.35 +// attempt to call another function (like vsprintf for example). 1.36 +// So we just shut off the warning for this file. We reenable it at the end. 1.37 +#pragma GCC diagnostic ignored "-Wmissing-format-attribute" 1.38 +#endif // !__clang__ 1.39 + 1.40 +// Reference to the shared GTMLogger instance. This is not a singleton, it's 1.41 +// just an easy reference to one shared instance. 1.42 +static GTMLogger *gSharedLogger = nil; 1.43 + 1.44 + 1.45 +@implementation GTMLogger 1.46 + 1.47 +// Returns a pointer to the shared logger instance. If none exists, a standard 1.48 +// logger is created and returned. 1.49 ++ (id)sharedLogger { 1.50 + @synchronized(self) { 1.51 + if (gSharedLogger == nil) { 1.52 + gSharedLogger = [[self standardLogger] retain]; 1.53 + } 1.54 + } 1.55 + return [[gSharedLogger retain] autorelease]; 1.56 +} 1.57 + 1.58 ++ (void)setSharedLogger:(GTMLogger *)logger { 1.59 + @synchronized(self) { 1.60 + [gSharedLogger autorelease]; 1.61 + gSharedLogger = [logger retain]; 1.62 + } 1.63 +} 1.64 + 1.65 ++ (id)standardLogger { 1.66 + // Don't trust NSFileHandle not to throw 1.67 + @try { 1.68 + id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput]; 1.69 + id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] 1.70 + autorelease]; 1.71 + id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease]; 1.72 + return [[[self alloc] initWithWriter:writer 1.73 + formatter:fr 1.74 + filter:filter] autorelease]; 1.75 + } 1.76 + @catch (id e) { 1.77 + // Ignored 1.78 + } 1.79 + return nil; 1.80 +} 1.81 + 1.82 ++ (id)standardLoggerWithStderr { 1.83 + // Don't trust NSFileHandle not to throw 1.84 + @try { 1.85 + id me = [self standardLogger]; 1.86 + [me setWriter:[NSFileHandle fileHandleWithStandardError]]; 1.87 + return me; 1.88 + } 1.89 + @catch (id e) { 1.90 + // Ignored 1.91 + } 1.92 + return nil; 1.93 +} 1.94 + 1.95 ++ (id)standardLoggerWithStdoutAndStderr { 1.96 + // We're going to take advantage of the GTMLogger to GTMLogWriter adaptor 1.97 + // and create a composite logger that an outer "standard" logger can use 1.98 + // as a writer. Our inner loggers should apply no formatting since the main 1.99 + // logger does that and we want the caller to be able to change formatters 1.100 + // or add writers without knowing the inner structure of our composite. 1.101 + 1.102 + // Don't trust NSFileHandle not to throw 1.103 + @try { 1.104 + GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init] 1.105 + autorelease]; 1.106 + GTMLogger *stdoutLogger = 1.107 + [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput] 1.108 + formatter:formatter 1.109 + filter:[[[GTMLogMaximumLevelFilter alloc] 1.110 + initWithMaximumLevel:kGTMLoggerLevelInfo] 1.111 + autorelease]]; 1.112 + GTMLogger *stderrLogger = 1.113 + [self loggerWithWriter:[NSFileHandle fileHandleWithStandardError] 1.114 + formatter:formatter 1.115 + filter:[[[GTMLogMininumLevelFilter alloc] 1.116 + initWithMinimumLevel:kGTMLoggerLevelError] 1.117 + autorelease]]; 1.118 + GTMLogger *compositeWriter = 1.119 + [self loggerWithWriter:[NSArray arrayWithObjects: 1.120 + stdoutLogger, stderrLogger, nil] 1.121 + formatter:formatter 1.122 + filter:[[[GTMLogNoFilter alloc] init] autorelease]]; 1.123 + GTMLogger *outerLogger = [self standardLogger]; 1.124 + [outerLogger setWriter:compositeWriter]; 1.125 + return outerLogger; 1.126 + } 1.127 + @catch (id e) { 1.128 + // Ignored 1.129 + } 1.130 + return nil; 1.131 +} 1.132 + 1.133 ++ (id)standardLoggerWithPath:(NSString *)path { 1.134 + @try { 1.135 + NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644]; 1.136 + if (fh == nil) return nil; 1.137 + id me = [self standardLogger]; 1.138 + [me setWriter:fh]; 1.139 + return me; 1.140 + } 1.141 + @catch (id e) { 1.142 + // Ignored 1.143 + } 1.144 + return nil; 1.145 +} 1.146 + 1.147 ++ (id)loggerWithWriter:(id<GTMLogWriter>)writer 1.148 + formatter:(id<GTMLogFormatter>)formatter 1.149 + filter:(id<GTMLogFilter>)filter { 1.150 + return [[[self alloc] initWithWriter:writer 1.151 + formatter:formatter 1.152 + filter:filter] autorelease]; 1.153 +} 1.154 + 1.155 ++ (id)logger { 1.156 + return [[[self alloc] init] autorelease]; 1.157 +} 1.158 + 1.159 +- (id)init { 1.160 + return [self initWithWriter:nil formatter:nil filter:nil]; 1.161 +} 1.162 + 1.163 +- (id)initWithWriter:(id<GTMLogWriter>)writer 1.164 + formatter:(id<GTMLogFormatter>)formatter 1.165 + filter:(id<GTMLogFilter>)filter { 1.166 + if ((self = [super init])) { 1.167 + [self setWriter:writer]; 1.168 + [self setFormatter:formatter]; 1.169 + [self setFilter:filter]; 1.170 + } 1.171 + return self; 1.172 +} 1.173 + 1.174 +- (void)dealloc { 1.175 + // Unlikely, but |writer_| may be an NSFileHandle, which can throw 1.176 + @try { 1.177 + [formatter_ release]; 1.178 + [filter_ release]; 1.179 + [writer_ release]; 1.180 + } 1.181 + @catch (id e) { 1.182 + // Ignored 1.183 + } 1.184 + [super dealloc]; 1.185 +} 1.186 + 1.187 +- (id<GTMLogWriter>)writer { 1.188 + return [[writer_ retain] autorelease]; 1.189 +} 1.190 + 1.191 +- (void)setWriter:(id<GTMLogWriter>)writer { 1.192 + @synchronized(self) { 1.193 + [writer_ autorelease]; 1.194 + writer_ = nil; 1.195 + if (writer == nil) { 1.196 + // Try to use stdout, but don't trust NSFileHandle 1.197 + @try { 1.198 + writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain]; 1.199 + } 1.200 + @catch (id e) { 1.201 + // Leave |writer_| nil 1.202 + } 1.203 + } else { 1.204 + writer_ = [writer retain]; 1.205 + } 1.206 + } 1.207 +} 1.208 + 1.209 +- (id<GTMLogFormatter>)formatter { 1.210 + return [[formatter_ retain] autorelease]; 1.211 +} 1.212 + 1.213 +- (void)setFormatter:(id<GTMLogFormatter>)formatter { 1.214 + @synchronized(self) { 1.215 + [formatter_ autorelease]; 1.216 + formatter_ = nil; 1.217 + if (formatter == nil) { 1.218 + @try { 1.219 + formatter_ = [[GTMLogBasicFormatter alloc] init]; 1.220 + } 1.221 + @catch (id e) { 1.222 + // Leave |formatter_| nil 1.223 + } 1.224 + } else { 1.225 + formatter_ = [formatter retain]; 1.226 + } 1.227 + } 1.228 +} 1.229 + 1.230 +- (id<GTMLogFilter>)filter { 1.231 + return [[filter_ retain] autorelease]; 1.232 +} 1.233 + 1.234 +- (void)setFilter:(id<GTMLogFilter>)filter { 1.235 + @synchronized(self) { 1.236 + [filter_ autorelease]; 1.237 + filter_ = nil; 1.238 + if (filter == nil) { 1.239 + @try { 1.240 + filter_ = [[GTMLogNoFilter alloc] init]; 1.241 + } 1.242 + @catch (id e) { 1.243 + // Leave |filter_| nil 1.244 + } 1.245 + } else { 1.246 + filter_ = [filter retain]; 1.247 + } 1.248 + } 1.249 +} 1.250 + 1.251 +- (void)logDebug:(NSString *)fmt, ... { 1.252 + va_list args; 1.253 + va_start(args, fmt); 1.254 + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug]; 1.255 + va_end(args); 1.256 +} 1.257 + 1.258 +- (void)logInfo:(NSString *)fmt, ... { 1.259 + va_list args; 1.260 + va_start(args, fmt); 1.261 + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo]; 1.262 + va_end(args); 1.263 +} 1.264 + 1.265 +- (void)logError:(NSString *)fmt, ... { 1.266 + va_list args; 1.267 + va_start(args, fmt); 1.268 + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError]; 1.269 + va_end(args); 1.270 +} 1.271 + 1.272 +- (void)logAssert:(NSString *)fmt, ... { 1.273 + va_list args; 1.274 + va_start(args, fmt); 1.275 + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert]; 1.276 + va_end(args); 1.277 +} 1.278 + 1.279 +@end // GTMLogger 1.280 + 1.281 +@implementation GTMLogger (GTMLoggerMacroHelpers) 1.282 + 1.283 +- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... { 1.284 + va_list args; 1.285 + va_start(args, fmt); 1.286 + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug]; 1.287 + va_end(args); 1.288 +} 1.289 + 1.290 +- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... { 1.291 + va_list args; 1.292 + va_start(args, fmt); 1.293 + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo]; 1.294 + va_end(args); 1.295 +} 1.296 + 1.297 +- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... { 1.298 + va_list args; 1.299 + va_start(args, fmt); 1.300 + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError]; 1.301 + va_end(args); 1.302 +} 1.303 + 1.304 +- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... { 1.305 + va_list args; 1.306 + va_start(args, fmt); 1.307 + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert]; 1.308 + va_end(args); 1.309 +} 1.310 + 1.311 +@end // GTMLoggerMacroHelpers 1.312 + 1.313 +@implementation GTMLogger (PrivateMethods) 1.314 + 1.315 +- (void)logInternalFunc:(const char *)func 1.316 + format:(NSString *)fmt 1.317 + valist:(va_list)args 1.318 + level:(GTMLoggerLevel)level { 1.319 + // Primary point where logging happens, logging should never throw, catch 1.320 + // everything. 1.321 + @try { 1.322 + NSString *fname = func ? [NSString stringWithUTF8String:func] : nil; 1.323 + NSString *msg = [formatter_ stringForFunc:fname 1.324 + withFormat:fmt 1.325 + valist:args 1.326 + level:level]; 1.327 + if (msg && [filter_ filterAllowsMessage:msg level:level]) 1.328 + [writer_ logMessage:msg level:level]; 1.329 + } 1.330 + @catch (id e) { 1.331 + // Ignored 1.332 + } 1.333 +} 1.334 + 1.335 +@end // PrivateMethods 1.336 + 1.337 + 1.338 +@implementation NSFileHandle (GTMFileHandleLogWriter) 1.339 + 1.340 ++ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode { 1.341 + int fd = -1; 1.342 + if (path) { 1.343 + int flags = O_WRONLY | O_APPEND | O_CREAT; 1.344 + fd = open([path fileSystemRepresentation], flags, mode); 1.345 + } 1.346 + if (fd == -1) return nil; 1.347 + return [[[self alloc] initWithFileDescriptor:fd 1.348 + closeOnDealloc:YES] autorelease]; 1.349 +} 1.350 + 1.351 +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { 1.352 + @synchronized(self) { 1.353 + // Closed pipes should not generate exceptions in our caller. Catch here 1.354 + // as well [GTMLogger logInternalFunc:...] so that an exception in this 1.355 + // writer does not prevent other writers from having a chance. 1.356 + @try { 1.357 + NSString *line = [NSString stringWithFormat:@"%@\n", msg]; 1.358 + [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]]; 1.359 + } 1.360 + @catch (id e) { 1.361 + // Ignored 1.362 + } 1.363 + } 1.364 +} 1.365 + 1.366 +@end // GTMFileHandleLogWriter 1.367 + 1.368 + 1.369 +@implementation NSArray (GTMArrayCompositeLogWriter) 1.370 + 1.371 +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { 1.372 + @synchronized(self) { 1.373 + id<GTMLogWriter> child = nil; 1.374 + GTM_FOREACH_OBJECT(child, self) { 1.375 + if ([child conformsToProtocol:@protocol(GTMLogWriter)]) 1.376 + [child logMessage:msg level:level]; 1.377 + } 1.378 + } 1.379 +} 1.380 + 1.381 +@end // GTMArrayCompositeLogWriter 1.382 + 1.383 + 1.384 +@implementation GTMLogger (GTMLoggerLogWriter) 1.385 + 1.386 +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { 1.387 + switch (level) { 1.388 + case kGTMLoggerLevelDebug: 1.389 + [self logDebug:@"%@", msg]; 1.390 + break; 1.391 + case kGTMLoggerLevelInfo: 1.392 + [self logInfo:@"%@", msg]; 1.393 + break; 1.394 + case kGTMLoggerLevelError: 1.395 + [self logError:@"%@", msg]; 1.396 + break; 1.397 + case kGTMLoggerLevelAssert: 1.398 + [self logAssert:@"%@", msg]; 1.399 + break; 1.400 + default: 1.401 + // Ignore the message. 1.402 + break; 1.403 + } 1.404 +} 1.405 + 1.406 +@end // GTMLoggerLogWriter 1.407 + 1.408 + 1.409 +@implementation GTMLogBasicFormatter 1.410 + 1.411 +- (NSString *)prettyNameForFunc:(NSString *)func { 1.412 + NSString *name = [func stringByTrimmingCharactersInSet: 1.413 + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; 1.414 + NSString *function = @"(unknown)"; 1.415 + if ([name length]) { 1.416 + if (// Objective C __func__ and __PRETTY_FUNCTION__ 1.417 + [name hasPrefix:@"-["] || [name hasPrefix:@"+["] || 1.418 + // C++ __PRETTY_FUNCTION__ and other preadorned formats 1.419 + [name hasSuffix:@")"]) { 1.420 + function = name; 1.421 + } else { 1.422 + // Assume C99 __func__ 1.423 + function = [NSString stringWithFormat:@"%@()", name]; 1.424 + } 1.425 + } 1.426 + return function; 1.427 +} 1.428 + 1.429 +- (NSString *)stringForFunc:(NSString *)func 1.430 + withFormat:(NSString *)fmt 1.431 + valist:(va_list)args 1.432 + level:(GTMLoggerLevel)level { 1.433 + // Performance note: We may want to do a quick check here to see if |fmt| 1.434 + // contains a '%', and if not, simply return 'fmt'. 1.435 + if (!(fmt && args)) return nil; 1.436 + return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease]; 1.437 +} 1.438 + 1.439 +@end // GTMLogBasicFormatter 1.440 + 1.441 + 1.442 +@implementation GTMLogStandardFormatter 1.443 + 1.444 +- (id)init { 1.445 + if ((self = [super init])) { 1.446 + dateFormatter_ = [[NSDateFormatter alloc] init]; 1.447 + [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4]; 1.448 + [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; 1.449 + pname_ = [[[NSProcessInfo processInfo] processName] copy]; 1.450 + pid_ = [[NSProcessInfo processInfo] processIdentifier]; 1.451 + if (!(dateFormatter_ && pname_)) { 1.452 + [self release]; 1.453 + return nil; 1.454 + } 1.455 + } 1.456 + return self; 1.457 +} 1.458 + 1.459 +- (void)dealloc { 1.460 + [dateFormatter_ release]; 1.461 + [pname_ release]; 1.462 + [super dealloc]; 1.463 +} 1.464 + 1.465 +- (NSString *)stringForFunc:(NSString *)func 1.466 + withFormat:(NSString *)fmt 1.467 + valist:(va_list)args 1.468 + level:(GTMLoggerLevel)level { 1.469 + NSString *tstamp = nil; 1.470 + @synchronized (dateFormatter_) { 1.471 + tstamp = [dateFormatter_ stringFromDate:[NSDate date]]; 1.472 + } 1.473 + return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@", 1.474 + tstamp, pname_, pid_, pthread_self(), 1.475 + level, [self prettyNameForFunc:func], 1.476 + // |super| has guard for nil |fmt| and |args| 1.477 + [super stringForFunc:func withFormat:fmt valist:args level:level]]; 1.478 +} 1.479 + 1.480 +@end // GTMLogStandardFormatter 1.481 + 1.482 + 1.483 +@implementation GTMLogLevelFilter 1.484 + 1.485 +// Check the environment and the user preferences for the GTMVerboseLogging key 1.486 +// to see if verbose logging has been enabled. The environment variable will 1.487 +// override the defaults setting, so check the environment first. 1.488 +// COV_NF_START 1.489 +static BOOL IsVerboseLoggingEnabled(void) { 1.490 + static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging"; 1.491 + NSString *value = [[[NSProcessInfo processInfo] environment] 1.492 + objectForKey:kVerboseLoggingKey]; 1.493 + if (value) { 1.494 + // Emulate [NSString boolValue] for pre-10.5 1.495 + value = [value stringByTrimmingCharactersInSet: 1.496 + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; 1.497 + if ([[value uppercaseString] hasPrefix:@"Y"] || 1.498 + [[value uppercaseString] hasPrefix:@"T"] || 1.499 + [value intValue]) { 1.500 + return YES; 1.501 + } else { 1.502 + return NO; 1.503 + } 1.504 + } 1.505 + return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey]; 1.506 +} 1.507 +// COV_NF_END 1.508 + 1.509 +// In DEBUG builds, log everything. If we're not in a debug build we'll assume 1.510 +// that we're in a Release build. 1.511 +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { 1.512 +#if DEBUG 1.513 + return YES; 1.514 +#endif 1.515 + 1.516 + BOOL allow = YES; 1.517 + 1.518 + switch (level) { 1.519 + case kGTMLoggerLevelDebug: 1.520 + allow = NO; 1.521 + break; 1.522 + case kGTMLoggerLevelInfo: 1.523 + allow = IsVerboseLoggingEnabled(); 1.524 + break; 1.525 + case kGTMLoggerLevelError: 1.526 + allow = YES; 1.527 + break; 1.528 + case kGTMLoggerLevelAssert: 1.529 + allow = YES; 1.530 + break; 1.531 + default: 1.532 + allow = YES; 1.533 + break; 1.534 + } 1.535 + 1.536 + return allow; 1.537 +} 1.538 + 1.539 +@end // GTMLogLevelFilter 1.540 + 1.541 + 1.542 +@implementation GTMLogNoFilter 1.543 + 1.544 +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { 1.545 + return YES; // Allow everything through 1.546 +} 1.547 + 1.548 +@end // GTMLogNoFilter 1.549 + 1.550 + 1.551 +@implementation GTMLogAllowedLevelFilter 1.552 + 1.553 +// Private designated initializer 1.554 +- (id)initWithAllowedLevels:(NSIndexSet *)levels { 1.555 + self = [super init]; 1.556 + if (self != nil) { 1.557 + allowedLevels_ = [levels retain]; 1.558 + // Cap min/max level 1.559 + if (!allowedLevels_ || 1.560 + // NSIndexSet is unsigned so only check the high bound, but need to 1.561 + // check both first and last index because NSIndexSet appears to allow 1.562 + // wraparound. 1.563 + ([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) || 1.564 + ([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) { 1.565 + [self release]; 1.566 + return nil; 1.567 + } 1.568 + } 1.569 + return self; 1.570 +} 1.571 + 1.572 +- (id)init { 1.573 + // Allow all levels in default init 1.574 + return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: 1.575 + NSMakeRange(kGTMLoggerLevelUnknown, 1.576 + (kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]]; 1.577 +} 1.578 + 1.579 +- (void)dealloc { 1.580 + [allowedLevels_ release]; 1.581 + [super dealloc]; 1.582 +} 1.583 + 1.584 +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { 1.585 + return [allowedLevels_ containsIndex:level]; 1.586 +} 1.587 + 1.588 +@end // GTMLogAllowedLevelFilter 1.589 + 1.590 + 1.591 +@implementation GTMLogMininumLevelFilter 1.592 + 1.593 +- (id)initWithMinimumLevel:(GTMLoggerLevel)level { 1.594 + return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: 1.595 + NSMakeRange(level, 1.596 + (kGTMLoggerLevelAssert - level + 1))]]; 1.597 +} 1.598 + 1.599 +@end // GTMLogMininumLevelFilter 1.600 + 1.601 + 1.602 +@implementation GTMLogMaximumLevelFilter 1.603 + 1.604 +- (id)initWithMaximumLevel:(GTMLoggerLevel)level { 1.605 + return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: 1.606 + NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]]; 1.607 +} 1.608 + 1.609 +@end // GTMLogMaximumLevelFilter 1.610 + 1.611 +#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) 1.612 +// See comment at top of file. 1.613 +#pragma GCC diagnostic error "-Wmissing-format-attribute" 1.614 +#endif // !__clang__ 1.615 +