#import "DDTTYLogger.h"
#import <unistd.h>
#import <sys/uio.h>
/**
* Welcome to Cocoa Lumberjack!
*
* The project page has a wealth of documentation
if you have
any questions.
* https://github.com/CocoaLumberjack/CocoaLumberjack
*
* If you're new to the project you may wish to read the "Getting Started" wiki.
* https://github.com/CocoaLumberjack/CocoaLumberjack/wiki/GettingStarted
**/
#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC.
Use -fobjc-arc
flag (or convert project to ARC
).
#endif
// We probably shouldn't be using DDLog() statements within the DDLog implementation.
// But we still want to leave our
log statements
for any future debugging,
// and to allow other developers to
trace the implementation
(which is a great learning tool
).
//
// So we use primitive logging macros around NSLog.
// We maintain the NS prefix on the macros to be explicit about the fact that we're using NSLog.
#define LOG_LEVEL 2
#define NSLogError(frmt, ...) do{ if(LOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogWarn(frmt, ...) do{ if(LOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogInfo(frmt, ...) do{ if(LOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogDebug(frmt, ...) do{ if(LOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogVerbose(frmt, ...) do{ if(LOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)
// Xcode does NOT natively support colors in the Xcode debugging console.
// You'll need to install the XcodeColors plugin to see colors in the Xcode console.
// https://github.com/robbiehanson/XcodeColors
//
// The following
is documentation from the XcodeColors project:
//
//
// How to apply color formatting to your
log statements:
//
// To
set the foreground color:
// Insert the ESCAPE_SEQ into your
string, followed by "fg124,
12,
255;" where r=
124, g=
12, b=
255.
//
// To
set the background color:
// Insert the ESCAPE_SEQ into your
string, followed by "bg12,
24,
36;" where r=
12, g=
24, b=
36.
//
// To
reset the foreground color
(to default value
):
// Insert the ESCAPE_SEQ into your
string, followed by "fg;"
//
// To
reset the background color
(to default value
):
// Insert the ESCAPE_SEQ into your
string, followed by "bg;"
//
// To
reset the foreground and background color
(to default values
) in one operation:
// Insert the ESCAPE_SEQ into your
string, followed by ";"
#define XCODE_COLORS_ESCAPE_SEQ "\033["
#define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE_SEQ "fg;" //
Clear any foreground color
#define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE_SEQ "bg;" //
Clear any background color
#define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE_SEQ ";" //
Clear any foreground or background color
// Some simple defines to make life easier on ourself
#if TARGET_OS_IPHONE
#define MakeColor(r, g, b) [UIColor colorWithRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]
#else
#define MakeColor(r, g, b) [NSColor colorWithCalibratedRed:(r/255.0f) green:(g/255.0f) blue:(b/255.0f) alpha:1.0f]
#endif
#if TARGET_OS_IPHONE
#define OSColor UIColor
#else
#define OSColor NSColor
#endif
//
If running in a shell, not
all RGB colors will be supported.
// In this case we automatically map to the closest available color.
// In order to provide this mapping, we have a hard-coded
set of the standard RGB values available in the shell.
// However, not every shell
is the same, and Apple likes to think different even when it comes to shell colors.
//
// Map to standard Terminal.app colors (1), or
// map to standard xterm colors (0).
#define MAP_TO_TERMINAL_APP_COLORS 1
@interface DDTTYLoggerColorProfile : NSObject {
@public
int mask;
int context;
uint8_t fg_r;
uint8_t fg_g;
uint8_t fg_b;
uint8_t bg_r;
uint8_t bg_g;
uint8_t bg_b;
NSUInteger fgCodeIndex;
NSString *fgCodeRaw;
NSUInteger bgCodeIndex;
NSString *bgCodeRaw;
size_t fgCodeLen;
size_t bgCodeLen;
size_t resetCodeLen;
}
-
(instancetype
)initWithForegroundColor:
(OSColor *
)fgColor backgroundColor:
(OSColor *
)bgColor
flag:
(int
)mask context:
(int
)ctxt;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation DDTTYLogger
static BOOL isaColorTTY;
static BOOL isaColor256TTY;
static BOOL isaXcodeColorTTY;
static NSArray *codes_fg = nil;
static NSArray *codes_bg = nil;
static NSArray *colors = nil;
static DDTTYLogger *sharedInstance;
/**
* Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 16 color mode.
*
* This method
is used when the application
is running from within a shell that only supports
16 color mode.
* This method
is not invoked
if the application
is running within Xcode, or via normal UI app launch.
**/
+ (void)initialize_colors_16
{
if (codes_fg || codes_bg || colors) return;
NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:16];
// In a standard shell only 16 colors are supported.
//
//
More information about ansi escape codes can be found online.
// http://en.wikipedia.org/wiki/ANSI_escape_code
[m_codes_fg addObject:@"30m"]; // normal - black
[m_codes_fg addObject:@"31m"]; // normal - red
[m_codes_fg addObject:@"32m"]; // normal - green
[m_codes_fg addObject:@"33m"]; // normal - yellow
[m_codes_fg addObject:@"34m"]; // normal - blue
[m_codes_fg addObject:@"35m"]; // normal - magenta
[m_codes_fg addObject:@"36m"]; // normal - cyan
[m_codes_fg addObject:@"37m"
]; // normal -
gray
[m_codes_fg addObject:@"1;30m"]; // bright - darkgray
[m_codes_fg addObject:@"1;31m"]; // bright - red
[m_codes_fg addObject:@"1;32m"]; // bright - green
[m_codes_fg addObject:@"1;33m"]; // bright - yellow
[m_codes_fg addObject:@"1;34m"]; // bright - blue
[m_codes_fg addObject:@"1;35m"]; // bright - magenta
[m_codes_fg addObject:@"1;36m"]; // bright - cyan
[m_codes_fg addObject:@"1;37m"]; // bright - white
[m_codes_bg addObject:@"40m"]; // normal - black
[m_codes_bg addObject:@"41m"]; // normal - red
[m_codes_bg addObject:@"42m"]; // normal - green
[m_codes_bg addObject:@"43m"]; // normal - yellow
[m_codes_bg addObject:@"44m"]; // normal - blue
[m_codes_bg addObject:@"45m"]; // normal - magenta
[m_codes_bg addObject:@"46m"]; // normal - cyan
[m_codes_bg addObject:@"47m"
]; // normal -
gray
[m_codes_bg addObject:@"1;40m"]; // bright - darkgray
[m_codes_bg addObject:@"1;41m"]; // bright - red
[m_codes_bg addObject:@"1;42m"]; // bright - green
[m_codes_bg addObject:@"1;43m"]; // bright - yellow
[m_codes_bg addObject:@"1;44m"]; // bright - blue
[m_codes_bg addObject:@"1;45m"]; // bright - magenta
[m_codes_bg addObject:@"1;46m"]; // bright - cyan
[m_codes_bg addObject:@"1;47m"]; // bright - white
#if MAP_TO_TERMINAL_APP_COLORS
// Standard Terminal.app colors:
//
// These are the default colors used by Apple's Terminal.app.
[m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black
[m_colors addObject:MakeColor(194, 54, 33)]; // normal - red
[m_colors addObject:MakeColor( 37, 188, 36)]; // normal - green
[m_colors addObject:MakeColor(173, 173, 39)]; // normal - yellow
[m_colors addObject:MakeColor( 73, 46, 225)]; // normal - blue
[m_colors addObject:MakeColor(211, 56, 211)]; // normal - magenta
[m_colors addObject:MakeColor( 51, 187, 200)]; // normal - cyan
[m_colors addObject:MakeColor
(203,
204,
205)]; // normal -
gray
[m_colors addObject:MakeColor(129, 131, 131)]; // bright - darkgray
[m_colors addObject:MakeColor(252, 57, 31)]; // bright - red
[m_colors addObject:MakeColor( 49, 231, 34)]; // bright - green
[m_colors addObject:MakeColor(234, 236, 35)]; // bright - yellow
[m_colors addObject:MakeColor( 88, 51, 255)]; // bright - blue
[m_colors addObject:MakeColor(249, 53, 248)]; // bright - magenta
[m_colors addObject:MakeColor( 20, 240, 240)]; // bright - cyan
[m_colors addObject:MakeColor(233, 235, 235)]; // bright - white
#else
// Standard xterm colors:
//
// These are the default colors used by most xterm shells.
[m_colors addObject:MakeColor( 0, 0, 0)]; // normal - black
[m_colors addObject:MakeColor(205, 0, 0)]; // normal - red
[m_colors addObject:MakeColor( 0, 205, 0)]; // normal - green
[m_colors addObject:MakeColor(205, 205, 0)]; // normal - yellow
[m_colors addObject:MakeColor( 0, 0, 238)]; // normal - blue
[m_colors addObject:MakeColor(205, 0, 205)]; // normal - magenta
[m_colors addObject:MakeColor( 0, 205, 205)]; // normal - cyan
[m_colors addObject:MakeColor
(229,
229,
229)]; // normal -
gray
[m_colors addObject:MakeColor(127, 127, 127)]; // bright - darkgray
[m_colors addObject:MakeColor(255, 0, 0)]; // bright - red
[m_colors addObject:MakeColor( 0, 255, 0)]; // bright - green
[m_colors addObject:MakeColor(255, 255, 0)]; // bright - yellow
[m_colors addObject:MakeColor( 92, 92, 255)]; // bright - blue
[m_colors addObject:MakeColor(255, 0, 255)]; // bright - magenta
[m_colors addObject:MakeColor( 0, 255, 255)]; // bright - cyan
[m_colors addObject:MakeColor(255, 255, 255)]; // bright - white
#endif
codes_fg = [m_codes_fg copy];
codes_bg = [m_codes_bg copy];
colors = [m_colors copy];
NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
}
/**
* Initializes the colors array, as well as the codes_fg and codes_bg arrays, for 256 color mode.
*
* This method
is used when the application
is running from within a shell that supports
256 color mode.
* This method
is not invoked
if the application
is running within Xcode, or via normal UI app launch.
**/
+ (void)initialize_colors_256
{
if (codes_fg || codes_bg || colors) return;
NSMutableArray *m_codes_fg = [NSMutableArray arrayWithCapacity:(256-16)];
NSMutableArray *m_codes_bg = [NSMutableArray arrayWithCapacity:(256-16)];
NSMutableArray *m_colors = [NSMutableArray arrayWithCapacity:(256-16)];
#if MAP_TO_TERMINAL_APP_COLORS
// Standard Terminal.app colors:
//
// These are the colors the Terminal.app uses in xterm-256color mode.
// In this mode, the terminal supports 256 different colors, specified by 256 color codes.
//
// The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
// These are actually configurable, and thus we ignore them for the purposes of mapping,
// as we can't rely on them being constant. They are largely duplicated anyway.
//
// The next 216 color codes are designed to run the spectrum, with several shades of every color.
//
While the color codes are standardized, the actual RGB values
for each color code
is not.
// Apple's Terminal.app uses different RGB values from that of a standard xterm.
// Apple's choices in colors are designed to be a little nicer on the eyes.
//
// The last 24 color codes represent a grayscale.
//
// Unfortunately, unlike the standard xterm color chart,
// Apple's RGB values cannot be calculated using a simple formula
(at least not that
I know of
).
// Also,
I don't know of
any ways to programmatically query the shell
for the RGB values.
// So this big giant color chart had to be made by hand.
//
//
More information about ansi escape codes can be found online.
// http://en.wikipedia.org/wiki/ANSI_escape_code
// Colors
[m_colors addObject:MakeColor( 47, 49, 49)];
[m_colors addObject:MakeColor( 60, 42, 144)];
[m_colors addObject:MakeColor( 66, 44, 183)];
[m_colors addObject:MakeColor( 73, 46, 222)];
[m_colors addObject:MakeColor( 81, 50, 253)];
[m_colors addObject:MakeColor( 88, 51, 255)];
[m_colors addObject:MakeColor( 42, 128, 37)];
[m_colors addObject:MakeColor( 42, 127, 128)];
[m_colors addObject:MakeColor( 44, 126, 169)];
[m_colors addObject:MakeColor( 56, 125, 209)];
[m_colors addObject:MakeColor( 59, 124, 245)];
[m_colors addObject:MakeColor( 66, 123, 255)];
[m_colors addObject:MakeColor( 51, 163, 41)];
[m_colors addObject:MakeColor( 39, 162, 121)];
[m_colors addObject:MakeColor( 42, 161, 162)];
[m_colors addObject:MakeColor( 53, 160, 202)];
[m_colors addObject:MakeColor( 45, 159, 240)];
[m_colors addObject:MakeColor( 58, 158, 255)];
[m_colors addObject:MakeColor( 31, 196, 37)];
[m_colors addObject:MakeColor( 48, 196, 115)];
[m_colors addObject:MakeColor( 39, 195, 155)];
[m_colors addObject:MakeColor( 49, 195, 195)];
[m_colors addObject:MakeColor( 32, 194, 235)];
[m_colors addObject:MakeColor( 53, 193, 255)];
[m_colors addObject:MakeColor( 50, 229, 35)];
[m_colors addObject:MakeColor( 40, 229, 109)];
[m_colors addObject:MakeColor( 27, 229, 149)];
[m_colors addObject:MakeColor( 49, 228, 189)];
[m_colors addObject:MakeColor( 33, 228, 228)];
[m_colors addObject:MakeColor( 53, 227, 255)];
[m_colors addObject:MakeColor( 27, 254, 30)];
[m_colors addObject:MakeColor( 30, 254, 103)];
[m_colors addObject:MakeColor( 45, 254, 143)];
[m_colors addObject:MakeColor( 38, 253, 182)];
[m_colors addObject:MakeColor( 38, 253, 222)];
[m_colors addObject:MakeColor( 42, 253, 252)];
[m_colors addObject:MakeColor(140, 48, 40)];
[m_colors addObject:MakeColor(136, 51, 136)];
[m_colors addObject:MakeColor(135, 52, 177)];
[m_colors addObject:MakeColor(134, 52, 217)];
[m_colors addObject:MakeColor(135, 56, 248)];
[m_colors addObject:MakeColor(134, 53, 255)];
[m_colors addObject:MakeColor(125, 125, 38)];
[m_colors addObject:MakeColor(124, 125, 125)];
[m_colors addObject:MakeColor(122, 124, 166)];
[m_colors addObject:MakeColor(123, 124, 207)];
[m_colors addObject:MakeColor(123, 122, 247)];
[m_colors addObject:MakeColor(124, 121, 255)];
[m_colors addObject:MakeColor(119, 160, 35)];
[m_colors addObject:MakeColor(117, 160, 120)];
[m_colors addObject:MakeColor(117, 160, 160)];
[m_colors addObject:MakeColor(115, 159, 201)];
[m_colors addObject:MakeColor(116, 158, 240)];
[m_colors addObject:MakeColor(117, 157, 255)];
[m_colors addObject:MakeColor(113, 195, 39)];
[m_colors addObject:MakeColor(110, 194, 114)];
[m_colors addObject:MakeColor(111, 194, 154)];
[m_colors addObject:MakeColor(108, 194, 194)];
[m_colors addObject:MakeColor(109, 193, 234)];
[m_colors addObject:MakeColor(108, 192, 255)];
[m_colors addObject:MakeColor(105, 228, 30)];
[m_colors addObject:MakeColor(103, 228, 109)];
[m_colors addObject:MakeColor(105, 228, 148)];
[m_colors addObject:MakeColor(100, 227, 188)];
[m_colors addObject:MakeColor( 99, 227, 227)];
[m_colors addObject:MakeColor( 99, 226, 253)];
[m_colors addObject:MakeColor( 92, 253, 34)];
[m_colors addObject:MakeColor( 96, 253, 103)];
[m_colors addObject:MakeColor( 97, 253, 142)];
[m_colors addObject:MakeColor( 88, 253, 182)];
[m_colors addObject:MakeColor( 93, 253, 221)];
[m_colors addObject:MakeColor( 88, 254, 251)];
[m_colors addObject:MakeColor(177, 53, 34)];
[m_colors addObject:MakeColor(174, 54, 131)];
[m_colors addObject:MakeColor(172, 55, 172)];
[m_colors addObject:MakeColor(171, 57, 213)];
[m_colors addObject:MakeColor(170, 55, 249)];
[m_colors addObject:MakeColor(170, 57, 255)];
[m_colors addObject:MakeColor(165, 123, 37)];
[m_colors addObject:MakeColor(163, 123, 123)];
[m_colors addObject:MakeColor(162, 123, 164)];
[m_colors addObject:MakeColor(161, 122, 205)];
[m_colors addObject:MakeColor(161, 121, 241)];
[m_colors addObject:MakeColor(161, 121, 255)];
[m_colors addObject:MakeColor(158, 159, 33)];
[m_colors addObject:MakeColor(157, 158, 118)];
[m_colors addObject:MakeColor(157, 158, 159)];
[m_colors addObject:MakeColor(155, 157, 199)];
[m_colors addObject:MakeColor(155, 157, 239)];
[m_colors addObject:MakeColor(154, 156, 255)];
[m_colors addObject:MakeColor(152, 193, 40)];
[m_colors addObject:MakeColor(151, 193, 113)];
[m_colors addObject:MakeColor(150, 193, 153)];
[m_colors addObject:MakeColor(150, 192, 193)];
[m_colors addObject:MakeColor(148, 192, 232)];
[m_colors addObject:MakeColor(149, 191, 253)];
[m_colors addObject:MakeColor(146, 227, 28)];
[m_colors addObject:MakeColor(144, 227, 108)];
[m_colors addObject:MakeColor(144, 227, 147)];
[m_colors addObject:MakeColor(144, 227, 187)];
[m_colors addObject:MakeColor(142, 226, 227)];
[m_colors addObject:MakeColor(142, 225, 252)];
[m_colors addObject:MakeColor(138, 253, 36)];
[m_colors addObject:MakeColor(137, 253, 102)];
[m_colors addObject:MakeColor(136, 253, 141)];
[m_colors addObject:MakeColor(138, 254, 181)];
[m_colors addObject:MakeColor(135, 255, 220)];
[m_colors addObject:MakeColor(133, 255, 250)];
[m_colors addObject:MakeColor(214, 57, 30)];
[m_colors addObject:MakeColor(211, 59, 126)];
[m_colors addObject:MakeColor(209, 57, 168)];
[m_colors addObject:MakeColor(208, 55, 208)];
[m_colors addObject:MakeColor(207, 58, 247)];
[m_colors addObject:MakeColor(206, 61, 255)];
[m_colors addObject:MakeColor(204, 121, 32)];
[m_colors addObject:MakeColor(202, 121, 121)];
[m_colors addObject:MakeColor(201, 121, 161)];
[m_colors addObject:MakeColor(200, 120, 202)];
[m_colors addObject:MakeColor(200, 120, 241)];
[m_colors addObject:MakeColor(198, 119, 255)];
[m_colors addObject:MakeColor(198, 157, 37)];
[m_colors addObject:MakeColor(196, 157, 116)];
[m_colors addObject:MakeColor(195, 156, 157)];
[m_colors addObject:MakeColor(195, 156, 197)];
[m_colors addObject:MakeColor(194, 155, 236)];
[m_colors addObject:MakeColor(193, 155, 255)];
[m_colors addObject:MakeColor(191, 192, 36)];
[m_colors addObject:MakeColor(190, 191, 112)];
[m_colors addObject:MakeColor(189, 191, 152)];
[m_colors addObject:MakeColor(189, 191, 191)];
[m_colors addObject:MakeColor(188, 190, 230)];
[m_colors addObject:MakeColor(187, 190, 253)];
[m_colors addObject:MakeColor(185, 226, 28)];
[m_colors addObject:MakeColor(184, 226, 106)];
[m_colors addObject:MakeColor(183, 225, 146)];
[m_colors addObject:MakeColor(183, 225, 186)];
[m_colors addObject:MakeColor(182, 225, 225)];
[m_colors addObject:MakeColor(181, 224, 252)];
[m_colors addObject:MakeColor(178, 255, 35)];
[m_colors addObject:MakeColor(178, 255, 101)];
[m_colors addObject:MakeColor(177, 254, 141)];
[m_colors addObject:MakeColor(176, 254, 180)];
[m_colors addObject:MakeColor(176, 254, 220)];
[m_colors addObject:MakeColor(175, 253, 249)];
[m_colors addObject:MakeColor(247, 56, 30)];
[m_colors addObject:MakeColor(245, 57, 122)];
[m_colors addObject:MakeColor(243, 59, 163)];
[m_colors addObject:MakeColor(244, 60, 204)];
[m_colors addObject:MakeColor(242, 59, 241)];
[m_colors addObject:MakeColor(240, 55, 255)];
[m_colors addObject:MakeColor(241, 119, 36)];
[m_colors addObject:MakeColor(240, 120, 118)];
[m_colors addObject:MakeColor(238, 119, 158)];
[m_colors addObject:MakeColor(237, 119, 199)];
[m_colors addObject:MakeColor(237, 118, 238)];
[m_colors addObject:MakeColor(236, 118, 255)];
[m_colors addObject:MakeColor(235, 154, 36)];
[m_colors addObject:MakeColor(235, 154, 114)];
[m_colors addObject:MakeColor(234, 154, 154)];
[m_colors addObject:MakeColor(232, 154, 194)];
[m_colors addObject:MakeColor(232, 153, 234)];
[m_colors addObject:MakeColor(232, 153, 255)];
[m_colors addObject:MakeColor(230, 190, 30)];
[m_colors addObject:MakeColor(229, 189, 110)];
[m_colors addObject:MakeColor(228, 189, 150)];
[m_colors addObject:MakeColor(227, 189, 190)];
[m_colors addObject:MakeColor(227, 189, 229)];
[m_colors addObject:MakeColor(226, 188, 255)];
[m_colors addObject:MakeColor(224, 224, 35)];
[m_colors addObject:MakeColor(223, 224, 105)];
[m_colors addObject:MakeColor(222, 224, 144)];
[m_colors addObject:MakeColor(222, 223, 184)];
[m_colors addObject:MakeColor(222, 223, 224)];
[m_colors addObject:MakeColor(220, 223, 253)];
[m_colors addObject:MakeColor(217, 253, 28)];
[m_colors addObject:MakeColor(217, 253, 99)];
[m_colors addObject:MakeColor(216, 252, 139)];
[m_colors addObject:MakeColor(216, 252, 179)];
[m_colors addObject:MakeColor(215, 252, 218)];
[m_colors addObject:MakeColor(215, 251, 250)];
[m_colors addObject:MakeColor(255, 61, 30)];
[m_colors addObject:MakeColor(255, 60, 118)];
[m_colors addObject:MakeColor(255, 58, 159)];
[m_colors addObject:MakeColor(255, 56, 199)];
[m_colors addObject:MakeColor(255, 55, 238)];
[m_colors addObject:MakeColor(255, 59, 255)];
[m_colors addObject:MakeColor(255, 117, 29)];
[m_colors addObject:MakeColor(255, 117, 115)];
[m_colors addObject:MakeColor(255, 117, 155)];
[m_colors addObject:MakeColor(255, 117, 195)];
[m_colors addObject:MakeColor(255, 116, 235)];
[m_colors addObject:MakeColor(254, 116, 255)];
[m_colors addObject:MakeColor(255, 152, 27)];
[m_colors addObject:MakeColor(255, 152, 111)];
[m_colors addObject:MakeColor(254, 152, 152)];
[m_colors addObject:MakeColor(255, 152, 192)];
[m_colors addObject:MakeColor(254, 151, 231)];
[m_colors addObject:MakeColor(253, 151, 253)];
[m_colors addObject:MakeColor(255, 187, 33)];
[m_colors addObject:MakeColor(253, 187, 107)];
[m_colors addObject:MakeColor(252, 187, 148)];
[m_colors addObject:MakeColor(253, 187, 187)];
[m_colors addObject:MakeColor(254, 187, 227)];
[m_colors addObject:MakeColor(252, 186, 252)];
[m_colors addObject:MakeColor(252, 222, 34)];
[m_colors addObject:MakeColor(251, 222, 103)];
[m_colors addObject:MakeColor(251, 222, 143)];
[m_colors addObject:MakeColor(250, 222, 182)];
[m_colors addObject:MakeColor(251, 221, 222)];
[m_colors addObject:MakeColor(252, 221, 252)];
[m_colors addObject:MakeColor(251, 252, 15)];
[m_colors addObject:MakeColor(251, 252, 97)];
[m_colors addObject:MakeColor(249, 252, 137)];
[m_colors addObject:MakeColor(247, 252, 177)];
[m_colors addObject:MakeColor(247, 253, 217)];
[m_colors addObject:MakeColor(254, 255, 255)];
// Grayscale
[m_colors addObject:MakeColor( 52, 53, 53)];
[m_colors addObject:MakeColor( 57, 58, 59)];
[m_colors addObject:MakeColor( 66, 67, 67)];
[m_colors addObject:MakeColor( 75, 76, 76)];
[m_colors addObject:MakeColor( 83, 85, 85)];
[m_colors addObject:MakeColor( 92, 93, 94)];
[m_colors addObject:MakeColor(101, 102, 102)];
[m_colors addObject:MakeColor(109, 111, 111)];
[m_colors addObject:MakeColor(118, 119, 119)];
[m_colors addObject:MakeColor(126, 127, 128)];
[m_colors addObject:MakeColor(134, 136, 136)];
[m_colors addObject:MakeColor(143, 144, 145)];
[m_colors addObject:MakeColor(151, 152, 153)];
[m_colors addObject:MakeColor(159, 161, 161)];
[m_colors addObject:MakeColor(167, 169, 169)];
[m_colors addObject:MakeColor(176, 177, 177)];
[m_colors addObject:MakeColor(184, 185, 186)];
[m_colors addObject:MakeColor(192, 193, 194)];
[m_colors addObject:MakeColor(200, 201, 202)];
[m_colors addObject:MakeColor(208, 209, 210)];
[m_colors addObject:MakeColor(216, 218, 218)];
[m_colors addObject:MakeColor(224, 226, 226)];
[m_colors addObject:MakeColor(232, 234, 234)];
[m_colors addObject:MakeColor(240, 242, 242)];
// Color codes
int index = 16;
while (index < 256)
{
[m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
[m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
index++;
}
#else
// Standard xterm colors:
//
// These are the colors xterm shells use in xterm-256color mode.
// In this mode, the shell supports 256 different colors, specified by 256 color codes.
//
// The first 16 color codes map to the original 16 color codes supported by the earlier xterm-color mode.
// These are generally configurable, and thus we ignore them for the purposes of mapping,
// as we can't rely on them being constant. They are largely duplicated anyway.
//
// The next 216 color codes are designed to run the spectrum, with several shades of every color.
// The last 24 color codes represent a grayscale.
//
//
While the color codes are standardized, the actual RGB values
for each color code
is not.
// However most standard xterms follow a well known color chart,
//
which can easily be calculated using the simple formula below.
//
//
More information about ansi escape codes can be found online.
// http://en.wikipedia.org/wiki/ANSI_escape_code
int index = 16;
int r; // red
int g; // green
int b; // blue
int ri; // r increment
int gi; // g increment
int bi; // b increment
// Calculate xterm colors (using standard algorithm)
int r = 0;
int g = 0;
int b = 0;
for (ri = 0; ri < 6; ri++)
{
r = (ri == 0) ? 0 : 95 + (40 * (ri - 1));
for (gi = 0; gi < 6; gi++)
{
g = (gi == 0) ? 0 : 95 + (40 * (gi - 1));
for (bi = 0; bi < 6; bi++)
{
b = (bi == 0) ? 0 : 95 + (40 * (bi - 1));
[m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
[m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
[m_colors addObject:MakeColor(r, g, b)];
index++;
}
}
}
// Calculate xterm grayscale (using standard algorithm)
r = 8;
g = 8;
b = 8;
while (index < 256)
{
[m_codes_fg addObject:[NSString stringWithFormat:@"38;5;%dm", index]];
[m_codes_bg addObject:[NSString stringWithFormat:@"48;5;%dm", index]];
[m_colors addObject:MakeColor(r, g, b)];
r += 10;
g += 10;
b += 10;
index++;
}
#endif
codes_fg = [m_codes_fg copy];
codes_bg = [m_codes_bg copy];
colors = [m_colors copy];
NSAssert([codes_fg count] == [codes_bg count], @"Invalid colors/codes array(s)");
NSAssert([codes_fg count] == [colors count], @"Invalid colors/codes array(s)");
}
+ (void)getRed:(CGFloat *)rPtr green:(CGFloat *)gPtr blue:(CGFloat *)bPtr fromColor:(OSColor *)color
{
#if TARGET_OS_IPHONE
// iOS
BOOL done = NO;
if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)])
{
done =
[color getRed:rPtr green:gPtr blue:bPtr alpha:
NULL];
}
if (!done)
{
// The method getRed:green:blue:alpha: was only available starting iOS 5.
// So in iOS 4 and earlier, we have to jump through hoops.
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(&pixel, 1, 1, 8, 4, rgbColorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaNoneSkipLast);
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, CGRectMake(0, 0, 1, 1));
if (rPtr) { *rPtr = pixel[0] / 255.0f; }
if (gPtr) { *gPtr = pixel[1] / 255.0f; }
if (bPtr) { *bPtr = pixel[2] / 255.0f; }
CGContextRelease(context);
CGColorSpaceRelease(rgbColorSpace);
}
#else
// Mac OS X
NSColor *safeColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
[safeColor getRed:rPtr green:gPtr blue:bPtr alpha:
NULL];
#endif
}
/**
* Maps the given color to the closest available color supported by the shell.
* The shell may support 256 colors, or only 16.
*
* This method loops through the known supported color
set, and calculates the closest color.
* The array index of that color, within the colors array,
is then returned.
* This array index may also be used as the index within the codes_fg and codes_bg arrays.
**/
+ (NSUInteger)codeIndexForColor:(OSColor *)inColor
{
CGFloat inR, inG, inB;
[self getRed:&inR green:&inG blue:&inB fromColor:inColor];
NSUInteger bestIndex = 0;
CGFloat lowestDistance = 100.0f;
for (OSColor *color in colors)
{
// Calculate Euclidean distance
(lower value means closer to given color
)
CGFloat r, g, b;
[self getRed:&r green:&g blue:&b fromColor:color];
#if CGFLOAT_IS_DOUBLE
CGFloat distance =
sqrt(pow
(r-inR,
2.0) + pow
(g-inG,
2.0) + pow
(b-inB,
2.0));
#else
CGFloat distance = sqrtf(powf(r-inR, 2.0f) + powf(g-inG, 2.0f) + powf(b-inB, 2.0f));
#endif
NSLogVerbose(@"DDTTYLogger: %3lu : %.3f,%.3f,%.3f & %.3f,%.3f,%.3f = %.6f",
(unsigned long
)i, inR, inG, inB, r, g, b, distance
);
if (distance < lowestDistance)
{
lowestDistance = distance;
NSLogVerbose(@"DDTTYLogger: New best index = %lu", (unsigned long)bestIndex);
}
}
return bestIndex;
}
/**
* The runtime sends initialize to each
class in a program exactly one time just before the
class,
* or
any class that inherits from it,
is sent its first message from within the program.
(Thus the
* method may never be invoked
if the
class is not used.
) The runtime sends the initialize message to
* classes in a thread-safe manner. Superclasses receive this message before their subclasses.
*
* This method may also be called directly (assumably by accident), hence the safety mechanism.
**/
+ (void)initialize
{
static BOOL initialized = NO;
if (!initialized)
{
initialized = YES;
char *term = getenv
("TERM"
);
if (term)
{
if (strcasestr
(term, "color"
) !=
NULL)
{
isaColorTTY = YES;
isaColor256TTY =
(strcasestr
(term, "
256"
) !=
NULL);
if (isaColor256TTY)
[self initialize_colors_256];
else
[self initialize_colors_16];
}
}
else
{
// Xcode does NOT natively support colors in the Xcode debugging console.
// You'll need to install the XcodeColors plugin to see colors in the Xcode console.
//
// PS - Please read the header file before diving into the source code.
char *xcode_colors = getenv
("XcodeColors"
);
if (xcode_colors &&
(strcmp(xcode_colors, "YES"
) ==
0))
{
isaXcodeColorTTY = YES;
}
}
NSLogInfo(@"DDTTYLogger: isaColorTTY = %@", (isaColorTTY ? @"YES" : @"NO"));
NSLogInfo(@"DDTTYLogger: isaColor256TTY: %@", (isaColor256TTY ? @"YES" : @"NO"));
NSLogInfo(@"DDTTYLogger: isaXcodeColorTTY: %@", (isaXcodeColorTTY ? @"YES" : @"NO"));
sharedInstance =
[[[self
class] alloc
] init
];
}
}
+ (instancetype)sharedInstance
{
return sharedInstance;
}
- (id)init
{
if (sharedInstance != nil)
{
return nil;
}
if ((self = [super init]))
{
calendar =
[NSCalendar autoupdatingCurrentCalendar
];
calendarUnitFlags = 0;
calendarUnitFlags |= NSYearCalendarUnit;
calendarUnitFlags |= NSMonthCalendarUnit;
calendarUnitFlags |= NSDayCalendarUnit;
calendarUnitFlags |= NSHourCalendarUnit;
calendarUnitFlags |= NSMinuteCalendarUnit;
calendarUnitFlags |= NSSecondCalendarUnit;
// Initialze
'app' variable
(char *
)
appName = [[NSProcessInfo processInfo] processName];
appLen = [appName lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
app =
(char *
)malloc
(appLen +
1);
if (app ==
NULL) return nil;
[appName getCString:app maxLength:(appLen+1) encoding:NSUTF8StringEncoding];
// Initialize
'pid' variable
(char *
)
processID = [NSString stringWithFormat:@"%i", (int)getpid()];
pidLen = [processID lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
pid =
(char *
)malloc
(pidLen +
1);
if (pid ==
NULL) return nil;
BOOL processedID = [processID getCString:pid maxLength:(pidLen+1) encoding:NSUTF8StringEncoding];
if (NO == processedID) return nil;
// Initialize color stuff
colorsEnabled = NO;
colorProfilesArray = [[NSMutableArray alloc] initWithCapacity:8];
colorProfilesDict = [[NSMutableDictionary alloc] initWithCapacity:8];
}
return self;
}
- (void)loadDefaultColorProfiles
{
[self setForegroundColor:MakeColor(214, 57, 30) backgroundColor:nil forFlag:LOG_FLAG_ERROR];
[self setForegroundColor:MakeColor(204, 121, 32) backgroundColor:nil forFlag:LOG_FLAG_WARN];
}
- (BOOL)colorsEnabled
{
// The design of this method
is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method
is designed explicitly
for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This
is the intended result.
Fix it by accessing the ivar directly.
// Great strides have been take to ensure this
is safe to do.
Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
__block BOOL result;
dispatch_sync(globalLoggingQueue, ^{
dispatch_sync(loggerQueue, ^{
result = colorsEnabled;
});
});
return result;
}
- (void)setColorsEnabled:(BOOL)newColorsEnabled
{
dispatch_block_t block = ^{ @autoreleasepool {
colorsEnabled = newColorsEnabled;
if ([colorProfilesArray count] == 0) {
[self loadDefaultColorProfiles];
}
}};
// The design of this method
is taken from the DDAbstractLogger implementation.
// For extensive documentation please refer to the DDAbstractLogger implementation.
// Note: The internal implementation MUST access the colorsEnabled variable directly,
// This method
is designed explicitly
for external access.
//
// Using "self." syntax to go through this method will cause immediate deadlock.
// This
is the intended result.
Fix it by accessing the ivar directly.
// Great strides have been take to ensure this
is safe to do.
Plus it's MUCH faster.
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
NSAssert(![self isOnInternalLoggerQueue], @"MUST access ivar directly, NOT via self.* syntax.");
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
- (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask
{
[self setForegroundColor:txtColor backgroundColor:bgColor forFlag:mask context:LOG_CONTEXT_ALL];
}
- (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forFlag:(int)mask context:(int)ctxt
{
dispatch_block_t block = ^{ @autoreleasepool {
DDTTYLoggerColorProfile *newColorProfile =
[[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
backgroundColor:bgColor
context:ctxt];
NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray)
{
if ((colorProfile->mask == mask) && (colorProfile->context == ctxt))
{
break;
}
}
if (i <
[colorProfilesArray count
])
[colorProfilesArray replaceObjectAtIndex:
i withObject:newColorProfile
];
else
[colorProfilesArray addObject:newColorProfile];
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)setForegroundColor:(OSColor *)txtColor backgroundColor:(OSColor *)bgColor forTag:(id <NSCopying>)tag
{
NSAssert([(id <NSObject>)tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag");
dispatch_block_t block = ^{ @autoreleasepool {
DDTTYLoggerColorProfile *newColorProfile =
[[DDTTYLoggerColorProfile alloc] initWithForegroundColor:txtColor
backgroundColor:bgColor
context:0];
NSLogInfo(@"DDTTYLogger: newColorProfile: %@", newColorProfile);
[colorProfilesDict setObject:newColorProfile forKey:tag];
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)clearColorsForFlag:(int)mask
{
[self clearColorsForFlag:mask context:0];
}
- (void)clearColorsForFlag:(int)mask context:(int)context
{
dispatch_block_t block = ^{ @autoreleasepool {
for (DDTTYLoggerColorProfile *colorProfile in colorProfilesArray)
{
if ((colorProfile->mask == mask) && (colorProfile->context == context))
{
break;
}
}
if (i <
[colorProfilesArray count
])
{
[colorProfilesArray removeObjectAtIndex:
i];
}
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)clearColorsForTag:(id <NSCopying>)tag
{
NSAssert([(id <NSObject>)tag conformsToProtocol:@protocol(NSCopying)], @"Invalid tag");
dispatch_block_t block = ^{ @autoreleasepool {
[colorProfilesDict removeObjectForKey:tag];
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)clearColorsForAllFlags
{
dispatch_block_t block = ^{ @autoreleasepool {
[colorProfilesArray removeAllObjects];
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)clearColorsForAllTags
{
dispatch_block_t block = ^{ @autoreleasepool {
[colorProfilesDict removeAllObjects];
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)clearAllColors
{
dispatch_block_t block = ^{ @autoreleasepool {
[colorProfilesArray removeAllObjects];
[colorProfilesDict removeAllObjects];
}};
// The design of the setter logic below
is taken from the DDAbstractLogger implementation.
// For documentation please refer to the DDAbstractLogger implementation.
if ([self isOnInternalLoggerQueue])
{
block();
}
else
{
dispatch_queue_t globalLoggingQueue = [DDLog loggingQueue];
NSAssert(![self isOnGlobalLoggingQueue], @"Core architecture requirement failure");
dispatch_async(globalLoggingQueue, ^{
dispatch_async(loggerQueue, block);
});
}
}
- (void)logMessage:(DDLogMessage *)logMessage
{
NSString *logMsg = logMessage->logMsg;
BOOL isFormatted = NO;
if (formatter)
{
logMsg = [formatter formatLogMessage:logMessage];
isFormatted = logMsg != logMessage->logMsg;
}
if (logMsg)
{
// Search
for a color
profile associated with the
log message
DDTTYLoggerColorProfile *colorProfile = nil;
if (colorsEnabled)
{
if (logMessage->tag)
{
colorProfile = [colorProfilesDict objectForKey:logMessage->tag];
}
if (colorProfile == nil)
{
for (DDTTYLoggerColorProfile *cp in colorProfilesArray)
{
if (logMessage->logFlag & cp->mask)
{
if (logMessage->logContext == cp->context)
{
colorProfile = cp;
// Stop searching
break;
}
// Check
if LOG_CONTEXT_ALL was specified as a default color
for this
flag
if (cp->context == LOG_CONTEXT_ALL)
{
colorProfile = cp;
// We don't
break to keep searching
for more specific color profiles
for the context
}
}
}
}
}
//
// We use the stack instead of the heap for speed if possible.
// But we're extra cautious to avoid a stack overflow.
NSUInteger msgLen = [logMsg lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
const BOOL useStack = msgLen < (1024 * 4);
char msgStack
[useStack ?
(msgLen +
1) :
1]; // Analyzer doesn't like zero-
size array, hence the
1
char *msg = useStack ? msgStack :
(char *
)malloc
(msgLen +
1);
BOOL logMsgEnc = [logMsg getCString:msg maxLength:(msgLen + 1) encoding:NSUTF8StringEncoding];
if (!logMsgEnc)
{
if (!useStack && msg !=
NULL) free
(msg
);
return;
}
// Write the
log message to STDERR
if (isFormatted)
{
// The
log message has already been formatted.
if (colorProfile)
{
v[0].iov_base = colorProfile->fgCode;
v[0].iov_len = colorProfile->fgCodeLen;
v[1].iov_base = colorProfile->bgCode;
v[1].iov_len = colorProfile->bgCodeLen;
v[4].iov_base = colorProfile->resetCode;
v[4].iov_len = colorProfile->resetCodeLen;
}
else
{
v[0].iov_base = "";
v[0].iov_len = 0;
v[1].iov_base = "";
v[1].iov_len = 0;
v[4].iov_base = "";
v[4].iov_len = 0;
}
v
[2].
iov_base =
(char *
)msg;
v[2].iov_len = msgLen;
v[3].iov_base = "\n";
v[3].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
writev(STDERR_FILENO, v, 5);
}
else
{
// The
log message
is unformatted, so apply standard NSLog style formatting.
int len;
// Calculate timestamp.
// The technique below
is faster than using NSDateFormatter.
NSDateComponents *components =
[calendar components:calendarUnitFlags fromDate:logMessage->timestamp
];
NSTimeInterval epoch = [logMessage->timestamp timeIntervalSinceReferenceDate];
int milliseconds =
(int
)((epoch -
floor(epoch
)) *
1000);
len = snprintf(ts, 24, "%04ld-%02ld-%02ld %02ld:%02ld:%02ld:%03d", // yyyy-MM-dd HH:mm:ss:SSS
(long)components.year,
(long)components.month,
(long)components.day,
(long)components.hour,
(long)components.minute,
(long)components.second, milliseconds);
size_t tsLen =
MIN(24-
1, len
);
// Calculate thread ID
//
// How many characters do we need for the thread id?
// logMessage->machThreadID
is of
type mach_port_t,
which is an unsigned int.
//
// 8 hex chars for 32 bit, plus ending '\0' = 9
len = snprintf(tid, 9, "%x", logMessage->machThreadID);
size_t tidLen =
MIN(9-
1, len
);
// Here
is our
format: "
%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg
if (colorProfile)
{
v[0].iov_base = colorProfile->fgCode;
v[0].iov_len = colorProfile->fgCodeLen;
v[1].iov_base = colorProfile->bgCode;
v[1].iov_len = colorProfile->bgCodeLen;
v[12].iov_base = colorProfile->resetCode;
v[12].iov_len = colorProfile->resetCodeLen;
}
else
{
v[0].iov_base = "";
v[0].iov_len = 0;
v[1].iov_base = "";
v[1].iov_len = 0;
v[12].iov_base = "";
v[12].iov_len = 0;
}
v[2].iov_base = ts;
v[2].iov_len = tsLen;
v[3].iov_base = " ";
v[3].iov_len = 1;
v[4].iov_base = app;
v[4].iov_len = appLen;
v[5].iov_base = "[";
v[5].iov_len = 1;
v[6].iov_base = pid;
v[6].iov_len = pidLen;
v[7].iov_base = ":";
v[7].iov_len = 1;
v[8].iov_base = tid;
v
[8].
iov_len =
MIN((size_t
)8, tidLen
); // snprintf doesn't
return what you might think
v[9].iov_base = "] ";
v[9].iov_len = 2;
v
[10].
iov_base =
(char *
)msg;
v[10].iov_len = msgLen;
v[11].iov_base = "\n";
v[11].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
writev(STDERR_FILENO, v, 13);
}
if (!useStack) {
free(msg);
}
}
}
- (NSString *)loggerName
{
return @"cocoa.lumberjack.ttyLogger";
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation DDTTYLoggerColorProfile
-
(instancetype
)initWithForegroundColor:
(OSColor *
)fgColor backgroundColor:
(OSColor *
)bgColor
flag:
(int
)aMask context:
(int
)ctxt
{
if ((self = [super init]))
{
mask = aMask;
context = ctxt;
CGFloat r, g, b;
if (fgColor)
{
[DDTTYLogger getRed:&r green:&g blue:&b fromColor:fgColor];
fg_r = (uint8_t)(r * 255.0f);
fg_g = (uint8_t)(g * 255.0f);
fg_b = (uint8_t)(b * 255.0f);
}
if (bgColor)
{
[DDTTYLogger getRed:&r green:&g blue:&b fromColor:bgColor];
bg_r = (uint8_t)(r * 255.0f);
bg_g = (uint8_t)(g * 255.0f);
bg_b = (uint8_t)(b * 255.0f);
}
if (fgColor && isaColorTTY)
{
// Map foreground color to closest available shell color
fgCodeIndex = [DDTTYLogger codeIndexForColor:fgColor];
fgCodeRaw = [codes_fg objectAtIndex:fgCodeIndex];
NSString *escapeSeq = @"\033[";
NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger len2 = [fgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
BOOL escapeSeqEnc = [escapeSeq getCString:(fgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding];
BOOL fgCodeRawEsc = [fgCodeRaw getCString:(fgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding];
if (!escapeSeqEnc || !fgCodeRawEsc) return nil;
fgCodeLen = len1+len2;
}
else if (fgColor && isaXcodeColorTTY)
{
// Convert foreground color to color code sequence
const
char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
int result = snprintf(fgCode, 24, "%sfg%u,%u,%u;", escapeSeq, fg_r, fg_g, fg_b);
fgCodeLen =
MIN(result,
(24-
1));
}
else
{
// No foreground color or no color support
fgCode[0] = '\0';
fgCodeLen = 0;
}
if (bgColor && isaColorTTY)
{
// Map background color to closest available shell color
bgCodeIndex = [DDTTYLogger codeIndexForColor:bgColor];
bgCodeRaw = [codes_bg objectAtIndex:bgCodeIndex];
NSString *escapeSeq = @"\033[";
NSUInteger len1 = [escapeSeq lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger len2 = [bgCodeRaw lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
BOOL escapeSeqEnc = [escapeSeq getCString:(bgCode) maxLength:(len1+1) encoding:NSUTF8StringEncoding];
BOOL bgCodeRawEsc = [bgCodeRaw getCString:(bgCode+len1) maxLength:(len2+1) encoding:NSUTF8StringEncoding];
if (!escapeSeqEnc || !bgCodeRawEsc) return nil;
bgCodeLen = len1+len2;
}
else if (bgColor && isaXcodeColorTTY)
{
// Convert background color to color code sequence
const
char *escapeSeq = XCODE_COLORS_ESCAPE_SEQ;
int result = snprintf(bgCode, 24, "%sbg%u,%u,%u;", escapeSeq, bg_r, bg_g, bg_b);
bgCodeLen =
MIN(result,
(24-
1));
}
else
{
// No background color or no color support
bgCode[0] = '\0';
bgCodeLen = 0;
}
if (isaColorTTY)
{
resetCodeLen = snprintf(resetCode, 8, "\033[0m");
}
else if (isaXcodeColorTTY)
{
resetCodeLen = snprintf(resetCode, 8, XCODE_COLORS_RESET);
}
else
{
resetCode[0] = '\0';
resetCodeLen = 0;
}
}
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:
@"<DDTTYLoggerColorProfile: %p mask:%i ctxt:%i fg:%u,%u,%u bg:%u,%u,%u fgCode:%@ bgCode:%@>",
self, mask, context, fg_r, fg_g, fg_b, bg_r, bg_g, bg_b, fgCodeRaw, bgCodeRaw];
}
@end