CocoaLumberjack:如何将自定义数据字段存储为日志消息的一部分?

时间:2015-03-01 20:38:07

标签: objective-c logging cocoalumberjack

这是我的用例:

我正在使用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)并预先执行所有JSONification:

+ (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,可通过自定义格式化程序访问。

1 个答案:

答案 0 :(得分:0)

CocoaLumberjack Github Issues Tracker收到来自@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;