|  | // Software License Agreement (BSD License) | 
|  | // | 
|  | // Copyright (c) 2010-2015, Deusty, LLC | 
|  | // All rights reserved. | 
|  | // | 
|  | // Redistribution and use of this software in source and binary forms, | 
|  | // with or without modification, are permitted provided that the following conditions are met: | 
|  | // | 
|  | // * Redistributions of source code must retain the above copyright notice, | 
|  | //   this list of conditions and the following disclaimer. | 
|  | // | 
|  | // * Neither the name of Deusty nor the names of its contributors may be used | 
|  | //   to endorse or promote products derived from this software without specific | 
|  | //   prior written permission of Deusty, LLC. | 
|  |  | 
|  | #import "DDASLLogger.h" | 
|  | #import <asl.h> | 
|  |  | 
|  | #if !__has_feature(objc_arc) | 
|  | #error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). | 
|  | #endif | 
|  |  | 
|  | const char* const kDDASLKeyDDLog = "DDLog"; | 
|  |  | 
|  | const char* const kDDASLDDLogValue = "1"; | 
|  |  | 
|  | static DDASLLogger *sharedInstance; | 
|  |  | 
|  | @interface DDASLLogger () { | 
|  | aslclient _client; | 
|  | } | 
|  |  | 
|  | @end | 
|  |  | 
|  |  | 
|  | @implementation DDASLLogger | 
|  |  | 
|  | + (instancetype)sharedInstance { | 
|  | static dispatch_once_t DDASLLoggerOnceToken; | 
|  |  | 
|  | dispatch_once(&DDASLLoggerOnceToken, ^{ | 
|  | sharedInstance = [[[self class] alloc] init]; | 
|  | }); | 
|  |  | 
|  | return sharedInstance; | 
|  | } | 
|  |  | 
|  | - (instancetype)init { | 
|  | if (sharedInstance != nil) { | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | if ((self = [super init])) { | 
|  | // A default asl client is provided for the main thread, | 
|  | // but background threads need to create their own client. | 
|  |  | 
|  | _client = asl_open(NULL, "com.apple.console", 0); | 
|  | } | 
|  |  | 
|  | return self; | 
|  | } | 
|  |  | 
|  | - (void)logMessage:(DDLogMessage *)logMessage { | 
|  | // Skip captured log messages | 
|  | if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message; | 
|  |  | 
|  | if (message) { | 
|  | const char *msg = [message UTF8String]; | 
|  |  | 
|  | size_t aslLogLevel; | 
|  | switch (logMessage->_flag) { | 
|  | // Note: By default ASL will filter anything above level 5 (Notice). | 
|  | // So our mappings shouldn't go above that level. | 
|  | case DDLogFlagError     : aslLogLevel = ASL_LEVEL_CRIT;     break; | 
|  | case DDLogFlagWarning   : aslLogLevel = ASL_LEVEL_ERR;      break; | 
|  | case DDLogFlagInfo      : aslLogLevel = ASL_LEVEL_WARNING;  break; // Regular NSLog's level | 
|  | case DDLogFlagDebug     : | 
|  | case DDLogFlagVerbose   : | 
|  | default                 : aslLogLevel = ASL_LEVEL_NOTICE;   break; | 
|  | } | 
|  |  | 
|  | static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" }; | 
|  |  | 
|  | // NSLog uses the current euid to set the ASL_KEY_READ_UID. | 
|  | uid_t const readUID = geteuid(); | 
|  |  | 
|  | char readUIDString[16]; | 
|  | #ifndef NS_BLOCK_ASSERTIONS | 
|  | int l = snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); | 
|  | #else | 
|  | snprintf(readUIDString, sizeof(readUIDString), "%d", readUID); | 
|  | #endif | 
|  |  | 
|  | NSAssert(l < sizeof(readUIDString), | 
|  | @"Formatted euid is too long."); | 
|  | NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])), | 
|  | @"Unhandled ASL log level."); | 
|  |  | 
|  | aslmsg m = asl_new(ASL_TYPE_MSG); | 
|  | if (m != NULL) { | 
|  | if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 && | 
|  | asl_set(m, ASL_KEY_MSG, msg) == 0 && | 
|  | asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 && | 
|  | asl_set(m, kDDASLKeyDDLog, kDDASLDDLogValue) == 0) { | 
|  | asl_send(_client, m); | 
|  | } | 
|  | asl_free(m); | 
|  | } | 
|  | //TODO handle asl_* failures non-silently? | 
|  | } | 
|  | } | 
|  |  | 
|  | - (NSString *)loggerName { | 
|  | return @"cocoa.lumberjack.aslLogger"; | 
|  | } | 
|  |  | 
|  | @end |