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