当前位置:  开发笔记 > IOS > 正文

我应该如何处理Objective-C库中的日志?

如何解决《我应该如何处理Objective-C库中的日志?》经验,为你挑选了1个好方法。

我正在编写一个Objective-C库,在某些地方我想记录一些信息.使用NSLog并不理想,因为它不可配置,既没有级别支持也没有标记支持.CocoaLumberjack和NSLogger都是流行的日志库,支持级别和上下文/标签,但我不想依赖第三方日志库.

如何以可配置的方式生成日志,而不会强制我的用户使用特定的日志记录库?



1> 0xced..:

TL; DR 在API中公开日志处理程序块.


这是一个建议,使用记录器类作为公共API的一部分,可以非常轻松地配置日志记录.我们称之为MYLibraryLogger:

// MYLibraryLogger.h

#import 

typedef NS_ENUM(NSUInteger, MYLogLevel) {
    MYLogLevelError   = 0,
    MYLogLevelWarning = 1,
    MYLogLevelInfo    = 2,
    MYLogLevelDebug   = 3,
    MYLogLevelVerbose = 4,
};

@interface MYLibraryLogger : NSObject

+ (void) setLogHandler:(void (^)(NSString * (^message)(void), MYLogLevel level, const char *file, const char *function, NSUInteger line))logHandler;

@end

该类有一个允许客户端注册日志处理程序块的方法.这使得客户端使用他们喜欢的库实现日志记录变得微不足道.以下是客户端如何将其与NSLogger一起使用:

[MYLibraryLogger setLogHandler:^(NSString * (^message)(void), MYLogLevel level, const char *file, const char *function, NSUInteger line) {
    LogMessageRawF(file, (int)line, function, @"MYLibrary", (int)level, message());
}];

或者使用CocoaLumberjack:

[MYLibraryLogger setLogHandler:^(NSString * (^message)(void), MYLogLevel level, const char *file, const char *function, NSUInteger line) {
    // The `MYLogLevel` enum matches the `DDLogFlag` options from DDLog.h when shifted
    [DDLog log:YES message:message() level:ddLogLevel flag:(1 << level) context:MYLibraryLumberjackContext file:file function:function line:line tag:nil];
}];

以下是MYLibraryLogger使用默认日志处理程序的实现,该处理程序仅记录错误和警告:

// MYLibraryLogger.m

#import "MYLibraryLogger.h"

static void (^LogHandler)(NSString * (^)(void), MYLogLevel, const char *, const char *, NSUInteger) = ^(NSString *(^message)(void), MYLogLevel level, const char *file, const char *function, NSUInteger line)
{
    if (level == MYLogLevelError || level == MYLogLevelWarning)
        NSLog(@"[MYLibrary] %@", message());
};

@implementation MYLibraryLogger

+ (void) setLogHandler:(void (^)(NSString * (^message)(void), MYLogLevel level, const char *file, const char *function, NSUInteger line))logHandler
{
    LogHandler = logHandler;
}

+ (void) logMessage:(NSString * (^)(void))message level:(MYLogLevel)level file:(const char *)file function:(const char *)function line:(NSUInteger)line
{
    if (LogHandler)
        LogHandler(message, level, file, function, line);
}

@end

此解决方案最后一个缺失的部分是一组宏,供您通过库使用.

// MYLibraryLogger+Private.h

#import 

#import "MYLibraryLogger.h"

@interface MYLibraryLogger ()

+ (void) logMessage:(NSString * (^)(void))message level:(MYLogLevel)level file:(const char *)file function:(const char *)function line:(NSUInteger)line;

@end

#define MYLibraryLog(_level, _message) [MYLibraryLogger logMessage:(_message) level:(_level) file:__FILE__ function:__PRETTY_FUNCTION__ line:__LINE__]

#define MYLibraryLogError(format, ...)   MYLibraryLog(MYLogLevelError,   (^{ return [NSString stringWithFormat:(format), ##__VA_ARGS__]; }))
#define MYLibraryLogWarning(format, ...) MYLibraryLog(MYLogLevelWarning, (^{ return [NSString stringWithFormat:(format), ##__VA_ARGS__]; }))
#define MYLibraryLogInfo(format, ...)    MYLibraryLog(MYLogLevelInfo,    (^{ return [NSString stringWithFormat:(format), ##__VA_ARGS__]; }))
#define MYLibraryLogDebug(format, ...)   MYLibraryLog(MYLogLevelDebug,   (^{ return [NSString stringWithFormat:(format), ##__VA_ARGS__]; }))
#define MYLibraryLogVerbose(format, ...) MYLibraryLog(MYLogLevelVerbose, (^{ return [NSString stringWithFormat:(format), ##__VA_ARGS__]; }))

然后你只需在你的库中使用它:

MYLibraryLogError(@"Operation finished with error: %@", error);

注意日志消息是一个块返回一个字符串而不是一个字符串.这样,如果定义的日志处理程序决定不评估消息,则可以避免昂贵的计算(例如,基于上面的默认日志处理程序中的日志级别).这使您可以编写带有可能代价高昂的日志消息的单线日志,以便在丢弃日志时不会出现性能损失,例如:

MYLibraryLogDebug(@"Object: %@", ^{ return object.debugDescription; }());

推荐阅读
jerry613
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有