PageRenderTime 31ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/XMPP_Demo/Vendor/CocoaLumberjack/DDTTYLogger.m

https://gitlab.com/praveenvelanati/ios-demo
Objective C | 1480 lines | 1002 code | 291 blank | 187 comment | 116 complexity | 9e65556b1a751fc1caeba7d2fafbcfb9 MD5 | raw file
  1. #import "DDTTYLogger.h"
  2. #import <unistd.h>
  3. #import <sys/uio.h>
  4. /**
  5. * Welcome to Cocoa Lumberjack!
  6. *
  7. * The project page has a wealth of documentation if you have any questions.
  8. * https://github.com/robbiehanson/CocoaLumberjack
  9. *
  10. * If you're new to the project you may wish to read the "Getting Started" wiki.
  11. * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
  12. **/
  13. #if ! __has_feature(objc_arc)
  14. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  15. #endif
  16. // We probably shouldn't be using DDLog() statements within the DDLog implementation.
  17. // But we still want to leave our log statements for any future debugging,
  18. // and to allow other developers to trace the implementation (which is a great learning tool).
  19. //
  20. // So we use primitive logging macros around NSLog.
  21. // We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
  22. #define LOG_LEVEL 2
  23. #define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
  24. #define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
  25. #define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
  26. #define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
  27. // Xcode does NOT natively support colors in the Xcode debugging console.
  28. // You'll need to install the XcodeColors plugin to see colors in the Xcode console.
  29. // https://github.com/robbiehanson/XcodeColors
  30. //
  31. // The following is documentation from the XcodeColors project:
  32. //
  33. //
  34. // How to apply color formatting to your log statements:
  35. //
  36. // To set the foreground color:
  37. // Insert the ESCAPE_SEQ into your string, followed by "fg124,12,255;" where r=124, g=12, b=255.
  38. //
  39. // To set the background color:
  40. // Insert the ESCAPE_SEQ into your string, followed by "bg12,24,36;" where r=12, g=24, b=36.
  41. //
  42. // To reset the foreground color (to default value):
  43. // Insert the ESCAPE_SEQ into your string, followed by "fg;"
  44. //
  45. // To reset the background color (to default value):
  46. // Insert the ESCAPE_SEQ into your string, followed by "bg;"
  47. //
  48. // To reset the foreground and background color (to default values) in one operation:
  49. // Insert the ESCAPE_SEQ into your string, followed by ";"
  50. #define XCODE_COLORS_ESCAPE_SEQ "\033["
  51. #define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE_SEQ "fg;" // Clear any foreground color
  52. #define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE_SEQ "bg;" // Clear any background color
  53. #define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE_SEQ ";" // Clear any foreground or background color
  54. // Some simple defines to make life easier on ourself
  55. #if TARGET_OS_IPHONE
  56. #define MakeColor(r, g, b) [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]
  57. #else
  58. #define MakeColor(r, g, b) [NSColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]
  59. #endif
  60. #if TARGET_OS_IPHONE
  61. #define OSColor UIColor
  62. #else
  63. #define OSColor NSColor
  64. #endif
  65. // If running in a shell, not all RGB colors will be supported.
  66. // In this case we automatically map to the closest available color.
  67. // In order to provide this mapping, we have a hard-coded set of the standard RGB values available in the shell.
  68. // However, not every shell is the same, and Apple likes to think different even when it comes to shell colors.
  69. //
  70. // Map to standard Terminal.app colors (1), or
  71. // map to standard xterm colors (0).
  72. #define MAP_TO_TERMINAL_APP_COLORS 1
  73. @interface DDTTYLoggerColorProfile : NSObject {
  74. @public
  75. int mask;
  76. int context;
  77. uint8_t fg_r;
  78. uint8_t fg_g;
  79. uint8_t fg_b;
  80. uint8_t bg_r;
  81. uint8_t bg_g;
  82. uint8_t bg_b;
  83. NSUInteger fgCodeIndex;
  84. NSString *fgCodeRaw;
  85. NSUInteger bgCodeIndex;
  86. NSString *bgCodeRaw;
  87. char fgCode[24];
  88. size_t fgCodeLen;
  89. char bgCode[24];
  90. size_t bgCodeLen;
  91. char resetCode[8];
  92. size_t resetCodeLen;
  93. }
  94. - (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)mask context:(int)ctxt;
  95. @end
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. #pragma mark -
  98. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  99. @implementation DDTTYLogger
  100. static BOOL isaTTY;
  101. static BOOL isaColorTTY;
  102. static BOOL isaColor256TTY;
  103. static BOOL isaXcodeColorTTY;
  104. static NSArray *codes_fg = nil;
  105. static NSArray *codes_bg = nil;
  106. static NSArray *colors = nil;
  107. static DDTTYLogger *sharedInstance;
  108. /**
  109. * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 16 color mode.
  110. *
  111. * This method is used when the application is running from within a shell that only supports 16 color mode.
  112. * This method is not invoked if the application is running within Xcode, or via normal UI app launch.
  113. **/
  114. + (void)initialize_colors_16
  115. {
  116. if (codes_fg || codes_bg || colors) return;
  117. NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:16];
  118. NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:16];
  119. NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:16];
  120. // In a standard shell only 16 colors are supported.
  121. //
  122. // More information about ansi escape codes can be found online.
  123. // http://en.wikipedia.org/wiki/ANSI_escape_code
  124. [m_codes_fg addObject:@"30m"]; // normal - black
  125. [m_codes_fg addObject:@"31m"]; // normal - red
  126. [m_codes_fg addObject:@"32m"]; // normal - green
  127. [m_codes_fg addObject:@"33m"]; // normal - yellow
  128. [m_codes_fg addObject:@"34m"]; // normal - blue
  129. [m_codes_fg addObject:@"35m"]; // normal - magenta
  130. [m_codes_fg addObject:@"36m"]; // normal - cyan
  131. [m_codes_fg addObject:@"37m"]; // normal - gray
  132. [m_codes_fg addObject:@"1;30m"]; // bright - darkgray
  133. [m_codes_fg addObject:@"1;31m"]; // bright - red
  134. [m_codes_fg addObject:@"1;32m"]; // bright - green
  135. [m_codes_fg addObject:@"1;33m"]; // bright - yellow
  136. [m_codes_fg addObject:@"1;34m"]; // bright - blue
  137. [m_codes_fg addObject:@"1;35m"]; // bright - magenta
  138. [m_codes_fg addObject:@"1;36m"]; // bright - cyan
  139. [m_codes_fg addObject:@"1;37m"]; // bright - white
  140. [m_codes_bg addObject:@"40m"]; // normal - black
  141. [m_codes_bg addObject:@"41m"]; // normal - red
  142. [m_codes_bg addObject:@"42m"]; // normal - green
  143. [m_codes_bg addObject:@"43m"]; // normal - yellow
  144. [m_codes_bg addObject:@"44m"]; // normal - blue
  145. [m_codes_bg addObject:@"45m"]; // normal - magenta
  146. [m_codes_bg addObject:@"46m"]; // normal - cyan
  147. [m_codes_bg addObject:@"47m"]; // normal - gray
  148. [m_codes_bg addObject:@"1;40m"]; // bright - darkgray
  149. [m_codes_bg addObject:@"1;41m"]; // bright - red
  150. [m_codes_bg addObject:@"1;42m"]; // bright - green
  151. [m_codes_bg addObject:@"1;43m"]; // bright - yellow
  152. [m_codes_bg addObject:@"1;44m"]; // bright - blue
  153. [m_codes_bg addObject:@"1;45m"]; // bright - magenta
  154. [m_codes_bg addObject:@"1;46m"]; // bright - cyan
  155. [m_codes_bg addObject:@"1;47m"]; // bright - white
  156. #if MAP_TO_TERMINAL_APP_COLORS
  157. // Standard Terminal.app colors:
  158. //
  159. // These are the default colors used by Apple's Terminal.app.
  160. [m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black
  161. [m_colors addObject:MakeColor(194, 54, 33)]; // normal - red
  162. [m_colors addObject:MakeColor( 37, 188, 36)]; // normal - green
  163. [m_colors addObject:MakeColor(173, 173, 39)]; // normal - yellow
  164. [m_colors addObject:MakeColor( 73, 46, 225)]; // normal - blue
  165. [m_colors addObject:MakeColor(211, 56, 211)]; // normal - magenta
  166. [m_colors addObject:MakeColor( 51, 187, 200)]; // normal - cyan
  167. [m_colors addObject:MakeColor(203, 204, 205)]; // normal - gray
  168. [m_colors addObject:MakeColor(129, 131, 131)]; // bright - darkgray
  169. [m_colors addObject:MakeColor(252, 57, 31)]; // bright - red
  170. [m_colors addObject:MakeColor( 49, 231, 34)]; // bright - green
  171. [m_colors addObject:MakeColor(234, 236, 35)]; // bright - yellow
  172. [m_colors addObject:MakeColor( 88, 51, 255)]; // bright - blue
  173. [m_colors addObject:MakeColor(249, 53, 248)]; // bright - magenta
  174. [m_colors addObject:MakeColor( 20, 240, 240)]; // bright - cyan
  175. [m_colors addObject:MakeColor(233, 235, 235)]; // bright - white
  176. #else
  177. // Standard xterm colors:
  178. //
  179. // These are the default colors used by most xterm shells.
  180. [m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black
  181. [m_colors addObject:MakeColor(205, 0, 0)]; // normal - red
  182. [m_colors addObject:MakeColor( 0, 205, 0)]; // normal - green
  183. [m_colors addObject:MakeColor(205, 205, 0)]; // normal - yellow
  184. [m_colors addObject:MakeColor( 0, 0, 238)]; // normal - blue
  185. [m_colors addObject:MakeColor(205, 0, 205)]; // normal - magenta
  186. [m_colors addObject:MakeColor( 0, 205, 205)]; // normal - cyan
  187. [m_colors addObject:MakeColor(229, 229, 229)]; // normal - gray
  188. [m_colors addObject:MakeColor(127, 127, 127)]; // bright - darkgray
  189. [m_colors addObject:MakeColor(255, 0, 0)]; // bright - red
  190. [m_colors addObject:MakeColor( 0, 255, 0)]; // bright - green
  191. [m_colors addObject:MakeColor(255, 255, 0)]; // bright - yellow
  192. [m_colors addObject:MakeColor( 92, 92, 255)]; // bright - blue
  193. [m_colors addObject:MakeColor(255, 0, 255)]; // bright - magenta
  194. [m_colors addObject:MakeColor( 0, 255, 255)]; // bright - cyan
  195. [m_colors addObject:MakeColor(255, 255, 255)]; // bright - white
  196. #endif
  197. codes_fg = [m_codes_fg copy];
  198. codes_bg = [m_codes_bg copy];
  199. colors = [m_colors copy];
  200. NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
  201. NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
  202. }
  203. /**
  204. * Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 256 color mode.
  205. *
  206. * This method is used when the application is running from within a shell that supports 256 color mode.
  207. * This method is not invoked if the application is running within Xcode, or via normal UI app launch.
  208. **/
  209. + (void)initialize_colors_256
  210. {
  211. if (codes_fg || codes_bg || colors) return;
  212. NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:(256-16)];
  213. NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:(256-16)];
  214. NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:(256-16)];
  215. #if MAP_TO_TERMINAL_APP_COLORS
  216. // Standard Terminal.app colors:
  217. //
  218. // These are the colors the Terminal.app uses in xterm-256color mode.
  219. // In this mode, the terminal supports 256 different colors, specified by 256 color codes.
  220. //
  221. // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
  222. // These are actually configurable, and thus we ignore them for the purposes of mapping,
  223. // as we can't rely on them being constant. They are largely duplicated anyway.
  224. //
  225. // The next 216 color codes are designed to run the spectrum, with several shades of every color.
  226. // While the color codes are standardized, the actual RGB values for each color code is not.
  227. // Apple's Terminal.app uses different RGB values from that of a standard xterm.
  228. // Apple's choices in colors are designed to be a little nicer on the eyes.
  229. //
  230. // The last 24 color codes represent a grayscale.
  231. //
  232. // Unfortunately, unlike the standard xterm color chart,
  233. // Apple's RGB values cannot be calculated using a simple formula (at least not that I know of).
  234. // Also, I don't know of any ways to programmatically query the shell for the RGB values.
  235. // So this big giant color chart had to be made by hand.
  236. //
  237. // More information about ansi escape codes can be found online.
  238. // http://en.wikipedia.org/wiki/ANSI_escape_code
  239. // Colors
  240. [m_colors addObject:MakeColor( 47, 49, 49)];
  241. [m_colors addObject:MakeColor( 60, 42, 144)];
  242. [m_colors addObject:MakeColor( 66, 44, 183)];
  243. [m_colors addObject:MakeColor( 73, 46, 222)];
  244. [m_colors addObject:MakeColor( 81, 50, 253)];
  245. [m_colors addObject:MakeColor( 88, 51, 255)];
  246. [m_colors addObject:MakeColor( 42, 128, 37)];
  247. [m_colors addObject:MakeColor( 42, 127, 128)];
  248. [m_colors addObject:MakeColor( 44, 126, 169)];
  249. [m_colors addObject:MakeColor( 56, 125, 209)];
  250. [m_colors addObject:MakeColor( 59, 124, 245)];
  251. [m_colors addObject:MakeColor( 66, 123, 255)];
  252. [m_colors addObject:MakeColor( 51, 163, 41)];
  253. [m_colors addObject:MakeColor( 39, 162, 121)];
  254. [m_colors addObject:MakeColor( 42, 161, 162)];
  255. [m_colors addObject:MakeColor( 53, 160, 202)];
  256. [m_colors addObject:MakeColor( 45, 159, 240)];
  257. [m_colors addObject:MakeColor( 58, 158, 255)];
  258. [m_colors addObject:MakeColor( 31, 196, 37)];
  259. [m_colors addObject:MakeColor( 48, 196, 115)];
  260. [m_colors addObject:MakeColor( 39, 195, 155)];
  261. [m_colors addObject:MakeColor( 49, 195, 195)];
  262. [m_colors addObject:MakeColor( 32, 194, 235)];
  263. [m_colors addObject:MakeColor( 53, 193, 255)];
  264. [m_colors addObject:MakeColor( 50, 229, 35)];
  265. [m_colors addObject:MakeColor( 40, 229, 109)];
  266. [m_colors addObject:MakeColor( 27, 229, 149)];
  267. [m_colors addObject:MakeColor( 49, 228, 189)];
  268. [m_colors addObject:MakeColor( 33, 228, 228)];
  269. [m_colors addObject:MakeColor( 53, 227, 255)];
  270. [m_colors addObject:MakeColor( 27, 254, 30)];
  271. [m_colors addObject:MakeColor( 30, 254, 103)];
  272. [m_colors addObject:MakeColor( 45, 254, 143)];
  273. [m_colors addObject:MakeColor( 38, 253, 182)];
  274. [m_colors addObject:MakeColor( 38, 253, 222)];
  275. [m_colors addObject:MakeColor( 42, 253, 252)];
  276. [m_colors addObject:MakeColor(140, 48, 40)];
  277. [m_colors addObject:MakeColor(136, 51, 136)];
  278. [m_colors addObject:MakeColor(135, 52, 177)];
  279. [m_colors addObject:MakeColor(134, 52, 217)];
  280. [m_colors addObject:MakeColor(135, 56, 248)];
  281. [m_colors addObject:MakeColor(134, 53, 255)];
  282. [m_colors addObject:MakeColor(125, 125, 38)];
  283. [m_colors addObject:MakeColor(124, 125, 125)];
  284. [m_colors addObject:MakeColor(122, 124, 166)];
  285. [m_colors addObject:MakeColor(123, 124, 207)];
  286. [m_colors addObject:MakeColor(123, 122, 247)];
  287. [m_colors addObject:MakeColor(124, 121, 255)];
  288. [m_colors addObject:MakeColor(119, 160, 35)];
  289. [m_colors addObject:MakeColor(117, 160, 120)];
  290. [m_colors addObject:MakeColor(117, 160, 160)];
  291. [m_colors addObject:MakeColor(115, 159, 201)];
  292. [m_colors addObject:MakeColor(116, 158, 240)];
  293. [m_colors addObject:MakeColor(117, 157, 255)];
  294. [m_colors addObject:MakeColor(113, 195, 39)];
  295. [m_colors addObject:MakeColor(110, 194, 114)];
  296. [m_colors addObject:MakeColor(111, 194, 154)];
  297. [m_colors addObject:MakeColor(108, 194, 194)];
  298. [m_colors addObject:MakeColor(109, 193, 234)];
  299. [m_colors addObject:MakeColor(108, 192, 255)];
  300. [m_colors addObject:MakeColor(105, 228, 30)];
  301. [m_colors addObject:MakeColor(103, 228, 109)];
  302. [m_colors addObject:MakeColor(105, 228, 148)];
  303. [m_colors addObject:MakeColor(100, 227, 188)];
  304. [m_colors addObject:MakeColor( 99, 227, 227)];
  305. [m_colors addObject:MakeColor( 99, 226, 253)];
  306. [m_colors addObject:MakeColor( 92, 253, 34)];
  307. [m_colors addObject:MakeColor( 96, 253, 103)];
  308. [m_colors addObject:MakeColor( 97, 253, 142)];
  309. [m_colors addObject:MakeColor( 88, 253, 182)];
  310. [m_colors addObject:MakeColor( 93, 253, 221)];
  311. [m_colors addObject:MakeColor( 88, 254, 251)];
  312. [m_colors addObject:MakeColor(177, 53, 34)];
  313. [m_colors addObject:MakeColor(174, 54, 131)];
  314. [m_colors addObject:MakeColor(172, 55, 172)];
  315. [m_colors addObject:MakeColor(171, 57, 213)];
  316. [m_colors addObject:MakeColor(170, 55, 249)];
  317. [m_colors addObject:MakeColor(170, 57, 255)];
  318. [m_colors addObject:MakeColor(165, 123, 37)];
  319. [m_colors addObject:MakeColor(163, 123, 123)];
  320. [m_colors addObject:MakeColor(162, 123, 164)];
  321. [m_colors addObject:MakeColor(161, 122, 205)];
  322. [m_colors addObject:MakeColor(161, 121, 241)];
  323. [m_colors addObject:MakeColor(161, 121, 255)];
  324. [m_colors addObject:MakeColor(158, 159, 33)];
  325. [m_colors addObject:MakeColor(157, 158, 118)];
  326. [m_colors addObject:MakeColor(157, 158, 159)];
  327. [m_colors addObject:MakeColor(155, 157, 199)];
  328. [m_colors addObject:MakeColor(155, 157, 239)];
  329. [m_colors addObject:MakeColor(154, 156, 255)];
  330. [m_colors addObject:MakeColor(152, 193, 40)];
  331. [m_colors addObject:MakeColor(151, 193, 113)];
  332. [m_colors addObject:MakeColor(150, 193, 153)];
  333. [m_colors addObject:MakeColor(150, 192, 193)];
  334. [m_colors addObject:MakeColor(148, 192, 232)];
  335. [m_colors addObject:MakeColor(149, 191, 253)];
  336. [m_colors addObject:MakeColor(146, 227, 28)];
  337. [m_colors addObject:MakeColor(144, 227, 108)];
  338. [m_colors addObject:MakeColor(144, 227, 147)];
  339. [m_colors addObject:MakeColor(144, 227, 187)];
  340. [m_colors addObject:MakeColor(142, 226, 227)];
  341. [m_colors addObject:MakeColor(142, 225, 252)];
  342. [m_colors addObject:MakeColor(138, 253, 36)];
  343. [m_colors addObject:MakeColor(137, 253, 102)];
  344. [m_colors addObject:MakeColor(136, 253, 141)];
  345. [m_colors addObject:MakeColor(138, 254, 181)];
  346. [m_colors addObject:MakeColor(135, 255, 220)];
  347. [m_colors addObject:MakeColor(133, 255, 250)];
  348. [m_colors addObject:MakeColor(214, 57, 30)];
  349. [m_colors addObject:MakeColor(211, 59, 126)];
  350. [m_colors addObject:MakeColor(209, 57, 168)];
  351. [m_colors addObject:MakeColor(208, 55, 208)];
  352. [m_colors addObject:MakeColor(207, 58, 247)];
  353. [m_colors addObject:MakeColor(206, 61, 255)];
  354. [m_colors addObject:MakeColor(204, 121, 32)];
  355. [m_colors addObject:MakeColor(202, 121, 121)];
  356. [m_colors addObject:MakeColor(201, 121, 161)];
  357. [m_colors addObject:MakeColor(200, 120, 202)];
  358. [m_colors addObject:MakeColor(200, 120, 241)];
  359. [m_colors addObject:MakeColor(198, 119, 255)];
  360. [m_colors addObject:MakeColor(198, 157, 37)];
  361. [m_colors addObject:MakeColor(196, 157, 116)];
  362. [m_colors addObject:MakeColor(195, 156, 157)];
  363. [m_colors addObject:MakeColor(195, 156, 197)];
  364. [m_colors addObject:MakeColor(194, 155, 236)];
  365. [m_colors addObject:MakeColor(193, 155, 255)];
  366. [m_colors addObject:MakeColor(191, 192, 36)];
  367. [m_colors addObject:MakeColor(190, 191, 112)];
  368. [m_colors addObject:MakeColor(189, 191, 152)];
  369. [m_colors addObject:MakeColor(189, 191, 191)];
  370. [m_colors addObject:MakeColor(188, 190, 230)];
  371. [m_colors addObject:MakeColor(187, 190, 253)];
  372. [m_colors addObject:MakeColor(185, 226, 28)];
  373. [m_colors addObject:MakeColor(184, 226, 106)];
  374. [m_colors addObject:MakeColor(183, 225, 146)];
  375. [m_colors addObject:MakeColor(183, 225, 186)];
  376. [m_colors addObject:MakeColor(182, 225, 225)];
  377. [m_colors addObject:MakeColor(181, 224, 252)];
  378. [m_colors addObject:MakeColor(178, 255, 35)];
  379. [m_colors addObject:MakeColor(178, 255, 101)];
  380. [m_colors addObject:MakeColor(177, 254, 141)];
  381. [m_colors addObject:MakeColor(176, 254, 180)];
  382. [m_colors addObject:MakeColor(176, 254, 220)];
  383. [m_colors addObject:MakeColor(175, 253, 249)];
  384. [m_colors addObject:MakeColor(247, 56, 30)];
  385. [m_colors addObject:MakeColor(245, 57, 122)];
  386. [m_colors addObject:MakeColor(243, 59, 163)];
  387. [m_colors addObject:MakeColor(244, 60, 204)];
  388. [m_colors addObject:MakeColor(242, 59, 241)];
  389. [m_colors addObject:MakeColor(240, 55, 255)];
  390. [m_colors addObject:MakeColor(241, 119, 36)];
  391. [m_colors addObject:MakeColor(240, 120, 118)];
  392. [m_colors addObject:MakeColor(238, 119, 158)];
  393. [m_colors addObject:MakeColor(237, 119, 199)];
  394. [m_colors addObject:MakeColor(237, 118, 238)];
  395. [m_colors addObject:MakeColor(236, 118, 255)];
  396. [m_colors addObject:MakeColor(235, 154, 36)];
  397. [m_colors addObject:MakeColor(235, 154, 114)];
  398. [m_colors addObject:MakeColor(234, 154, 154)];
  399. [m_colors addObject:MakeColor(232, 154, 194)];
  400. [m_colors addObject:MakeColor(232, 153, 234)];
  401. [m_colors addObject:MakeColor(232, 153, 255)];
  402. [m_colors addObject:MakeColor(230, 190, 30)];
  403. [m_colors addObject:MakeColor(229, 189, 110)];
  404. [m_colors addObject:MakeColor(228, 189, 150)];
  405. [m_colors addObject:MakeColor(227, 189, 190)];
  406. [m_colors addObject:MakeColor(227, 189, 229)];
  407. [m_colors addObject:MakeColor(226, 188, 255)];
  408. [m_colors addObject:MakeColor(224, 224, 35)];
  409. [m_colors addObject:MakeColor(223, 224, 105)];
  410. [m_colors addObject:MakeColor(222, 224, 144)];
  411. [m_colors addObject:MakeColor(222, 223, 184)];
  412. [m_colors addObject:MakeColor(222, 223, 224)];
  413. [m_colors addObject:MakeColor(220, 223, 253)];
  414. [m_colors addObject:MakeColor(217, 253, 28)];
  415. [m_colors addObject:MakeColor(217, 253, 99)];
  416. [m_colors addObject:MakeColor(216, 252, 139)];
  417. [m_colors addObject:MakeColor(216, 252, 179)];
  418. [m_colors addObject:MakeColor(215, 252, 218)];
  419. [m_colors addObject:MakeColor(215, 251, 250)];
  420. [m_colors addObject:MakeColor(255, 61, 30)];
  421. [m_colors addObject:MakeColor(255, 60, 118)];
  422. [m_colors addObject:MakeColor(255, 58, 159)];
  423. [m_colors addObject:MakeColor(255, 56, 199)];
  424. [m_colors addObject:MakeColor(255, 55, 238)];
  425. [m_colors addObject:MakeColor(255, 59, 255)];
  426. [m_colors addObject:MakeColor(255, 117, 29)];
  427. [m_colors addObject:MakeColor(255, 117, 115)];
  428. [m_colors addObject:MakeColor(255, 117, 155)];
  429. [m_colors addObject:MakeColor(255, 117, 195)];
  430. [m_colors addObject:MakeColor(255, 116, 235)];
  431. [m_colors addObject:MakeColor(254, 116, 255)];
  432. [m_colors addObject:MakeColor(255, 152, 27)];
  433. [m_colors addObject:MakeColor(255, 152, 111)];
  434. [m_colors addObject:MakeColor(254, 152, 152)];
  435. [m_colors addObject:MakeColor(255, 152, 192)];
  436. [m_colors addObject:MakeColor(254, 151, 231)];
  437. [m_colors addObject:MakeColor(253, 151, 253)];
  438. [m_colors addObject:MakeColor(255, 187, 33)];
  439. [m_colors addObject:MakeColor(253, 187, 107)];
  440. [m_colors addObject:MakeColor(252, 187, 148)];
  441. [m_colors addObject:MakeColor(253, 187, 187)];
  442. [m_colors addObject:MakeColor(254, 187, 227)];
  443. [m_colors addObject:MakeColor(252, 186, 252)];
  444. [m_colors addObject:MakeColor(252, 222, 34)];
  445. [m_colors addObject:MakeColor(251, 222, 103)];
  446. [m_colors addObject:MakeColor(251, 222, 143)];
  447. [m_colors addObject:MakeColor(250, 222, 182)];
  448. [m_colors addObject:MakeColor(251, 221, 222)];
  449. [m_colors addObject:MakeColor(252, 221, 252)];
  450. [m_colors addObject:MakeColor(251, 252, 15)];
  451. [m_colors addObject:MakeColor(251, 252, 97)];
  452. [m_colors addObject:MakeColor(249, 252, 137)];
  453. [m_colors addObject:MakeColor(247, 252, 177)];
  454. [m_colors addObject:MakeColor(247, 253, 217)];
  455. [m_colors addObject:MakeColor(254, 255, 255)];
  456. // Grayscale
  457. [m_colors addObject:MakeColor( 52, 53, 53)];
  458. [m_colors addObject:MakeColor( 57, 58, 59)];
  459. [m_colors addObject:MakeColor( 66, 67, 67)];
  460. [m_colors addObject:MakeColor( 75, 76, 76)];
  461. [m_colors addObject:MakeColor( 83, 85, 85)];
  462. [m_colors addObject:MakeColor( 92, 93, 94)];
  463. [m_colors addObject:MakeColor(101, 102, 102)];
  464. [m_colors addObject:MakeColor(109, 111, 111)];
  465. [m_colors addObject:MakeColor(118, 119, 119)];
  466. [m_colors addObject:MakeColor(126, 127, 128)];
  467. [m_colors addObject:MakeColor(134, 136, 136)];
  468. [m_colors addObject:MakeColor(143, 144, 145)];
  469. [m_colors addObject:MakeColor(151, 152, 153)];
  470. [m_colors addObject:MakeColor(159, 161, 161)];
  471. [m_colors addObject:MakeColor(167, 169, 169)];
  472. [m_colors addObject:MakeColor(176, 177, 177)];
  473. [m_colors addObject:MakeColor(184, 185, 186)];
  474. [m_colors addObject:MakeColor(192, 193, 194)];
  475. [m_colors addObject:MakeColor(200, 201, 202)];
  476. [m_colors addObject:MakeColor(208, 209, 210)];
  477. [m_colors addObject:MakeColor(216, 218, 218)];
  478. [m_colors addObject:MakeColor(224, 226, 226)];
  479. [m_colors addObject:MakeColor(232, 234, 234)];
  480. [m_colors addObject:MakeColor(240, 242, 242)];
  481. // Color codes
  482. int index = 16;
  483. while (index < 256)
  484. {
  485. [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
  486. [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
  487. index++;
  488. }
  489. #else
  490. // Standard xterm colors:
  491. //
  492. // These are the colors xterm shells use in xterm-256color mode.
  493. // In this mode, the shell supports 256 different colors, specified by 256 color codes.
  494. //
  495. // The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
  496. // These are generally configurable, and thus we ignore them for the purposes of mapping,
  497. // as we can't rely on them being constant. They are largely duplicated anyway.
  498. //
  499. // The next 216 color codes are designed to run the spectrum, with several shades of every color.
  500. // The last 24 color codes represent a grayscale.
  501. //
  502. // While the color codes are standardized, the actual RGB values for each color code is not.
  503. // However most standard xterms follow a well known color chart,
  504. // which can easily be calculated using the simple formula below.
  505. //
  506. // More information about ansi escape codes can be found online.
  507. // http://en.wikipedia.org/wiki/ANSI_escape_code
  508. int index = 16;
  509. int r; // red
  510. int g; // green
  511. int b; // blue
  512. int ri; // r increment
  513. int gi; // g increment
  514. int bi; // b increment
  515. // Calculate xterm colors (using standard algorithm)
  516. int r = 0;
  517. int g = 0;
  518. int b = 0;
  519. for (ri = 0; ri < 6; ri++)
  520. {
  521. r = (ri == 0) ? 0 : 95 + (40 * (ri - 1));
  522. for (gi = 0; gi < 6; gi++)
  523. {
  524. g = (gi == 0) ? 0 : 95 + (40 * (gi - 1));
  525. for (bi = 0; bi < 6; bi++)
  526. {
  527. b = (bi == 0) ? 0 : 95 + (40 * (bi - 1));
  528. [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
  529. [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
  530. [m_colors addObject:MakeColor(r, g, b)];
  531. index++;
  532. }
  533. }
  534. }
  535. // Calculate xterm grayscale (using standard algorithm)
  536. r = 8;
  537. g = 8;
  538. b = 8;
  539. while (index < 256)
  540. {
  541. [m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
  542. [m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
  543. [m_colors addObject:MakeColor(r, g, b)];
  544. r += 10;
  545. g += 10;
  546. b += 10;
  547. index++;
  548. }
  549. #endif
  550. codes_fg = [m_codes_fg copy];
  551. codes_bg = [m_codes_bg copy];
  552. colors = [m_colors copy];
  553. NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
  554. NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
  555. }
  556. + (void)getRed:(CGFloat *)rPtr green:(CGFloat *)gPtr blue:(CGFloat *)bPtr fromColor:(OSColor *)color
  557. {
  558. #if TARGET_OS_IPHONE
  559. // iOS
  560. if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)])
  561. {
  562. [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
  563. }
  564. else
  565. {
  566. // The method getRed:green:blue:alpha: was only available starting iOS 5.
  567. // So in iOS 4 and earlier, we have to jump through hoops.
  568. CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
  569. unsigned char pixel[4];
  570. CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, kCGImageAlphaNoneSkipLast);
  571. CGContextSetFillColorWithColor(context, [color CGColor]);
  572. CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
  573. if (rPtr) { *rPtr = pixel[0] / 255.0f; }
  574. if (gPtr) { *gPtr = pixel[1] / 255.0f; }
  575. if (bPtr) { *bPtr = pixel[2] / 255.0f; }
  576. CGContextRelease(context);
  577. CGColorSpaceRelease(rgbColorSpace);
  578. }
  579. #else
  580. // Mac OS X
  581. [color getRed:rPtr green:gPtr blue:bPtr alpha:NULL];
  582. #endif
  583. }
  584. /**
  585. * Maps the given color to the closest available color supported by the shell.
  586. * The shell may support 256 colors, or only 16.
  587. *
  588. * This method loops through the known supported color set, and calculates the closest color.
  589. * The array index of that color, within the colors array, is then returned.
  590. * This array index may also be used as the index within the codes_fg and codes_bg arrays.
  591. **/
  592. + (NSUInteger)codeIndexForColor:(OSColor *)inColor
  593. {
  594. CGFloat inR, inG, inB;
  595. [self getRed:&inR green:&inG blue:&inB fromColor:inColor];
  596. NSUInteger bestIndex = 0;
  597. CGFloat lowestDistance = 100.0f;
  598. NSUInteger i = 0;
  599. for (OSColor *color in colors)
  600. {
  601. // Calculate Euclidean distance (lower value means closer to given color)
  602. CGFloat r, g, b;
  603. [self getRed:&r green:&g blue:&b fromColor:color];
  604. #if CGFLOAT_IS_DOUBLE
  605. CGFloat distance = sqrt(pow(r-inR, 2.0) + pow(g-inG, 2.0) + pow(b-inB, 2.0));
  606. #else
  607. CGFloat distance = sqrtf(powf(r-inR, 2.0f) + powf(g-inG, 2.0f) + powf(b-inB, 2.0f));
  608. #endif
  609. NSLogVerbose(@"DDTTYLogger: %3lu : %.3f,%.3f,%.3f & %.3f,%.3f,%.3f = %.6f",
  610. (unsigned long)i, inR, inG, inB, r, g, b, distance);
  611. if (distance < lowestDistance)
  612. {
  613. bestIndex = i;
  614. lowestDistance = distance;
  615. NSLogVerbose(@"DDTTYLogger: New best index = %lu", (unsigned long)bestIndex);
  616. }
  617. i++;
  618. }
  619. return bestIndex;
  620. }
  621. /**
  622. * The runtime sends initialize to each class in a program exactly one time just before the class,
  623. * or any class that inherits from it, is sent its first message from within the program. (Thus the
  624. * method may never be invoked if the class is not used.) The runtime sends the initialize message to
  625. * classes in a thread-safe manner. Superclasses receive this message before their subclasses.
  626. *
  627. * This method may also be called directly (assumably by accident), hence the safety mechanism.
  628. **/
  629. + (void)initialize
  630. {
  631. static BOOL initialized = NO;
  632. if (!initialized)
  633. {
  634. initialized = YES;
  635. isaTTY = isatty(STDERR_FILENO);
  636. char *term = getenv("TERM");
  637. if (term)
  638. {
  639. if (strcasestr(term, "color") != NULL)
  640. {
  641. isaColorTTY = YES;
  642. isaColor256TTY = (strcasestr(term, "256") != NULL);
  643. if (isaColor256TTY)
  644. [self initialize_colors_256];
  645. else
  646. [self initialize_colors_16];
  647. }
  648. }
  649. else
  650. {
  651. // Xcode does NOT natively support colors in the Xcode debugging console.
  652. // You'll need to install the XcodeColors plugin to see colors in the Xcode console.
  653. //
  654. // PS - Please read the header file before diving into the source code.
  655. char *xcode_colors = getenv("XcodeColors");
  656. if (xcode_colors && (strcmp(xcode_colors, "YES") == 0))
  657. {
  658. isaXcodeColorTTY = YES;
  659. }
  660. }
  661. NSLogInfo(@"DDTTYLogger: isaColorTTY = %@", (isaColorTTY ? @"YES" : @"NO"));
  662. NSLogInfo(@"DDTTYLogger: isaColor256TTY: %@", (isaColor256TTY ? @"YES" : @"NO"));
  663. NSLogInfo(@"DDTTYLogger: isaXcodeColorTTY: %@", (isaXcodeColorTTY ? @"YES" : @"NO"));
  664. sharedInstance = [[DDTTYLogger alloc] init];
  665. }
  666. }
  667. + (DDTTYLogger *)sharedInstance
  668. {
  669. return sharedInstance;
  670. }
  671. - (id)init
  672. {
  673. if (sharedInstance != nil)
  674. {
  675. return nil;
  676. }
  677. if ((self = [super init]))
  678. {
  679. if (isaTTY)
  680. {
  681. calendar = [NSCalendar autoupdatingCurrentCalendar];
  682. calendarUnitFlags = 0;
  683. calendarUnitFlags |= NSYearCalendarUnit;
  684. calendarUnitFlags |= NSMonthCalendarUnit;
  685. calendarUnitFlags |= NSDayCalendarUnit;
  686. calendarUnitFlags |= NSHourCalendarUnit;
  687. calendarUnitFlags |= NSMinuteCalendarUnit;
  688. calendarUnitFlags |= NSSecondCalendarUnit;
  689. // Initialze 'app' variable (char *)
  690. appName = [[NSProcessInfo processInfo] processName];
  691. appLen = [appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  692. app = (char *)malloc(appLen + 1);
  693. [appName getCString:app maxLength:(appLen+1) encoding:NSUTF8StringEncoding];
  694. // Initialize 'pid' variable (char *)
  695. processID = [NSString stringWithFormat:@"%i", (int)getpid()];
  696. pidLen = [processID lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  697. pid = (char *)malloc(pidLen + 1);
  698. [processID getCString:pid maxLength:(pidLen+1) encoding:NSUTF8StringEncoding];
  699. // Initialize color stuff
  700. colorsEnabled = NO;
  701. colorProfilesArray = [[NSMutableArray alloc] initWithCapacity:8];
  702. colorProfilesDict = [[NSMutableDictionary alloc] initWithCapacity:8];
  703. }
  704. }
  705. return self;
  706. }
  707. - (void)loadDefaultColorProfiles
  708. {
  709. [self setForegroundColor:MakeColor(214, 57, 30) backgroundColor:nil forFlag:LOG_FLAG_ERROR];
  710. [self setForegroundColor:MakeColor(204, 121, 32) backgroundColor:nil forFlag:LOG_FLAG_WARN];
  711. }
  712. - (BOOL)colorsEnabled
  713. {
  714. // The design of this method is taken from the DDAbstractLogger implementation.
  715. // For documentation please refer to the DDAbstractLogger implementation.
  716. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  717. if (currentQueue == loggerQueue)
  718. {
  719. return colorsEnabled;
  720. }
  721. else
  722. {
  723. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  724. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  725. __block BOOL result;
  726. dispatch_sync(globalLoggingQueue, ^{
  727. dispatch_sync(loggerQueue, ^{
  728. result = colorsEnabled;
  729. });
  730. });
  731. return result;
  732. }
  733. }
  734. - (void)setColorsEnabled:(BOOL)newColorsEnabled
  735. {
  736. dispatch_block_t block = ^{ @autoreleasepool {
  737. colorsEnabled = newColorsEnabled;
  738. if ([colorProfilesArray count] == 0) {
  739. [self loadDefaultColorProfiles];
  740. }
  741. }};
  742. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  743. // For documentation please refer to the DDAbstractLogger implementation.
  744. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  745. if (currentQueue == loggerQueue)
  746. {
  747. block();
  748. }
  749. else
  750. {
  751. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  752. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  753. dispatch_async(globalLoggingQueue, ^{
  754. dispatch_async(loggerQueue, block);
  755. });
  756. }
  757. }
  758. - (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask
  759. {
  760. [self setForegroundColor:txtColor backgroundColor:bgColor forFlag:mask context:0];
  761. }
  762. - (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask context:(int)ctxt
  763. {
  764. dispatch_block_t block = ^{ @autoreleasepool {
  765. DDTTYLoggerColorProfile *newColorProfile =
  766. [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
  767. backgroundColor:bgColor
  768. flag:mask
  769. context:ctxt];
  770. NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
  771. NSUInteger i = 0;
  772. for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray)
  773. {
  774. if ((colorProfile->mask == mask) && (colorProfile->context == ctxt))
  775. {
  776. break;
  777. }
  778. i++;
  779. }
  780. if (i < [colorProfilesArray count])
  781. [colorProfilesArray replaceObjectAtIndex:i withObject:newColorProfile];
  782. else
  783. [colorProfilesArray addObject:newColorProfile];
  784. }};
  785. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  786. // For documentation please refer to the DDAbstractLogger implementation.
  787. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  788. if (currentQueue == loggerQueue)
  789. {
  790. block();
  791. }
  792. else
  793. {
  794. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  795. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  796. dispatch_async(globalLoggingQueue, ^{
  797. dispatch_async(loggerQueue, block);
  798. });
  799. }
  800. }
  801. - (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forTag:(id <NSCopying>)tag
  802. {
  803. NSAssert([(id <NSObject>)tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag");
  804. dispatch_block_t block = ^{ @autoreleasepool {
  805. DDTTYLoggerColorProfile *newColorProfile =
  806. [[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
  807. backgroundColor:bgColor
  808. flag:0
  809. context:0];
  810. NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
  811. [colorProfilesDict setObject:newColorProfile forKey:tag];
  812. }};
  813. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  814. // For documentation please refer to the DDAbstractLogger implementation.
  815. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  816. if (currentQueue == loggerQueue)
  817. {
  818. block();
  819. }
  820. else
  821. {
  822. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  823. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  824. dispatch_async(globalLoggingQueue, ^{
  825. dispatch_async(loggerQueue, block);
  826. });
  827. }
  828. }
  829. - (void)clearColorsForFlag:(int)mask
  830. {
  831. [self clearColorsForFlag:mask context:0];
  832. }
  833. - (void)clearColorsForFlag:(int)mask context:(int)context
  834. {
  835. dispatch_block_t block = ^{ @autoreleasepool {
  836. NSUInteger i = 0;
  837. for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray)
  838. {
  839. if ((colorProfile->mask == mask) && (colorProfile->context == context))
  840. {
  841. break;
  842. }
  843. i++;
  844. }
  845. if (i < [colorProfilesArray count])
  846. {
  847. [colorProfilesArray removeObjectAtIndex:i];
  848. }
  849. }};
  850. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  851. // For documentation please refer to the DDAbstractLogger implementation.
  852. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  853. if (currentQueue == loggerQueue)
  854. {
  855. block();
  856. }
  857. else
  858. {
  859. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  860. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  861. dispatch_async(globalLoggingQueue, ^{
  862. dispatch_async(loggerQueue, block);
  863. });
  864. }
  865. }
  866. - (void)clearColorsForTag:(id <NSCopying>)tag
  867. {
  868. NSAssert([(id <NSObject>)tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag");
  869. dispatch_block_t block = ^{ @autoreleasepool {
  870. [colorProfilesDict removeObjectForKey:tag];
  871. }};
  872. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  873. // For documentation please refer to the DDAbstractLogger implementation.
  874. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  875. if (currentQueue == loggerQueue)
  876. {
  877. block();
  878. }
  879. else
  880. {
  881. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  882. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  883. dispatch_async(globalLoggingQueue, ^{
  884. dispatch_async(loggerQueue, block);
  885. });
  886. }
  887. }
  888. - (void)clearColorsForAllFlags
  889. {
  890. dispatch_block_t block = ^{ @autoreleasepool {
  891. [colorProfilesArray removeAllObjects];
  892. }};
  893. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  894. // For documentation please refer to the DDAbstractLogger implementation.
  895. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  896. if (currentQueue == loggerQueue)
  897. {
  898. block();
  899. }
  900. else
  901. {
  902. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  903. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  904. dispatch_async(globalLoggingQueue, ^{
  905. dispatch_async(loggerQueue, block);
  906. });
  907. }
  908. }
  909. - (void)clearColorsForAllTags
  910. {
  911. dispatch_block_t block = ^{ @autoreleasepool {
  912. [colorProfilesDict removeAllObjects];
  913. }};
  914. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  915. // For documentation please refer to the DDAbstractLogger implementation.
  916. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  917. if (currentQueue == loggerQueue)
  918. {
  919. block();
  920. }
  921. else
  922. {
  923. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  924. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  925. dispatch_async(globalLoggingQueue, ^{
  926. dispatch_async(loggerQueue, block);
  927. });
  928. }
  929. }
  930. - (void)clearAllColors
  931. {
  932. dispatch_block_t block = ^{ @autoreleasepool {
  933. [colorProfilesArray removeAllObjects];
  934. [colorProfilesDict removeAllObjects];
  935. }};
  936. // The design of the setter logic below is taken from the DDAbstractLogger implementation.
  937. // For documentation please refer to the DDAbstractLogger implementation.
  938. dispatch_queue_t currentQueue = dispatch_get_current_queue();
  939. if (currentQueue == loggerQueue)
  940. {
  941. block();
  942. }
  943. else
  944. {
  945. dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
  946. NSAssert(currentQueue != globalLoggingQueue, @"Core architecture requirement failure");
  947. dispatch_async(globalLoggingQueue, ^{
  948. dispatch_async(loggerQueue, block);
  949. });
  950. }
  951. }
  952. - (void)logMessage:(DDLogMessage *)logMessage
  953. {
  954. if (!isaTTY) return;
  955. NSString *logMsg = logMessage->logMsg;
  956. BOOL isFormatted = NO;
  957. if (formatter)
  958. {
  959. logMsg = [formatter formatLogMessage:logMessage];
  960. isFormatted = logMsg != logMessage->logMsg;
  961. }
  962. if (logMsg)
  963. {
  964. // Search for a color profile associated with the log message
  965. DDTTYLoggerColorProfile *colorProfile = nil;
  966. if (colorsEnabled)
  967. {
  968. if (logMessage->tag)
  969. {
  970. colorProfile = [colorProfilesDict objectForKey:logMessage->tag];
  971. }
  972. if (colorProfile == nil)
  973. {
  974. for (DDTTYLoggerColorProfile *cp in colorProfilesArray)
  975. {
  976. if ((logMessage->logFlag & cp->mask) && (logMessage->logContext == cp->context))
  977. {
  978. colorProfile = cp;
  979. break;
  980. }
  981. }
  982. }
  983. }
  984. // Convert log message to C string.
  985. //
  986. // We use the stack instead of the heap for speed if possible.
  987. // But we're extra cautious to avoid a stack overflow.
  988. NSUInteger msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  989. const BOOL useStack = msgLen < (1024 * 4);
  990. char msgStack[useStack ? (msgLen + 1) : 1]; // Analyzer doesn't like zero-size array, hence the 1
  991. char *msg = useStack ? msgStack : (char *)malloc(msgLen + 1);
  992. [logMsg getCString:msg maxLength:(msgLen + 1) encoding:NSUTF8StringEncoding];
  993. // Write the log message to STDERR
  994. if (isFormatted)
  995. {
  996. // The log message has already been formatted.
  997. struct iovec v[4];
  998. if (colorProfile)
  999. {
  1000. v[0].iov_base = colorProfile->fgCode;
  1001. v[0].iov_len = colorProfile->fgCodeLen;
  1002. v[3].iov_base = colorProfile->resetCode;
  1003. v[3].iov_len = colorProfile->resetCodeLen;
  1004. }
  1005. else
  1006. {
  1007. v[0].iov_base = "";
  1008. v[0].iov_len = 0;
  1009. v[3].iov_base = "";
  1010. v[3].iov_len = 0;
  1011. }
  1012. v[1].iov_base = (char *)msg;
  1013. v[1].iov_len = msgLen;
  1014. v[2].iov_base = "\n";
  1015. v[2].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
  1016. writev(STDERR_FILENO, v, 4);
  1017. }
  1018. else
  1019. {
  1020. // The log message is unformatted, so apply standard NSLog style formatting.
  1021. int len;
  1022. // Calculate timestamp.
  1023. // The technique below is faster than using NSDateFormatter.
  1024. NSDateComponents *components = [calendar components:calendarUnitFlags fromDate:logMessage->timestamp];
  1025. NSTimeInterval epoch = [logMessage->timestamp timeIntervalSinceReferenceDate];
  1026. int milliseconds = (int)((epoch - floor(epoch)) * 1000);
  1027. char ts[24];
  1028. len = snprintf(ts, 24, "%04ld-%02ld-%02ld %02ld:%02ld:%02ld:%03d", // yyyy-MM-dd HH:mm:ss:SSS
  1029. (long)components.year,
  1030. (long)components.month,
  1031. (long)components.day,
  1032. (long)components.hour,
  1033. (long)components.minute,
  1034. (long)components.second, milliseconds);
  1035. size_t tsLen = MIN(24-1, len);
  1036. // Calculate thread ID
  1037. //
  1038. // How many characters do we need for the thread id?
  1039. // logMessage->machThreadID is of type mach_port_t, which is an unsigned int.
  1040. //
  1041. // 1 hex char = 4 bits
  1042. // 8 hex chars for 32 bit, plus ending '\0' = 9
  1043. char tid[9];
  1044. len = snprintf(tid, 9, "%x", logMessage->machThreadID);
  1045. size_t tidLen = MIN(9-1, len);
  1046. // Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg
  1047. struct iovec v[12];
  1048. if (colorProfile)
  1049. {
  1050. v[0].iov_base = colorProfile->fgCode;
  1051. v[0].iov_len = colorProfile->fgCodeLen;
  1052. v[11].iov_base = colorProfile->resetCode;
  1053. v[11].iov_len = colorProfile->resetCodeLen;
  1054. }
  1055. else
  1056. {
  1057. v[0].iov_base = "";
  1058. v[0].iov_len = 0;
  1059. v[11].iov_base = "";
  1060. v[11].iov_len = 0;
  1061. }
  1062. v[1].iov_base = ts;
  1063. v[1].iov_len = tsLen;
  1064. v[2].iov_base = " ";
  1065. v[2].iov_len = 1;
  1066. v[3].iov_base = app;
  1067. v[3].iov_len = appLen;
  1068. v[4].iov_base = "[";
  1069. v[4].iov_len = 1;
  1070. v[5].iov_base = pid;
  1071. v[5].iov_len = pidLen;
  1072. v[6].iov_base = ":";
  1073. v[6].iov_len = 1;
  1074. v[7].iov_base = tid;
  1075. v[7].iov_len = MIN((size_t)8, tidLen); // snprintf doesn't return what you might think
  1076. v[8].iov_base = "] ";
  1077. v[8].iov_len = 2;
  1078. v[9].iov_base = (char *)msg;
  1079. v[9].iov_len = msgLen;
  1080. v[10].iov_base = "\n";
  1081. v[10].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
  1082. writev(STDERR_FILENO, v, 12);
  1083. }
  1084. if (!useStack) {
  1085. free(msg);
  1086. }
  1087. }
  1088. }
  1089. - (NSString *)loggerName
  1090. {
  1091. return @"cocoa.lumberjack.ttyLogger";
  1092. }
  1093. @end
  1094. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1095. @implementation DDTTYLoggerColorProfile
  1096. - (id)initWithForegroundColor:(OSColor *)fgColor backgroundColor:(OSColor *)bgColor flag:(int)aMask context:(int)ctxt
  1097. {
  1098. if ((self = [super init]))
  1099. {
  1100. mask = aMask;
  1101. context = ctxt;
  1102. CGFloat r, g, b;
  1103. if (fgColor)
  1104. {
  1105. [DDTTYLogger getRed:&r green:&g blue:&b fromColor:fgColor];
  1106. fg_r = (uint8_t)(r * 255.0f);
  1107. fg_g = (uint8_t)(g * 255.0f);
  1108. fg_b = (uint8_t)(b * 255.0f);
  1109. }
  1110. if (bgColor)
  1111. {
  1112. [DDTTYLogger getRed:&r green:&g blue:&b fromColor:bgColor];
  1113. bg_r = (uint8_t)(r * 255.0f);
  1114. bg_g = (uint8_t)(g * 255.0f);
  1115. bg_b = (uint8_t)(b * 255.0f);
  1116. }
  1117. if (fgColor && isaColorTTY)
  1118. {
  1119. // Map foreground color to closest available shell color
  1120. fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor];
  1121. fgCodeRaw = [codes_fg objectAtIndex:fgCodeIndex];
  1122. NSString *escapeSeq = @"\033[";
  1123. NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  1124. NSUInteger len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  1125. [escapeSeq getCString:(fgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding];
  1126. [fgCodeRaw getCString:(fgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding];
  1127. fgCodeLen = len1+len2;
  1128. }
  1129. else if (fgColor && isaXcodeColorTTY)
  1130. {
  1131. // Convert foreground color to color code sequence
  1132. const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
  1133. int result = snprintf(fgCode, 24, "%sfg%u,%u,%u;", escapeSeq, fg_r, fg_g, fg_b);
  1134. fgCodeLen = MIN(result, (24-1));
  1135. }
  1136. else
  1137. {
  1138. // No foreground color or no color support
  1139. fgCode[0] = '\0';
  1140. fgCodeLen = 0;
  1141. }
  1142. if (bgColor && isaColorTTY)
  1143. {
  1144. // Map background color to closest available shell color
  1145. bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor];
  1146. bgCodeRaw = [codes_bg objectAtIndex:bgCodeIndex];
  1147. NSString *escapeSeq = @"\033[";
  1148. NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  1149. NSUInteger len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  1150. [escapeSeq getCString:(bgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding];
  1151. [bgCodeRaw getCString:(bgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding];
  1152. bgCodeLen = len1+len2;
  1153. }
  1154. else if (bgColor && isaXcodeColorTTY)
  1155. {
  1156. // Convert background color to color code sequence
  1157. const char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
  1158. int result = snprintf(bgCode, 24, "%sbg%u,%u,%u;", escapeSeq, bg_r, bg_g, bg_b);
  1159. bgCodeLen = MIN(result, (24-1));
  1160. }
  1161. else
  1162. {
  1163. // No background color or no color support
  1164. bgCode[0] = '\0';
  1165. bgCodeLen = 0;
  1166. }
  1167. if (isaColorTTY)
  1168. {
  1169. resetCodeLen = snprintf(resetCode, 8, "\033[0m");
  1170. }
  1171. else if (isaXcodeColorTTY)
  1172. {
  1173. resetCodeLen = snprintf(resetCode, 8, XCODE_COLORS_RESET);
  1174. }
  1175. else
  1176. {
  1177. resetCode[0] = '\0';
  1178. resetCodeLen = 0;
  1179. }
  1180. }
  1181. return self;
  1182. }
  1183. - (NSString *)description
  1184. {
  1185. return [NSString stringWithFormat:
  1186. @"<DDTTYLoggerColorProfile: %p mask:%i ctxt:%i fg:%u,%u,%u bg:%u,%u,%u fgCode:%@ bgCode:%@>",
  1187. self, mask, context, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b, fgCodeRaw, bgCodeRaw];
  1188. }
  1189. @end