Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimize apple system logs

+ (NSArray *)systemLogDictionariesForAppName:(NSString *)appName {   
  aslmsg q = asl_new(ASL_TYPE_QUERY);
  asl_set_query(q, ASL_KEY_SENDER, [appName cStringUsingEncoding:NSASCIIStringEncoding], ASL_QUERY_OP_EQUAL);
  aslresponse r = asl_search(NULL, q);
  aslmsg m;
  uint32_t i;
  const char *key, *val;
  NSMutableArray *systemLogDictionaries = [NSMutableArray array];

  while (NULL != (m = aslresponse_next(r)))
  {
      NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
      for (i = 0; (NULL != (key = asl_key(m, i))); i++)
      {
          val = asl_get(m, key);
          NSString *stringKey = [NSString stringWithCString:key encoding:NSUTF8StringEncoding];
          NSString *stringVal = [NSString stringWithCString:val encoding:NSUTF8StringEncoding];

          [dictionary setObject:stringVal forKey:stringKey];
      }
      [systemLogDictionaries addObject:dictionary];
  }
  aslresponse_free(r);

  return systemLogDictionaries;
}

Above code will get apple system log. Problem is, it take around 8second to pull all the logs from Apple System Log (ASL). Is there any way to optimize asl_set_query to get data faster or any other way which I am missing.

Note: Can we create a ASL query which will take time stamp and we can get less number of data to process. This will solve the problem I think.

like image 374
AAV Avatar asked Oct 03 '22 12:10

AAV


1 Answers

ASL supports a few different logging levels, so you could specify a more restrictive level.

For example you can add another query (according to the man page they are joined via the logical AND):

    // ...
    asl_set_query(q, ASL_KEY_SENDER, [appName cStringUsingEncoding:NSASCIIStringEncoding], ASL_QUERY_OP_EQUAL);
    // 3 is error messages
    asl_set_query(q, ASL_KEY_LEVEL, "3", ASL_QUERY_OP_LESS_EQUAL | ASL_QUERY_OP_NUMERIC);

    //-- Check for time --//

    /* A dumped entry with your code looks like:

         ASLMessageID = 1825403;
         "CFLog Local Time" = "2013-07-20 08:33:12.943";
         "CFLog Thread" = 951f;
         Facility = "com.apple.Safari";
         GID = 20;
         Host = "XXX.local";
         Level = 4;
         Message = "CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary on line 3. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolon to debug.";
         PID = 183;
         ReadUID = 501;
         Sender = Safari;
         Time = 1374305592;
         TimeNanoSec = 943173000;
         UID = 501;

    Time is a Unix timestamp, so you can use it in your query with ASL_KEY_TIME and one of these operators: ASL_QUERY_OP_EQUAL, ASL_QUERY_OP_GREATER, ASL_QUERY_OP_GREATER_EQUAL, ASL_QUERY_OP_LESS, ASL_QUERY_OP_LESS_EQUAL, ASL_QUERY_OP_NOT_EQUAL

    The code below, generates a unix timestamp for yesterday and dumps all messages that occurred yesterday or later. 
    (Nevermind the dirty/hacky way I generate the timestamp, that was just for testing purposes)
*/
    NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow: -(60.0f*60.0f*24.0f)];
    NSString *theDate = [NSString stringWithFormat:@"%d", (int)[yesterday timeIntervalSince1970]];

    asl_set_query(q, ASL_KEY_TIME, [theDate cStringUsingEncoding:NSASCIIStringEncoding], ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC);
    aslresponse r = asl_search(NULL, q);
    //...

For some more information on the different error levels check: http://www.cocoanetics.com/2011/03/accessing-the-ios-system-log/

Note that, depending on the level you set and the level your log messages are, further filtering may have no effect (ie. if all messages that are actually logged for your app are of the same level)

Further note, unlike the debug level querying, I haven't yet used the timestamp querying in any productive code, but in a test it seems to work perfectly fine and is doing what it is supposed to do.

like image 158
tttthomasssss Avatar answered Oct 21 '22 13:10

tttthomasssss