0

这是我的用例:

我正在使用 CocoaLumberjack 在我的应用程序中记录数据。我有六个不同的严重程度。有些数据是微不足道的(严重性 6),有些则不是(严重性 1)。我有两个“记录器”,这样所有数据都被记录到控制台,所有数据也被发送到 API 进行存储。API 接受 JSON 格式的日志消息。我有将日志发送到 API 的代码(自定义DDFileLoggerManager)。到目前为止,我一直在使用自定义DDLogFormatter将我的日志消息转换为 JSON 对象,然后由 DDFileLogger 写入磁盘。到目前为止,这种自定义格式仅由文件记录器使用,因此控制台消息仍然具有相当的可读性。(我不一定想将数千个 JSON 对象传送到控制台。)到目前为止,整个系统一直在完美运行。

这是问题所在:

对于发送到 API 服务器的日志数据版本,有时我还需要提交数据统计信息作为日志消息的一部分。我需要能够将键值对附加到日志消息中。我的 JSON 对象最终将如下所示:

{
    'time': '2015-03-01T13:54:03-05:00', 
    'message': 'User logged in',
    'severity': 6,
    'data': {
        'username':'testuser',
        'deviceType': 'iPad Air 2'
    }
}

最后,问题

如何让 CocoaLumberjack 允许我将任意键值数据存储为日志记录的一部分,然后在进行自定义格式化时检索它?

到目前为止,我提出的唯一解决方案是创建一个自定义函数,用于满足我所有的日志记录需求。该函数将接受一个数据参数 ( NSDictionary) 并预先完成所有 JSON 化:

+ (void) logWithSeverity: (uint) severity 
    data:(NSDictionary *) data 
    andFormat:(NSString *)formatString, ...
{
    va_list args;
    va_start(args, formatString);
    NSString *message = [[NSString alloc] initWithFormat:formatString 
        arguments:args];
    va_end(args);

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSLocale *enUSPOSIXLocale = 
        [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    [dateFormatter setLocale:enUSPOSIXLocale];
    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];

    if (data == nil) {
        data = @{};
    }

    // Since we are going to be using the pipe character as a data demarcation, 
    // we want to remove any that might naturally be occuring in the string
    NSDictionary *jsonDictionary = @{
     @"time": [dateFormatter stringFromDate:[NSDate date]],
     @"message": message,
     @"severity": [NSNumber numberWithUnsignedInt:severity],
     @"data": data
     };

    NSError* error;
    NSData *jsonData = [NSJSONSerialization 
        dataWithJSONObject:jsonDictionary options:0 error:&error];

    if(error) {
        NSLog(@"ERROR: We were unable to serialize JSON .");
        return;
    }


    NSString *jsonString = [[NSString alloc] initWithData:jsonData 
        encoding:NSUTF8StringEncoding];

    DDLogVerbose(jsonString);
}

我将是第一个承认这是一个糟糕的解决方案的人:

  • 自从实现它以来,我不得不关闭到控制台的输出,因为现在记录的所有内容都是一个大而笨重的 JSON 对象,其中包含我不想输出到控制台的各种数据。
  • 由于我的严重性级别现在在 JSON 对象内部,因此我不再使用 CocoaLumberjack logLevel 概念。我的记录器将始终设置为“详细”。因此,我完全摆脱了使用日志库的最大好处之一。

有没有人对我有更优雅的解决方案?在一个完美的世界中,会有这样一个函数:DDLogVerboseWithData(*someObject, @"User logged in.");然后该数据将作为 DDLogMessage 的一部分存储,并且可以通过自定义格式化程序访问。

4

1 回答 1

0

CocoaLumberjack Github 问题跟踪器上收到来自 @river 的非常有用的反馈后,我了解到我可以使用 DDLogMessage 的tag参数来存储我的数据。这就是我最终得到的结果:

/***
 *
 * Contains custom logging definitions that allow us to do our control server logging
 * 
 ****/

#import "DDLog.h"

#undef LOG_FLAG_ERROR
#undef LOG_FLAG_WARN
#undef LOG_FLAG_INFO
#undef LOG_FLAG_DEBUG
#undef LOG_FLAG_VERBOSE

#undef LOG_LEVEL_ERROR
#undef LOG_LEVEL_WARN
#undef LOG_LEVEL_INFO
#undef LOG_LEVEL_DEBUG
#undef LOG_LEVEL_VERBOSE

#undef LOG_ERROR
#undef LOG_WARN
#undef LOG_INFO
#undef LOG_DEBUG
#undef LOG_VERBOSE

#undef DDLogError
#undef DDLogWarn
#undef DDLogInfo
#undef DDLogDebug
#undef DDLogVerbose

#undef DDLogCError
#undef DDLogCWarn
#undef DDLogCInfo
#undef DDLogCDebug
#undef DDLogCVerbose

