| // |
| // GTMLogger+ASL.m |
| // |
| // Copyright 2007-2008 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy |
| // of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| // |
| |
| #import "GTMLogger+ASL.h" |
| #import "GTMDefines.h" |
| |
| |
| @implementation GTMLogger (GTMLoggerASLAdditions) |
| |
| + (id)standardLoggerWithASL { |
| id me = [self standardLogger]; |
| [me setWriter:[[[GTMLogASLWriter alloc] init] autorelease]]; |
| [me setFormatter:[[[GTMLogASLFormatter alloc] init] autorelease]]; |
| return me; |
| } |
| |
| @end |
| |
| |
| @implementation GTMLogASLWriter |
| |
| + (id)aslWriter { |
| return [[[self alloc] initWithClientClass:nil facility:nil] autorelease]; |
| } |
| |
| + (id)aslWriterWithFacility:(NSString *)facility { |
| return [[[self alloc] initWithClientClass:nil facility:facility] autorelease]; |
| } |
| |
| - (id)init { |
| return [self initWithClientClass:nil facility:nil]; |
| } |
| |
| - (id)initWithClientClass:(Class)clientClass facility:(NSString *)facility { |
| if ((self = [super init])) { |
| aslClientClass_ = clientClass; |
| if (aslClientClass_ == nil) { |
| aslClientClass_ = [GTMLoggerASLClient class]; |
| } |
| facility_ = [facility copy]; |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| [facility_ release]; |
| [super dealloc]; |
| } |
| |
| - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { |
| // Because |facility_| is an argument to asl_open() we must store a separate |
| // one for each facility in thread-local storage. |
| static NSString *const kASLClientKey = @"GTMLoggerASLClient"; |
| NSString *key = kASLClientKey; |
| if (facility_) { |
| key = [NSString stringWithFormat:@"GTMLoggerASLClient-%@", facility_]; |
| } |
| |
| // Lookup the ASL client in the thread-local storage dictionary |
| NSMutableDictionary *tls = [[NSThread currentThread] threadDictionary]; |
| GTMLoggerASLClient *client = [tls objectForKey:key]; |
| |
| // If the ASL client wasn't found (e.g., the first call from this thread), |
| // then create it and store it in the thread-local storage dictionary |
| if (client == nil) { |
| client = [[[aslClientClass_ alloc] initWithFacility:facility_] autorelease]; |
| [tls setObject:client forKey:key]; |
| } |
| |
| // Map the GTMLoggerLevel level to an ASL level. |
| int aslLevel = ASL_LEVEL_INFO; |
| switch (level) { |
| case kGTMLoggerLevelUnknown: |
| case kGTMLoggerLevelDebug: |
| case kGTMLoggerLevelInfo: |
| aslLevel = ASL_LEVEL_NOTICE; |
| break; |
| case kGTMLoggerLevelError: |
| aslLevel = ASL_LEVEL_ERR; |
| break; |
| case kGTMLoggerLevelAssert: |
| aslLevel = ASL_LEVEL_ALERT; |
| break; |
| } |
| |
| [client log:msg level:aslLevel]; |
| } |
| |
| @end // GTMLogASLWriter |
| |
| |
| @implementation GTMLogASLFormatter |
| |
| #if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) |
| // Some versions of GCC (4.2 and below AFAIK) aren't great about supporting |
| // -Wmissing-format-attribute |
| // when the function is anything more complex than foo(NSString *fmt, ...). |
| // You see the error inside the function when you turn ... into va_args and |
| // attempt to call another function (like vsprintf for example). |
| // So we just shut off the warning for this function. |
| #pragma GCC diagnostic ignored "-Wmissing-format-attribute" |
| #endif // !__clang__ |
| |
| - (NSString *)stringForFunc:(NSString *)func |
| withFormat:(NSString *)fmt |
| valist:(va_list)args |
| level:(GTMLoggerLevel)level { |
| return [NSString stringWithFormat:@"%@ %@", |
| [self prettyNameForFunc:func], |
| // |super| has guard for nil |fmt| and |args| |
| [super stringForFunc:func withFormat:fmt valist:args level:level]]; |
| } |
| |
| #if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) |
| #pragma GCC diagnostic error "-Wmissing-format-attribute" |
| #endif // !__clang__ |
| |
| @end // GTMLogASLFormatter |
| |
| |
| @implementation GTMLoggerASLClient |
| |
| - (id)init { |
| return [self initWithFacility:nil]; |
| } |
| |
| - (id)initWithFacility:(NSString *)facility { |
| if ((self = [super init])) { |
| client_ = asl_open(NULL, [facility UTF8String], 0); |
| if (client_ == NULL) { |
| // COV_NF_START - no real way to test this |
| [self release]; |
| return nil; |
| // COV_NF_END |
| } |
| #if TARGET_OS_IPHONE |
| // On iOS we need to flag the messages as available for read so |
| // asl_search() can see our own output. |
| msgOptions_ = asl_new(ASL_TYPE_MSG); |
| if ((msgOptions_ == NULL) || |
| (asl_set(msgOptions_, |
| ASL_KEY_READ_UID, |
| [[NSString stringWithFormat:@"%d", getuid()] UTF8String]) != 0)) { |
| // COV_NF_START - no real way to test this |
| [self release]; |
| return nil; |
| // COV_NF_END |
| } |
| #endif |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| if (msgOptions_ != NULL) asl_free(msgOptions_); |
| if (client_ != NULL) asl_close(client_); |
| [super dealloc]; |
| } |
| |
| // We don't test this one line because we don't want to pollute actual system |
| // logs with test messages. |
| // COV_NF_START |
| - (void)log:(NSString *)msg level:(int)level { |
| asl_log(client_, msgOptions_, level, "%s", [msg UTF8String]); |
| } |
| // COV_NF_END |
| |
| @end // GTMLoggerASLClient |