Every package has a LogRecordImpl table in its own database. The SAP Mobile Server can send import messages with LogRecordImpl records as part of its response to replay requests (success or failure). LogRecord stores two types of logs.
The SAP Mobile 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 = [SMP101Sales_order findAll]; if([salesorders size] > 0) { SMP101Sales_order * so = [salesorders item:0]; SMP101LogRecordImpl *lr = [SMP101LogRecordImpl getInstance]; lr.message = :@"testing record"]; lr.level = [SUPLogLevel INFO]; [lr save]; // submitting log records [SMP101SMP101DB submitLogRecords]; // synchronize with server [SMP101SMP101DB synchronize:@"system"]; } }
You can use the getLogRecords method to return log records from the table.
SUPQuery *query = [SUPQuery getInstance]; SUPObjectList *loglist = [SMP101SMP101DB 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 = [SMP101Sales_order findAll]; if([salesorders size] > 0) { SMP101Sales_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 = [SMP101SMP101DB 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 = [SMP101SMP101DB 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]];
This sample code shows how to find the corresponding MBO with the LogRecord and to delete the log record when a record is processed.
- (void)processLogs { SUPQuery *query = [SUPQuery getInstance]; SUPObjectList *logRecords = [SMP101SMP101DB getLogRecords:query]; for(id<SUPLogRecord> log in logRecords) { // Log warning message NSLog(@"log %@: %@ code:%d msg:%@",[log component],[log entityKey],[log code],[log message]); if([[log component] isEqualToString:@"Customer"]) { NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; int64_t surrogateKey = [[formatter numberFromString:[log entityKey]] longLongValue]; [formatter release]; SMP101Customer *c = [SMP101Customer find:surrogateKey]; if(c.pending) [c cancelPending]; [log delete]; [log submitPending]; } } }