Logging.m
author Jens Alfke <jens@mooseyard.com>
Wed Sep 02 08:41:25 2009 -0700 (2009-09-02)
changeset 35 5cab3034d3a1
parent 11 e5976864dfe9
permissions -rw-r--r--
10.6 compatibility: Fix some new compiler warnings, and work around apparent regressions in NSTask and -stringByStandardizingPath.
jens@0
     1
//
jens@0
     2
//  Logging.m
jens@0
     3
//  MYUtilities
jens@0
     4
//
jens@0
     5
//  Created by Jens Alfke on 1/5/08.
jens@0
     6
//  Copyright 2008 Jens Alfke. All rights reserved.
jens@0
     7
//
jens@0
     8
jens@0
     9
#import "Logging.h"
jens@11
    10
#import "CollectionUtils.h"
jens@11
    11
jens@11
    12
#include <unistd.h>
jens@0
    13
#include <fcntl.h>
jens@0
    14
#include <sys/param.h>
jens@11
    15
#include <termios.h>
jens@0
    16
jens@0
    17
jens@0
    18
NSString* LOC( NSString *key )     // Localized string lookup
jens@0
    19
{
jens@0
    20
    NSString *value = [[NSBundle mainBundle] localizedStringForKey:key value:nil table:nil];
jens@0
    21
    if( value == key ) {
jens@0
    22
        Warn(@"No localized string for '%@' in Localizable.strings!",key);
jens@0
    23
        value = [key uppercaseString];
jens@0
    24
    }
jens@0
    25
    return value;
jens@0
    26
}
jens@0
    27
jens@0
    28
jens@11
    29
typedef enum {
jens@11
    30
    kLoggingToOther,
jens@11
    31
    kLoggingToFile,
jens@11
    32
    kLoggingToTTY,
jens@11
    33
    kLoggingToColorTTY
jens@11
    34
} MYLoggingTo;
jens@11
    35
jens@11
    36
jens@1
    37
int _gShouldLog = -1;
jens@11
    38
static MYLoggingTo sLoggingTo;
jens@1
    39
static NSMutableSet *sEnabledDomains;
jens@0
    40
jens@0
    41
jens@11
    42
/** Does the file descriptor connect to console output, i.e. a terminal or Xcode? */
jens@11
    43
static MYLoggingTo getLoggingMode( int fd )
jens@0
    44
{
jens@11
    45
    if( isatty(fd) ) {
jens@11
    46
        const char *term = getenv("TERM");
jens@11
    47
        if( term && (strstr(term,"ANSI") || strstr(term,"ansi") || strstr(term,"color")) )
jens@11
    48
            return kLoggingToColorTTY;
jens@11
    49
        else
jens@11
    50
            return kLoggingToTTY;
jens@11
    51
    } else {
jens@11
    52
        char path[MAXPATHLEN];
jens@11
    53
        if( fcntl(fd, F_GETPATH, path) == 0 )
jens@11
    54
            return kLoggingToFile;
jens@11
    55
        else
jens@11
    56
            return kLoggingToOther;
jens@11
    57
    }
jens@0
    58
}
jens@0
    59
jens@0
    60
jens@1
    61
static void InitLogging()
jens@0
    62
{
jens@1
    63
    if( _gShouldLog != -1 )
jens@1
    64
        return;
jens@1
    65
jens@1
    66
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
jens@1
    67
    _gShouldLog = NO;
jens@1
    68
    sEnabledDomains = [[NSMutableSet alloc] init];
jens@1
    69
    NSDictionary *dflts = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
jens@1
    70
    for( NSString *key in dflts ) {
jens@1
    71
        if( [key hasPrefix: @"Log"] ) {
jens@1
    72
            BOOL value = [[NSUserDefaults standardUserDefaults] boolForKey: key];
jens@1
    73
            if( key.length==3 )
jens@1
    74
                _gShouldLog = value;
jens@1
    75
            else if( value )
jens@1
    76
                [sEnabledDomains addObject: [key substringFromIndex: 3]];
jens@1
    77
        }
jens@1
    78
    }
jens@11
    79
    sLoggingTo = getLoggingMode(STDERR_FILENO);
jens@1
    80
    
jens@11
    81
    Log(@"Logging mode %i enabled in domains: {%@}", 
jens@11
    82
        sLoggingTo,
jens@1
    83
        [[[sEnabledDomains allObjects] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)] 
jens@1
    84
                componentsJoinedByString: @", "]);
jens@1
    85
    [pool drain];
jens@1
    86
}
jens@1
    87
jens@1
    88
jens@1
    89
BOOL EnableLog( BOOL enable )
jens@1
    90
{
jens@1
    91
    if( _gShouldLog == -1 )
jens@1
    92
        InitLogging();
jens@1
    93
    BOOL old = _gShouldLog;
jens@1
    94
    _gShouldLog = enable;
jens@1
    95
    return old;
jens@1
    96
}
jens@1
    97
jens@1
    98
BOOL _WillLogTo( NSString *domain )
jens@1
    99
{
jens@1
   100
    if( _gShouldLog == -1 )
jens@1
   101
        InitLogging();
snej@19
   102
    return _gShouldLog && (domain==nil || [sEnabledDomains containsObject: domain]);
jens@1
   103
}
jens@1
   104