// Now define everything how we want it

#define LOG_FLAG_SEV_1   (1 << 0)  // 0...000001
#define LOG_FLAG_SEV_2   (1 << 1)  // 0...000010
#define LOG_FLAG_SEV_3   (1 << 2)  // 0...000100
#define LOG_FLAG_SEV_4   (1 << 3)  // 0...001000
#define LOG_FLAG_SEV_5   (1 << 4)  // 0...010000
#define LOG_FLAG_SEV_6   (1 << 5)  // 0...100000

#define LOG_LEVEL_SEV_1   (LOG_FLAG_SEV_1)                      // 0...000001
#define LOG_LEVEL_SEV_2   (LOG_FLAG_SEV_2 | LOG_LEVEL_SEV_1 ) // 0...000011
#define LOG_LEVEL_SEV_3   (LOG_FLAG_SEV_3 | LOG_LEVEL_SEV_2 ) // 0...000111
#define LOG_LEVEL_SEV_4   (LOG_FLAG_SEV_4 | LOG_LEVEL_SEV_3 ) // 0...001111
#define LOG_LEVEL_SEV_5   (LOG_FLAG_SEV_5 | LOG_LEVEL_SEV_4 ) // 0...011111
#define LOG_LEVEL_SEV_6   (LOG_FLAG_SEV_6 | LOG_LEVEL_SEV_5 ) // 0...111111

#define LOG_SEV_1   (ddLogLevel & LOG_FLAG_SEV_1 )
#define LOG_SEV_2   (ddLogLevel & LOG_FLAG_SEV_2 )
#define LOG_SEV_3   (ddLogLevel & LOG_FLAG_SEV_3 )
#define LOG_SEV_4   (ddLogLevel & LOG_FLAG_SEV_4 )
#define LOG_SEV_5   (ddLogLevel & LOG_FLAG_SEV_5 )
#define LOG_SEV_6   (ddLogLevel & LOG_FLAG_SEV_6 )

#define DDLogSeverity1(frmt, ...)    SYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_SEV_1,  0, frmt, ##__VA_ARGS__)
#define DDLogSeverity2(frmt, ...)    SYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_SEV_2,  0, frmt, ##__VA_ARGS__)
#define DDLogSeverity3(frmt, ...)    ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_SEV_3,   0, frmt, ##__VA_ARGS__)
#define DDLogSeverity4(frmt, ...)    ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_SEV_4, 0, frmt, ##__VA_ARGS__)
#define DDLogSeverity5(frmt, ...)    ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_SEV_5,   0, frmt, ##__VA_ARGS__)
#define DDLogSeverity6(frmt, ...)    ASYNC_LOG_OBJC_MAYBE(ddLogLevel, LOG_FLAG_SEV_6,  0, frmt, ##__VA_ARGS__)

#define DDLogCSeverity1(frmt, ...)   SYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_SEV_1,  0, frmt, ##__VA_ARGS__)
#define DDLogCSeverity2(frmt, ...)   SYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_SEV_2,  0, frmt, ##__VA_ARGS__)
#define DDLogCSeverity3(frmt, ...)   ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_SEV_3,   0, frmt, ##__VA_ARGS__)
#define DDLogCSeverity4(frmt, ...)   ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_SEV_4, 0, frmt, ##__VA_ARGS__)
#define DDLogCSeverity5(frmt, ...)   ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_SEV_5,   0, frmt, ##__VA_ARGS__)
#define DDLogCSeverity6(frmt, ...)   ASYNC_LOG_C_MAYBE(ddLogLevel, LOG_FLAG_SEV_6,  0, frmt, ##__VA_ARGS__)

#define DDLogSeverity1WithData(theData, frmt, ...) LOG_MACRO(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, LOG_FLAG_SEV_1, 0, theData, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogSeverity2WithData(theData, frmt, ...) LOG_MACRO(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, LOG_FLAG_SEV_2, 0, theData, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogSeverity3WithData(theData, frmt, ...) LOG_MACRO(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, LOG_FLAG_SEV_3, 0, theData, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogSeverity4WithData(theData, frmt, ...) LOG_MACRO(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, LOG_FLAG_SEV_4, 0, theData, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogSeverity5WithData(theData, frmt, ...) LOG_MACRO(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, LOG_FLAG_SEV_5, 0, theData, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)
#define DDLogSeverity6WithData(theData, frmt, ...) LOG_MACRO(LOG_ASYNC_ENABLED, LOG_LEVEL_DEF, LOG_FLAG_SEV_6, 0, theData, __PRETTY_FUNCTION__, frmt, ##__VA_ARGS__)

/**
 * Controls the verbosity of the entire app's logging.
 */
static const int ddLogLevel = LOG_LEVEL_SEV_6;
于 2015-03-03T15:49:42.500 回答