Using the Log Record APIs

Every package has a LogRecordImpl table in its own database. The Unwired Server can send import messages with LogRecordImpl records as part of its response to replay requests (success or failure).

The Unwired Server can embed a "log" JSON array into the header of a server message; the array is written to the LogRecordImpl table by the client. The client application can also write its own records. Each entity has a method called newLogRecord, which allows the entity to write its own log record. The LogRecordImpl table has "component" and "entityKey" columns that associate the log record entry with a particular MBO and primary key value.

SUPObjectList *salesorders = [SampleApp_Sales_order findAll];
  if([salesorders size] > 0)
  {
    SampleApp_Sales_order * so = [salesorders item:0];
    SampleApp_LogRecordImpl *lr = [so newLogRecord: 
      [SUPLogLevel INFO] withMessage:@"testing record"];                 
    MBOLogError(@"Log record is: %@",lr);
        
    // submitting log records
    [SampleApp_SampleAppDB submitLogRecords];
    while ([SampleApp_SampleAppDB hasPendingOperations])
      {
        [NSThread sleepForTimeInterval:0.2];
      }     
  }

You can use the getLogRecords method to return log records from the table.

SUPQuery *query = [SUPQuery getInstance];
  	 SUPObjectList *loglist = [SampleApp_SampleAppDB getLogRecords:query];
	for(id o in loglist)
	{
		LogRecordImpl *log = (LogRecordImpl*)o;
		MBOLogError(@"Log Record %llu: Operation = %@, Timestamp = %@,  
                                 
MBO = %@, key= %@,message=%@",log.messageId,log.operation,
  [SUPDateTimeUtil toString:log.timestamp],log.component,log.entityKey,log.message);
}

Each mobile business object has a getLogRecords instance method that returns a list of all the log records that have been recorded for a particular entity row in a mobile business object:

SUPObjectList *salesorders = [SampleApp_Sales_order findAll];
if([salesorders size] > 0)
{
  SampleApp_Sales_order * so = [salesorders item:0];
  SUPObjectList *loglist = [so getLogRecords];
for(id o in loglist)
{
  LogRecordImpl *log = (LogRecordImpl*)o;
  MBOLogError(@"Log Record %llu: Operation = %@, Timestamp = %@,  
                                 
MBO = %@, key= %@,message=%@",log.messageId,log.operation,
  [SUPDateTimeUtil toString:log.timestamp],log.component,log.entityKey,log.message);
}

Mobile business objects that support dynamic queries can be queried using the synthetic attribute hasLogRecords. This attribute generates a subquery that returns true if an entity row has any log records in the database, otherwise it returns false. The following code example prints out a list of customers, including first name, last name, and whether the customer row has log records:

SUPQuery *query = [SUPQuery getInstance];
[query select:@”x.surrogateKey,x.fname,x.lname,x.hasLogRecords”];
[query from:@”Customer”:@”x”];
SUPQueryResultSet *qrs = [SampleApp_SampleAppDB executeQuery:query];
MBOLogError(@”%@”,[qrs.columnNames toString]);
for(SUPDataValueList *row in qrs.array)
{
  MBOLogError(@”%@”,[row toString]);
}

If there are a large number of rows in the MBO table, but only a few have log records associated with them, you may want to keep an in-memory object to track which rows have log records. You can define a class property as follows:

NSMutableArray* customerKeysWithLogRecords;

After data is downloaded from the server, initialize the array:

customerKeysWithLogRecords = [[NSMutableArray alloc] initWithCapacity:20];
SUPObjectList *allLogRecords = [SampleApp_SampleAppDB getLogRecords:nil];
for(id<SUPLogRecord> lr in allLogRecords)
{
  if(([lr entityKey] != nil) && ([[lr component] compare:@”Customer”] == 0))
    [customerKeysWithLogRecords addObject:[lr entityKey]];
}

You do not need database access to determine if a row in the Customer MBO has a log record. The following expression returns true if a row has a log record:

BOOL hasALogRecord = [customerKeysWithLogRecords containsObject:
                                [customerRow keyToString]];