You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.6 KiB
154 lines
4.6 KiB
//
|
|
// FLEXASLLogController.m
|
|
// FLEX
|
|
//
|
|
// Created by Tanner on 3/14/19.
|
|
// Copyright © 2019 Flipboard. All rights reserved.
|
|
//
|
|
|
|
#import "FLEXASLLogController.h"
|
|
#import <asl.h>
|
|
|
|
// Querrying the ASL is much slower in the simulator. We need a longer polling interval to keep things repsonsive.
|
|
#if TARGET_IPHONE_SIMULATOR
|
|
#define updateInterval 5.0
|
|
#else
|
|
#define updateInterval 1.0
|
|
#endif
|
|
|
|
@interface FLEXASLLogController ()
|
|
|
|
@property (nonatomic, readonly) void (^updateHandler)(NSArray<FLEXSystemLogMessage *> *);
|
|
|
|
@property (nonatomic, strong) NSTimer *logUpdateTimer;
|
|
@property (nonatomic, readonly) NSMutableIndexSet *logMessageIdentifiers;
|
|
|
|
// ASL stuff
|
|
|
|
@property (nonatomic) NSUInteger heapSize;
|
|
@property (nonatomic) dispatch_queue_t logQueue;
|
|
@property (nonatomic) dispatch_io_t io;
|
|
@property (nonatomic) NSString *remaining;
|
|
@property (nonatomic) int stderror;
|
|
@property (nonatomic) NSString *lastTimestamp;
|
|
|
|
@end
|
|
|
|
@implementation FLEXASLLogController
|
|
|
|
+ (instancetype)withUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler
|
|
{
|
|
return [[self alloc] initWithUpdateHandler:newMessagesHandler];
|
|
}
|
|
|
|
- (id)initWithUpdateHandler:(void(^)(NSArray<FLEXSystemLogMessage *> *newMessages))newMessagesHandler
|
|
{
|
|
NSParameterAssert(newMessagesHandler);
|
|
|
|
self = [super init];
|
|
if (self) {
|
|
_updateHandler = newMessagesHandler;
|
|
_logMessageIdentifiers = [NSMutableIndexSet indexSet];
|
|
self.logUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:updateInterval
|
|
target:self
|
|
selector:@selector(updateLogMessages)
|
|
userInfo:nil
|
|
repeats:YES];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[self.logUpdateTimer invalidate];
|
|
}
|
|
|
|
- (BOOL)startMonitoring {
|
|
[self.logUpdateTimer fire];
|
|
return YES;
|
|
}
|
|
|
|
- (void)updateLogMessages
|
|
{
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
NSArray<FLEXSystemLogMessage *> *newMessages;
|
|
@synchronized (self) {
|
|
newMessages = [self newLogMessagesForCurrentProcess];
|
|
if (!newMessages.count) {
|
|
return;
|
|
}
|
|
|
|
for (FLEXSystemLogMessage *message in newMessages) {
|
|
[self.logMessageIdentifiers addIndex:(NSUInteger)message.messageID];
|
|
}
|
|
|
|
self.lastTimestamp = @(asl_get(newMessages.lastObject.aslMessage, ASL_KEY_TIME) ?: "null");
|
|
}
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self.updateHandler(newMessages);
|
|
});
|
|
});
|
|
}
|
|
|
|
#pragma mark - Log Message Fetching
|
|
|
|
- (NSArray<FLEXSystemLogMessage *> *)newLogMessagesForCurrentProcess
|
|
{
|
|
if (!self.logMessageIdentifiers.count) {
|
|
return [self allLogMessagesForCurrentProcess];
|
|
}
|
|
|
|
aslresponse response = [self ASLMessageListForCurrentProcess];
|
|
aslmsg aslMessage = NULL;
|
|
|
|
NSMutableArray<FLEXSystemLogMessage *> *newMessages = [NSMutableArray array];
|
|
|
|
while ((aslMessage = asl_next(response))) {
|
|
NSUInteger messageID = (NSUInteger)atoll(asl_get(aslMessage, ASL_KEY_MSG_ID));
|
|
if (![self.logMessageIdentifiers containsIndex:messageID]) {
|
|
[newMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
|
}
|
|
}
|
|
|
|
asl_release(response);
|
|
return newMessages;
|
|
}
|
|
|
|
- (aslresponse)ASLMessageListForCurrentProcess
|
|
{
|
|
static NSString *pidString = nil;
|
|
if (!pidString) {
|
|
pidString = @([[NSProcessInfo processInfo] processIdentifier]).stringValue;
|
|
}
|
|
|
|
// Create system log query object.
|
|
asl_object_t query = asl_new(ASL_TYPE_QUERY);
|
|
|
|
// Filter for messages from the current process.
|
|
// Note that this appears to happen by default on device, but is required in the simulator.
|
|
asl_set_query(query, ASL_KEY_PID, pidString.UTF8String, ASL_QUERY_OP_EQUAL);
|
|
// Filter for messages after the last retreived message.
|
|
if (self.lastTimestamp) {
|
|
asl_set_query(query, ASL_KEY_TIME, self.lastTimestamp.UTF8String, ASL_QUERY_OP_GREATER);
|
|
}
|
|
|
|
return asl_search(NULL, query);
|
|
}
|
|
|
|
- (NSArray<FLEXSystemLogMessage *> *)allLogMessagesForCurrentProcess
|
|
{
|
|
aslresponse response = [self ASLMessageListForCurrentProcess];
|
|
aslmsg aslMessage = NULL;
|
|
|
|
NSMutableArray<FLEXSystemLogMessage *> *logMessages = [NSMutableArray array];
|
|
while ((aslMessage = asl_next(response))) {
|
|
[logMessages addObject:[FLEXSystemLogMessage logMessageFromASLMessage:aslMessage]];
|
|
}
|
|
asl_release(response);
|
|
|
|
return logMessages;
|
|
}
|
|
|
|
@end
|