发布iOS应用时如何移除日志记录

10

目前,我正在为我的项目构建两个应用程序,一个是发布版本,另一个是调试版本(唯一不同的是所使用的签名证书和终端点)。由于某些政策,我不应该在本地创建ipa文件。因此,我使用maven基于脚本构建这两个版本(发布和调试)。由于相同的政策,输出应完全从应用程序中删除(如NSLog,printf...)。我知道预处理器宏,但我不想依赖它们,因为有人(不知情)可能会更改它们,并危及我想要实现的目标。因此,我想要:

  1. 能够在我使用模拟器或直接在真实设备上运行时注销任何我想要的内容
  2. 当我使用maven构建我的应用程序时,它将确保去除或禁用NSLogs

Maven依赖于远程存储库中的内容来进行实际构建,因此如果有一种方法在远程存储库提交期间禁用这些日志,那么也是一种解决方案。


1
所以让我来理解一下:您想在没有自从20世纪80年代以来用于编译时区分的任何工具的情况下对代码路径进行编译时区分?预处理器宏不是危险的依赖项,它们是唯一可以在没有任何开销的情况下使其工作的方法。如果您担心宏被更改,为什么不在其未定义时使用#error呢? - CodaFi
对我来说,预处理器宏完全没问题。只是我不做决策,所以需要提供另一种选择。:) 而且这不是“编译时差异”,我只需要禁用输出。 - Rui Peres
好的,我想我有一个解决方案。 - CodaFi
4个回答

2

使用这个宏,将自动在发布模式下关闭日志记录。 只需将所有的 NSLog 替换为 DLog ,并在以后使用 DLog 进行日志记录。 例如:DLog(@“Text:%@”,sometext);

#ifdef DEBUG
#   define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define DLog(...)
#endif

1
这是一个有趣的请求,但如果你愿意为每个被跳过的日志承受一点函数调用开销,那么它是可行的。在EtPanKit framework内部有一个很好的功能,它检查尝试调用日志函数的文件是否与您的Info.plist文件中预定义类的数组匹配。除了作为一个很好的调试过滤器之外,在发布时,您只需要从plist中删除所有键或在您的Release构建中指定一个不带LEPLogEnabledFilenames键值的不同的plist即可。
为了防止链接失效,这里是该函数本身和相关的宏,使其更容易调用:
#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];
}

1
我明白您不想依赖预处理宏,但是有一种简单的方法可以使用预处理器来删除任何NSLog语句:
请在您的前缀头文件中添加以下内容:
#ifndef DEBUG
#define NSLog(...)
#endif

如果未定义DEBUG,则预处理器将在整个应用程序代码中删除所有NSLog语句。 如果您的构建设置中未自动添加DEBUG,则可以简单地添加#define DEBUG语句,并在发布版本时将其注释掉。 printf()语句也可以这样做。 我已经在发布的应用程序中成功使用了这种方法来消除NSLog。

0

你可以像这样添加一个完整的日志系统:

#ifndef Logs_h
#define Logs_h

    /* Log levels */
    #define LOG_LEVEL_NO_LOG 0
    #define LOG_LEVEL_ONLY_ERRORS 1
    #define LOG_LEVEL_ERROS_AND_WARNINGS 2
    #define LOG_LEVEL_LOG_ALL 3
    /* Log levels */


    #ifdef DEBUG
        #define LOG_LEVEL LOG_LEVEL_LOG_ALL /* <-- Change The Log Level here */
    #else
        #define LOG_LEVEL LOG_LEVEL_NO_LOG /* No logs on release now */
    #endif


    /* Logs Macros */

    #if LOG_LEVEL >= LOG_LEVEL_LOG_ALL
        #define DebugLog(fmt, ...) NSLog(@"[Debug] %s [Line %d]: " fmt, __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
    #else
        #define DebugLog(...) /* */
    #endif

    #if LOG_LEVEL >= LOG_LEVEL_ERROS_AND_WARNINGS
        #define WarnLog(fmt, ...) NSLog(@"[Warning] %s [Line %d]: " fmt, __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
    #else
        #define WarnLog(...) /* */
    #endif

    #if LOG_LEVEL >= LOG_LEVEL_ONLY_ERRORS
        #define ErrorLog(fmt, ...) NSLog(@"[Error] %s [Line %d]: " fmt, __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
    #else
        #define ErrorLog(...) /* */
    #endif

#endif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接