jens@1
   105
BOOL _EnableLogTo( NSString *domain, BOOL enable )
jens@1
   106
{
jens@1
   107
    if( _gShouldLog == -1 )
jens@1
   108
        InitLogging();
jens@1
   109
    BOOL old = [sEnabledDomains containsObject: domain];
jens@1
   110
    if( enable )
jens@1
   111
        [sEnabledDomains addObject: domain];
jens@1
   112
    else
jens@1
   113
        [sEnabledDomains removeObject: domain];
jens@1
   114
    return old;
jens@1
   115
}
jens@1
   116
jens@1
   117
jens@11
   118
#define kWarningPrefix @"\007WARNING*** "
jens@11
   119
            
jens@11
   120
#define COLOR(STR)     (sLoggingTo==kLoggingToColorTTY ?@"\033["#STR"m" :@"")
jens@11
   121
jens@11
   122
jens@1
   123
static void _Logv( NSString *prefix, NSString *msg, va_list args )
jens@1
   124
{
jens@11
   125
    if( sLoggingTo > kLoggingToOther ) {
jens@0
   126
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
jens@0
   127
        static NSDateFormatter *sTimestampFormat;
jens@0
   128
        if( ! sTimestampFormat ) {
jens@0
   129
            sTimestampFormat = [[NSDateFormatter alloc] init];
jens@0
   130
            sTimestampFormat.dateFormat = @"HH:mm:ss.SSS";
jens@0
   131
        }
jens@0
   132
        NSDate *now = [[NSDate alloc] init];
jens@0
   133
        NSString *timestamp = [sTimestampFormat stringFromDate: now];
jens@0
   134
        [now release];
jens@1
   135
        NSString *separator = prefix.length ?@": " :@"";
jens@0
   136
        msg = [[NSString alloc] initWithFormat: msg arguments: args];
jens@11
   137
        NSString *prefixColor = (prefix==kWarningPrefix) ?COLOR(91) :COLOR(93);
jens@11
   138
        NSString *msgColor = (prefix==kWarningPrefix) ?@"" :COLOR(0);
jens@11
   139
        NSString *finalMsg = [[NSString alloc] initWithFormat: @"%@%@| %@%@%@%@%@\n", 
jens@11
   140
                              COLOR(30),timestamp,
jens@11
   141
                              prefixColor,prefix,separator,
jens@11
   142
                              msgColor,msg];
jens@0
   143
        fputs([finalMsg UTF8String], stderr);
jens@0
   144
        [finalMsg release];
jens@0
   145
        [msg release];
jens@0
   146
        [pool drain];
jens@11
   147
    } else {
jens@11
   148
        if( prefix.length )
jens@11
   149
            msg = $sprintf(@"%@: %@", prefix,msg);
jens@0
   150
        NSLogv(msg,args);
jens@11
   151
    }
jens@0
   152
}
jens@0
   153
jens@0
   154
jens@0
   155
void AlwaysLog( NSString *msg, ... )
jens@0
   156
{
jens@0
   157
    va_list args;
jens@0
   158
    va_start(args,msg);
jens@1
   159
    _Logv(@"",msg,args);
jens@0
   160
    va_end(args);
jens@0
   161
}
jens@0
   162
jens@0
   163
jens@0
   164
void _Log( NSString *msg, ... )
jens@0
   165
{
jens@1
   166
    if( _gShouldLog == -1 )
jens@1
   167
        InitLogging();
jens@1
   168
    if( _gShouldLog ) {
jens@0
   169
        va_list args;
jens@0
   170
        va_start(args,msg);
jens@1
   171
        _Logv(@"",msg,args);
jens@0
   172
        va_end(args);
jens@0
   173
    }
jens@0
   174
}
jens@0
   175
jens@0
   176
jens@1
   177
void _LogTo( NSString *domain, NSString *msg, ... )
jens@1
   178
{
jens@1
   179
    if( _gShouldLog == -1 )
jens@1
   180
        InitLogging();
jens@1
   181
    if( _gShouldLog && [sEnabledDomains containsObject: domain] ) {
jens@1
   182
        va_list args;
jens@1
   183
        va_start(args,msg);
jens@1
   184
        _Logv(domain, msg, args);
jens@1
   185
        va_end(args);
jens@1
   186
    }
jens@1
   187
}
jens@1
   188
jens@1
   189
jens@0
   190
void Warn( NSString *msg, ... )
jens@0
   191
{
jens@0
   192
    va_list args;
jens@0
   193
    va_start(args,msg);
jens@11
   194
    _Logv(kWarningPrefix,msg,args);
jens@0
   195
    va_end(args);
jens@0
   196
}
jens@0
   197
jens@0
   198
jens@11
   199
jens@11
   200
jens@11
   201
/*
jens@11
   202
 Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@11
   203
 
jens@11
   204
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@11
   205
 provided that the following conditions are met:
jens@11
   206
 
jens@11
   207
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@11
   208
 and the following disclaimer.
jens@11
   209
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@11
   210
 and the following disclaimer in the documentation and/or other materials provided with the
jens@11
   211
 distribution.
jens@11
   212
 
jens@11
   213
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@11
   214
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@11
   215
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@11
   216
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@11
   217
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@11
   218
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@11
   219
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@11
   220
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@11
   221
 */