Search code examples
iosmavennslog

Removing Logs when releasing iOS app


Currently I am building two apps for my project one in release & another in debug (the only thing that changes are provisioning profiles used to sign and the endpoints) . Because of some policies, I shouldn't be creating ipa files locally. So I use maven to build these two versions (release & debug), based on a script. Because of the same policies, output should be complete removed from the application (NSLog, printf...). I am aware of the preprocessor macros, but I don't want to rely on them, since someone (without knowing) might change them and jeopardise what I want to achieve. So what I want is:

  1. Be able to logout anything I want when I am using my simulator or when I run directly on a real device
  2. When I use maven to build my applications, it will make sure the NSLogs are stripped or disabled.

Maven relies on what's in a remote repository to actually make the build, so if there is a way of disabling this logs during the remote repo commit, it's a solution as well..


Solution

  • It's an interesting request, but feasible if you're willing to accept a bit of function-call overhead for each log that gets skipped. There is a nice feature inside of the EtPanKit framework that checks if the files that are trying to call the log function match an array of pre-defined classes in your Info.plist file. In addition to being a great debug filter, all you'd have to do at Release time is remove all the keys from the plist or specify a different one in your Release build with no values associated with the LEPLogEnabledFilenames key.

    In the interest of preventing link-rot, here's the function itself and the associated macros that make it a bit prettier to call:

    #define LEPLogStack(...) LEPLogInternal(__FILE__, __LINE__, 1, __VA_ARGS__)
    #define LEPLog(...) LEPLogInternal(__FILE__, __LINE__, 0, __VA_ARGS__)
    
    #import <Foundation/Foundation.h>
    #import <libgen.h>
    #import <time.h>
    #import <sys/time.h>
    #include <execinfo.h>
    #include <pthread.h>
    
    static NSSet * enabledFilesSet = nil;
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    
    void LEPLogInternal(const char * filename, unsigned int line, int dumpStack, NSString * format, ...)
    {
        va_list argp;
        NSString * str;
        NSAutoreleasePool * pool;
        char * filenameCopy;
        char * lastPathComponent;
        struct timeval tv;
        struct tm tm_value;
        //NSDictionary * enabledFilenames;
    
        pool = [[NSAutoreleasePool alloc] init];
    
        pthread_mutex_lock(&lock);
        if (enabledFilesSet == nil) {
            enabledFilesSet = [[NSSet alloc] initWithArray:[[NSUserDefaults standardUserDefaults] arrayForKey:LEPLogEnabledFilenames]];
        }
        pthread_mutex_unlock(&lock);
    
        NSString * fn;
        fn = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:filename length:strlen(filename)];
        fn = [fn lastPathComponent];
        if (![enabledFilesSet containsObject:fn]) {
            [pool release];
            return;
        }
    
        va_start(argp, format);
        str = [[NSString alloc] initWithFormat:format arguments:argp];
        va_end(argp);
    
        NSString * outputFileName = [[NSUserDefaults standardUserDefaults] stringForKey:LEPLogOutputFilename];
        static FILE * outputfileStream = NULL;
        if ( ( NULL == outputfileStream ) && outputFileName )
        {
            outputfileStream = fopen( [outputFileName UTF8String], "w+" );
        }
    
        if ( NULL == outputfileStream )
            outputfileStream = stderr;
    
        gettimeofday(&tv, NULL);
        localtime_r(&tv.tv_sec, &tm_value);
        fprintf(outputfileStream, "%04u-%02u-%02u %02u:%02u:%02u.%03u ", tm_value.tm_year + 1900, tm_value.tm_mon + 1, tm_value.tm_mday, tm_value.tm_hour, tm_value.tm_min, tm_value.tm_sec, tv.tv_usec / 1000);
        //fprintf(stderr, "%10s ", [[[NSDate date] description] UTF8String]);
        fprintf(outputfileStream, "[%s:%u] ", [[[NSProcessInfo processInfo] processName] UTF8String], [[NSProcessInfo processInfo] processIdentifier]);
        filenameCopy = strdup(filename);
        lastPathComponent = basename(filenameCopy);
        fprintf(outputfileStream, "(%s:%u) ", lastPathComponent, line);
        free(filenameCopy);
        fprintf(outputfileStream, "%s\n", [str UTF8String]);
        [str release];
    
        if (dumpStack) {
            void * frame[128];
            int frameCount;
            int i;
    
            frameCount = backtrace(frame, 128);
            for(i = 0 ; i < frameCount ; i ++) {
                fprintf(outputfileStream, "  %p\n", frame[i]);
            }
        }
    
        if ( outputFileName )
        {
            fflush(outputfileStream);
        }
    
        [pool release];
    }