Optimize apple system logs - ios

+ (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.

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.

Related

Sqlite shows EXC_BAD_ACCESS while executing query in ios

The code I am using for executing the query is as below:
NSString *score_query = #"Insert into tbl_assessment (Question,Answer,Option1,Option2,Option3,Explanation,Used,ImageName,Reference) values ('All of the following questions would be asked in a lifestyle questionnaire except:','Do you feel any pain in your chest when you perform physical activity?','Does your occupation cause you anxiety (mental stress)?','Does your occupation require extended periods of sitting?','Do you partake in any recreational activities (golf, tennis, skiing, etc.)?','NULL','N','NULL','NULL')";
NSLog(#"%#",score_query);
[database executeQuery:score_query];
I have generated this query dynamically. But I have added the query directly to the string.
But when I tried to execute this insert query, app crashes on below function:
- (NSArray )executeQuery:(NSString )sql, ... {
va_list args;
va_start(args, sql);
NSMutableArray *argsArray = [[NSMutableArray alloc] init];
NSUInteger i;
for (i = 0; i < [sql length]; ++i)
{
if ([sql characterAtIndex:i] == '?')
[argsArray addObject:va_arg(args, id)];
}
va_end(args);
NSArray *result = [self executeQuery:sql arguments:argsArray];
[argsArray release];
return result;
}
The dropbox for the classes I am using for database operation is given below:
https://www.dropbox.com/s/c4haxqnbh0re41c/Archive%202.zip?dl=0
I have already referred the below link but can't understand.
Sqlite shows EXC_BAD_ACCESS in ios SDK
In your example, you are only passing one argument to execQuery:, but your implementation is trying to pull additional arguments from the varargs every time it sees a '?' in the string, of which there are numerous '?'s.
That's causing the crash.

AWS Batch request for multi items filtered by array of values

I would like to ask about filterExpression for AWSDynamoDBScanExpression.
Problem:
I want to scan db for all object in one table where one parameter (lets call it uniqueId) is one of the value stored in array (array of required uniqueIds).
For one object - it's easy to do with
AWSDynamoDBScanExpression *scanExpression = [[AWSDynamoDBScanExpression alloc] init];
scanExpression.expressionAttributeNames = #{
#"#P": [NSString stringWithFormat:#"%#", property]
};
scanExpression.filterExpression =#"#P = :val";
scanExpression.expressionAttributeValues = #{
#":val" : #"some uniqueID"
};
so in same logic i want to scan db for multi objects
AWSDynamoDBScanExpression *scanExpression = [[AWSDynamoDBScanExpression alloc] init];
scanExpression.expressionAttributeNames = #{
#"#P": [NSString stringWithFormat:#"%#", property]
};
scanExpression.filterExpression = <WHAT SHOULD BE HERE, WHAT EXPRESSION>;
scanExpression.expressionAttributeValues = #{
#":val" : [#"some unique id 1",
#"some unique id 2",
#"some unique id 3"]
};
Is any way to change scanExpression.filterExpression to achive this?
EDIT 1
No, I'm not sure that scan is the best solution. Actually query is best variant think.
The structure of table
#P = :val1 OR #P = :val2
make sense
EDIT2
This is some update:
AWSDynamoDBQueryExpression *query = [[AWSDynamoDBQueryExpression alloc] init];
NSMutableDictionary *dictionaryAttributes = [[NSMutableDictionary alloc] init];
NSString *expression = #"";
for (int i = 0; i < filteredHashValues.count; i++) {
NSString *variableName = [NSString stringWithFormat:#":val%i", i];
[dictionaryAttributes setValue:filteredHashValues[i] forKey:variableName];
expression = [expression stringByAppendingString:expression.length ? [NSString stringWithFormat:#"OR #P = %# " , variableName] : [NSString stringWithFormat:#"#P = %# " , variableName]];
}
query.indexName = #"uniqueId-index";
query.expressionAttributeNames = #{
#"#P": [NSString stringWithFormat:#"%#", #"uniqueId"]
};
query.filterExpression = expression;
query.expressionAttributeValues = dictionaryAttributes;
AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
[[dynamoDBObjectMapper query:className expression:query] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) {
if (task.result) {
AWSDynamoDBPaginatedOutput *output = task.result;
}
return nil;
}];
But result
Printing description of expression:
#P = :val0 OR #P = :val1 OR #P = :val2 OR #P = :val3
Printing description of dictionaryAttributes:
{
":val0" = "8A93A3EA-9FB9-4396-BBF6-D0BD3CBE6BE5";
":val1" = "08533EBA-D3E5-406C-8CDE-03EECCCA801B";
":val2" = "954AE402-336E-423D-BF03-7E8AED1446FE";
":val3" = "F683BDF8-0507-4218-9927-9F14D470E593"; }
Printing description of task->_error: Error
`Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=0 "(null)"
UserInfo={__type=com.amazon.coral.validate#ValidationException,
message=ExpressionAttributeValues contains invalid value: Supplied
AttributeValue is empty, must contain exactly one of the supported
datatypes for key :awsddbomhashvalueplaceholder}
looks like ExpressionAttributeValues is empty - am i doing all correct?
are you sure that you want to use a scan expression? this really consumes a lot of read capacity and can ruine your dynamodb performances: a scan reads you entire table and only THEN applies the filter and returns the values.
if you provide us with your actual dynamodb table structure we could maybe discuss another solution. For example a solution could be to create a global secondary index (if eventual consistent read is ok for you) or a local secondary index (along with its limitations), with a range key on your value to filter. This would allow you to use queries, which is much nicer and advised as of best practices.
That been said, you can just add conditions to your filter using AND and OR operators, resulting in sth similar to "#P = :val1 OR #P = :val2"
hope that helps

Is it possible to read app specific warning messages?

I want to read the console of my application. My aim is find all messages like this:
Warning: Attempt to present <ChildViewController: 0x7b44e380> on <TopViewController: 0x7a65e5b0> which is already presenting (null)
I founded that on iOS7 you can’t read system messages.
Using Objective C to read log messages posted to the device console
In iOS 7 you can use ASL to read messages output by your own app, including on previous runs of the same build of your app, but not messages output by the system or by any other apps.
For my mind any warnings is a system messages. May be something changes on ios8?
It's possible to read from the "syslog.sock". There is source on Github which works under iOS8: https://github.com/eswick/ondeviceconsole
ASL no longer works from iOS7 onwards for system wide logs, iOS 7+ apps can only see their own log messages due to increased sandboxing.
If you only want to see your own app's logs, you can still use ASL:
aslmsg q, m;
int i;
const char *key, *val;
q = asl_new(ASL_TYPE_QUERY);
aslresponse r = asl_search(NULL, q);
while (NULL != (m = aslresponse_next(r)))
{
NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
for (i = 0; (NULL != (key = asl_key(m, i))); i++)
{
NSString *keyString = [NSString stringWithUTF8String:(char *)key];
val = asl_get(m, key);
NSString *string = val?[NSString stringWithUTF8String:val]:#"";
[tmpDict setObject:string forKey:keyString];
}
NSLog(#"%#", tmpDict);
}
aslresponse_free(r);

How do I compare characters in custom sqlite collation in objective-c?

I went through lots of questions here on SO (like this one) but I still need some assistance.
I need my sqlite select to order by slovenian alphabet (letter č comes after c, letter š after s and letter ž after z).
Here is the code I use:
static int sqlite3SloCollate(void * foo, int ll, const void *l, int rl,
const void *r){
NSString *left = [NSString stringWithCharacters:l length:ll];
NSString *right = [NSString stringWithCharacters:r length:rl];
//THIS IS WHERE I DON'T KNOW HOW TO COMPARE CHARACTERS
NSComparisonResult rs = [left compare:right options:NSForcedOrderingSearch];
return rs;
}
sqlite3_create_collation(database, "SLOCOLLATE", SQLITE_UTF8, NULL, &sqlite3SloCollate);
querySQL = [NSString stringWithFormat: #"SELECT s.id FROM lyrics l INNER JOIN song s ON (l.idSong=s.id) WHERE content LIKE '%%%#%%' GROUP BY s.id ORDER BY s.title COLLATE SLOCOLLATE;",searchString];
Which NSOrdering type should I use? Or do I have to write my own compare function (can you give me an example)?
I think that this function might help you :
- (NSComparisonResult)compare:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)range locale:(id)locale
(From Apple documentation).
You can create a locale using :
- (id)initWithLocaleIdentifier:(NSString *)string
(From Apple NSLocale Class Documentation).
This code should do the trick :
NSRange range = NSMakeRange(0, [left length]);
id locale = [[NSLocale alloc] initWithLocaleIdentifier:#"sl_SI"];
NSComparisonResult rs = [left compare:right options:NSForcedOrderingSearch range:range locale:locale];
I hope this will help.
The #DCMaxxx answer has most of it. Plus the comment that you need to use stringWithUTF8String. But there's some more issues.
1) stringWithUTF8String uses null-terminated c-strings, whilst sqlite is suppling strings with just a length and no null termination.
2) For the number of characters to compare, we need to take the shortest length, not just the left length.
3) When the comparison is equal for the compare, we then need to consider which string is longer.
Full code here. I use an NSMutableData object to convert length coded strings to null terminated strings. It's probably quicker and easier to do it with straight c code, if you are that way inclined.
static int sqlite3SloCollate(void * foo, int ll, const void *l, int rl,
const void *r){
NSMutableData* ld = [NSMutableData dataWithBytes:l length:ll+1];
[ld resetBytesInRange:NSMakeRange(ll, 1)];
NSString *left = [NSString stringWithUTF8String:[ld bytes]];
NSMutableData* rd = [NSMutableData dataWithBytes:r length:rl+1];
[rd resetBytesInRange:NSMakeRange(rl, 1)];
NSString *right = [NSString stringWithUTF8String:[rd bytes]];
NSRange range = NSMakeRange(0, MIN([left length],[right length]));
id locale = [[NSLocale alloc] initWithLocaleIdentifier:#"sl_SI"];
NSComparisonResult result = [left compare:right options:0 range:range locale:locale];
if (result==NSOrderedSame) {
if (ll>rl) {
result = NSOrderedDescending;
} else if (ll<rl) {
result = NSOrderedAscending;
}
}
// NSLog(#"Comparison:%# - %# - %li",left,right,(long)result);
return result;
}

Parsing json returned by foursquare for iPhone gives Unrecognised leading character

I'm trying to get the nearby places using the foursquare api.
Here's the json data that is returned from
NSDictionary *results = [jsonString JSONValue];
NSLog(#"%#", results);
(
{
code = 200;
errorDetail = "This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.";
errorType = deprecated;
},
{
groups = (
{
items = (
{
categories = (
{
icon = "https://foursquare.com/img/categories/parks_outdoors/default.png";
id = 4bf58dd8d48988d163941735;
name = Park;
parents = (
"Great Outdoors"
);
pluralName = Parks;
primary = 1;
shortName = Park;
}
);
Then I try to get the list of the groups in an array with
NSArray *groups = [ (NSDictionary *)results objectForKey:#"groups"];
This returns the following error
2011-11-05 11:42:12.907 XperienzApp[1972:207] No of results returned: 0 Results : (null)
2011-11-05 11:42:13.225 XperienzApp[1972:207] -JSONValue failed. Error trace is: (
"Error Domain=org.brautaset.JSON.ErrorDomain Code=3 \"Unrecognised leading character\" UserInfo=0x5849cd0 {NSLocalizedDescription=Unrecognised leading character}"
)
2011-11-05 11:42:13.225 XperienzApp[1972:207] No of results returned: 0 Results : (null)
How should I parse this?
Edit:
I tried the suggested technique, this gives me an array
id groups = [[(NSDictionary *)results objectForKey:#"response"] objectForKey:#"groups"];
if ([results count] > 1){
NSLog(#"groups class %#\ngroups %# %d", groups, [groups class], [groups count]);
The log output is of the form:
{
categories = (
{
icon = "https://foursquare.com/img/categories/nightlife/danceparty.png";
id = 4bf58dd8d48988d11f941735;
name = Nightclub;
parents = (
"Nightlife Spots"
);
pluralName = Nightclubs;
primary = 1;
shortName = Nightclub;
}
);
contact = {
};
hereNow = {
count = 0;
};
id = 4eb33ba561af0dda8f673c1b;
location = {
address = "144 Willow St 4R";
city = Brooklyn;
crossStreet = Pierrepont;
distance = 462;
lat = "40.696864";
lng = "-73.996409";
postalCode = 11201;
state = NY;
};
name = "Entertainment 720, Ltd.";
stats = {
checkinsCount = 3;
tipCount = 0;
usersCount = 1;
};
verified = 0;
}
);
name = Nearby;
type = nearby;
}
)
groups __NSArrayM 1
This is again not json and is hard to parse, how do I get the output in json.
I'm the iPhone lead at foursquare. I'll try to take a stab at what's going on here.
First of all, I highly recommend you use JSONKit for your parser. It's lightweight and insanely fast: https://github.com/johnezang/JSONKit
It appears that you are parsing the JSON properly and getting the dictionary properly. Then you are logging the parsed object, not the original JSON. The output you are seeing is how Objective-C chooses to serialize the parsed dictionary to text. It is definitely not JSON. Using JSONKit, you could send the JSONString selector to your parsed result and convert it back to JSON and log that.
If you could provide some details on the problem you are trying to solve, I might be able to help you out more. And as Maudicus said, please pay attention to the error you are getting back. You don't want your app to break when we make the change to the API.
If the output below NSLog(#"%#", results); is your log statement. It appears your results variable is an array of dictionary objects.
Try to log the class of results to verify that NSLog(#"%#", [results class]);
If it is an array your groups object is the second object.
if ([results count] > 1)
id groups = [results objectAtIndex:1];
NSLog(#"groups class %#\ngroups %#", [groups class], groups);
Keep doing this until you understand the format of your data
Also the line
errorDetail = "This endpoint will stop returning groups in the future. Please use a current version, see http://bit.ly/lZx3NU.";
should be cause for concern. Check the documentation on foursquare for the current way of getting groups.

Resources