iosobjective-cnsdatansmutabledatacocoalumberjack

Extract the latest 100 entries from Cocoa Lumberjack log


My app is using Cocoa Lumberjack as logging framework, it creates several log files that need to be aggregated.

At some point I need to send debug data as an E-Mail attachment. The entire log is too long, how do I get the latest 100 log entries?

I'm currently using the NSData object to hold the data as a byte buffer and does not offer reading line-by-line by default.

Initialize logging and variables (done elsewhere in the app):

[DDLog addLogger:[DDTTYLogger sharedInstance]];
NSArray *pathsDocs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [pathsDocs objectAtIndex:0];
DDLogFileManagerDefault *documentsFileManager = [[DDLogFileManagerDefault alloc] initWithLogsDirectory:documentsDirectory];
self.fileLogger = [[DDFileLogger alloc] initWithLogFileManager:documentsFileManager];
[DDLog addLogger:self.fileLogger];

The method for sending log:

NSArray* logFilePaths = [[self.fileLogger logFileManager] sortedLogFilePaths];
NSMutableArray* logFileDataArray = [[NSMutableArray alloc] init];

// Collect log file paths
for (NSString* logFilePath in logFilePaths) {
    NSURL* fileURL = [NSURL fileURLWithPath:logFilePath];
    NSData* logFileData = [NSData dataWithContentsOfURL:fileURL];
    if (logFileData) {
        // Insert at front to reverse the order, so that oldest logs appear first.
        [logFileDataArray insertObject:logFileData atIndex: 0];
    }
}  

NSMutableData* attachmentData = [[NSMutableData alloc] init];

// Collect log data from all log files        
for (NSData* logFileData in logFileDataArray) {
    [attachmentData appendData: logFileData];
}

// Convert `NSData` to `NSString`
NSString *logDataString = [[NSString alloc] initWithData:attachmentData encoding:NSUTF8StringEncoding];

// Extract the 100 most recent entries (rows) from `attachmentData`


// Convert `NSString` back to `NSData`        
NSData* logDataFinal = [logDataString dataUsingEncoding:NSUTF8StringEncoding];


// Add log data as mail attachment        
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];  
[mail addAttachmentData:logDataFinal mimeType: @"text/plain" fileName: @"diagnostic.log"];
//[mail addAttachmentData:attachmentData mimeType: @"text/plain" fileName: @"diagnostic.log"];

Solution

  • Here is the solution, had to convert from NSData into NSArray for it to work.

    NSString *logDataString = [[NSString alloc] initWithData:attachmentData encoding:NSUTF8StringEncoding];
    
    NSMutableArray * logDataArray = [[NSMutableArray alloc] initWithArray:[logDataString componentsSeparatedByString:@"\n"] copyItems: YES];
    unsigned int numberOfLinesToSend = 300;
    unsigned int minRange = 0;
    unsigned int maxRange = 0;
    
    
    // Calculate the range            
    if (numberOfLinesToSend != 0) {
        // If the number of lines is greater than 0, otherwise keep both min and max set to 0
        if ([logDataArray count]-1>numberOfLinesToSend) {
            // If the range does not exceed the number of entries, set both min and max
            minRange = [logDataArray count]-1-numberOfLinesToSend;
            maxRange = [logDataArray count]-minRange;
        } else {
            // Otherwise set to full range
            axRange = [logDataArray count];
        }
    }
    DDLogInfo(@"Creating log: [logDataArray count]=%i",[logDataArray count]);
    DDLogInfo(@"Creating log: NSMakeRange(%i,%i)",minRange, maxRange);
    
    // Extract the 100 most recent entries (rows) from `attachmentData`
    NSArray * selectedLinesArray = [logDataArray subarrayWithRange:NSMakeRange(minRange,maxRange)];
    
    // Convert `NSArray` back to `NSString`
    NSString * selectedLinesString = [selectedLinesArray componentsJoinedByString:@"\n"];
    
    // Convert `NSString` back to `NSData`        
    NSData* logDataFinal = [selectedLinesString dataUsingEncoding:NSUTF8StringEncoding];
    
    // Add log data as mail attachment 
    MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
    [mail addAttachmentData:logDataFinal mimeType: @"text/plain" fileName: @"diagnostic.log"];