gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 03:25:41 51 4
gpt4 key购买 nike

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

我如何才能以可配置的方式生成日志,而不是将特定的日志库强加给我的用户?

最佳答案

TL;DR 在您的 API 中公开一个日志处理程序 block 。


这里有一个建议,可以通过将记录器类作为公共(public) API 的一部分来非常轻松地配置日志记录。我们称它为 MYLibraryLogger:

// MYLibraryLogger.h

#import <Foundation/Foundation.h>

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

这个类有一个方法允许客户端注册一个日志处理程序 block 。这使得客户端使用他们最喜欢的库实现日志记录变得微不足道。以下是客户如何将其与 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 <Foundation/Foundation.h>

#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);

请注意日志 message 是如何返回一个字符串而不只是一个字符串的 block 。如果定义的日志处理程序决定不评估消息(例如,基于上面默认日志处理程序中的日志级别),您可以通过这种方式避免昂贵的计算。这使您可以编写单行日志,其中包含可能代价高昂的日志消息以进行计算,如果日志被丢弃,则不会影响性能,例如:

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

关于objective-c - 我应该如何处理 Objective-C 库中的日志?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34732814/

51 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com