DDASLLogger.m 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Software License Agreement (BSD License)
  2. //
  3. // Copyright (c) 2010-2022, Deusty, LLC
  4. // All rights reserved.
  5. //
  6. // Redistribution and use of this software in source and binary forms,
  7. // with or without modification, are permitted provided that the following conditions are met:
  8. //
  9. // * Redistributions of source code must retain the above copyright notice,
  10. // this list of conditions and the following disclaimer.
  11. //
  12. // * Neither the name of Deusty nor the names of its contributors may be used
  13. // to endorse or promote products derived from this software without specific
  14. // prior written permission of Deusty, LLC.
  15. #import <TargetConditionals.h>
  16. #if !TARGET_OS_WATCH
  17. #if !__has_feature(objc_arc)
  18. #error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  19. #endif
  20. #import <asl.h>
  21. #import <CocoaLumberjack/DDASLLogger.h>
  22. const char* const kDDASLKeyDDLog = "DDLog";
  23. const char* const kDDASLDDLogValue = "1";
  24. #pragma clang diagnostic push
  25. #pragma clang diagnostic ignored "-Wdeprecated"
  26. static DDASLLogger *sharedInstance;
  27. #pragma clang diagnostic pop
  28. @interface DDASLLogger () {
  29. aslclient _client;
  30. }
  31. @end
  32. #pragma clang diagnostic push
  33. #pragma clang diagnostic ignored "-Wdeprecated-implementations"
  34. @implementation DDASLLogger
  35. #pragma clang diagnostic pop
  36. + (instancetype)sharedInstance {
  37. static dispatch_once_t DDASLLoggerOnceToken;
  38. dispatch_once(&DDASLLoggerOnceToken, ^{
  39. sharedInstance = [[[self class] alloc] init];
  40. });
  41. return sharedInstance;
  42. }
  43. - (instancetype)init {
  44. if (sharedInstance != nil) {
  45. return nil;
  46. }
  47. if ((self = [super init])) {
  48. // A default asl client is provided for the main thread,
  49. // but background threads need to create their own client.
  50. _client = asl_open(NULL, "com.apple.console", 0);
  51. }
  52. return self;
  53. }
  54. - (DDLoggerName)loggerName {
  55. return DDLoggerNameASL;
  56. }
  57. - (void)logMessage:(DDLogMessage *)logMessage {
  58. // Skip captured log messages
  59. if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) {
  60. return;
  61. }
  62. NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
  63. if (message) {
  64. const char *msg = [message UTF8String];
  65. size_t aslLogLevel;
  66. switch (logMessage->_flag) {
  67. // Note: By default ASL will filter anything above level 5 (Notice).
  68. // So our mappings shouldn't go above that level.
  69. case DDLogFlagError : aslLogLevel = ASL_LEVEL_CRIT; break;
  70. case DDLogFlagWarning : aslLogLevel = ASL_LEVEL_ERR; break;
  71. case DDLogFlagInfo : aslLogLevel = ASL_LEVEL_WARNING; break; // Regular NSLog's level
  72. case DDLogFlagDebug :
  73. case DDLogFlagVerbose :
  74. default : aslLogLevel = ASL_LEVEL_NOTICE; break;
  75. }
  76. static char const *const level_strings[] = { "0", "1", "2", "3", "4", "5", "6", "7" };
  77. // NSLog uses the current euid to set the ASL_KEY_READ_UID.
  78. uid_t const readUID = geteuid();
  79. char readUIDString[16];
  80. #ifndef NS_BLOCK_ASSERTIONS
  81. size_t l = (size_t)snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
  82. #else
  83. snprintf(readUIDString, sizeof(readUIDString), "%d", readUID);
  84. #endif
  85. NSAssert(l < sizeof(readUIDString),
  86. @"Formatted euid is too long.");
  87. NSAssert(aslLogLevel < (sizeof(level_strings) / sizeof(level_strings[0])),
  88. @"Unhandled ASL log level.");
  89. aslmsg m = asl_new(ASL_TYPE_MSG);
  90. if (m != NULL) {
  91. if (asl_set(m, ASL_KEY_LEVEL, level_strings[aslLogLevel]) == 0 &&
  92. asl_set(m, ASL_KEY_MSG, msg) == 0 &&
  93. asl_set(m, ASL_KEY_READ_UID, readUIDString) == 0 &&
  94. asl_set(m, kDDASLKeyDDLog, kDDASLDDLogValue) == 0) {
  95. asl_send(_client, m);
  96. }
  97. asl_free(m);
  98. }
  99. //TODO handle asl_* failures non-silently?
  100. }
  101. }
  102. @end
  103. #endif