iOS 8设备日志读取的API

3

这个应用程序 "System Console"(由Electric Labs Ltd公司制作)如何访问iOS 8上的设备日志?

我正在尝试做同样的事情,但我只能得到自己应用程序的日志消息。 我正在使用Apple System Logging facility的API,遵循这篇文章 "Accessing the iOS System Log"中的示例。

我知道由于iOS 7+中的沙盒子系统,我的应用程序只能看到自己的日志消息。但我想知道“系统控制台”应用程序是如何避免这种限制的?


提供更多细节。 - annu
@annu 为什么他们需要提供更多信息?很明显他们想要什么。 - Popeye
@Popeye,我已经清楚地解释了上一个答案。 - annu
1
@annu你的评论毫无意义。 - Popeye
该应用在iOS 9(beta 1)上停止工作。 - Martijn Thé
显示剩余3条评论
3个回答

6

看起来你可以读取 "syslog.sock"。我在Github上找到了一个适用于iOS8的项目:https://github.com/eswick/ondeviceconsole

我创建了以下测试代码(空项目),并运行它以查看控制台中的当前日志信息。它识别了启动邮件应用程序、笔记应用程序等。这些信息需要解析,但这是另一个问题。(警告:下面的代码很丑!)请善用,不要用于恶意 ;)

//
//  ViewController.m
//  LogTest
//
//  Created by Freek Sanders on 26-02-15.

#import "ViewController.h"
#import <asl.h>

#import <sys/socket.h>
#import <sys/un.h>

#import <unistd.h>
#import <fcntl.h>
#import <poll.h>



#define SOCKET_PATH "/var/run/lockdown/syslog.sock"

#define COLOR_RESET         "\e[m"
#define COLOR_NORMAL        "\e[0m"
#define COLOR_DARK          "\e[2m"
#define COLOR_RED           "\e[0;31m"
#define COLOR_DARK_RED      "\e[2;31m"
#define COLOR_GREEN         "\e[0;32m"
#define COLOR_DARK_GREEN    "\e[2;32m"
#define COLOR_YELLOW        "\e[0;33m"
#define COLOR_DARK_YELLOW   "\e[2;33m"
#define COLOR_BLUE          "\e[0;34m"
#define COLOR_DARK_BLUE     "\e[2;34m"
#define COLOR_MAGENTA       "\e[0;35m"
#define COLOR_DARK_MAGENTA  "\e[2;35m"
#define COLOR_CYAN          "\e[0;36m"
#define COLOR_DARK_CYAN     "\e[2;36m"
#define COLOR_WHITE         "\e[0;37m"
#define COLOR_DARK_WHITE    "\e[0;37m"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    int nfd = unix_connect(SOCKET_PATH);

    // write "watch" command to socket to begin receiving messages
    write(nfd, "watch\n", 6);

    struct pollfd pfd[2];
    unsigned char buf[16384];
    int n = fileno(stdin);
    int lfd = fileno(stdout);
    int plen = 16384;

    pfd[0].fd = nfd;
    pfd[0].events = POLLIN;

    while (pfd[0].fd != -1) {

        if ((n = poll(pfd, 1, -1)) < 0) {
            close(nfd);
            perror("polling error");
            exit(1);
        }

        if (pfd[0].revents & POLLIN) {
            if ((n = read(nfd, buf, plen)) < 0)
                perror("read error"), exit(1); /* possibly not an error, just disconnection */
            else if (n == 0) {
                shutdown(nfd, SHUT_RD);
                pfd[0].fd = -1;
                pfd[0].events = 0;
            } else {
                if (atomicio(write_colored, lfd, buf, n) != n)
                    perror("atomicio failure"), exit(1);
            }
        }
    }
}

size_t atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
{
    char *s = _s;
    size_t pos = 0;
    ssize_t res;
    struct pollfd pfd;

    pfd.fd = fd;
    pfd.events = f == read ? POLLIN : POLLOUT;
    while (n > pos) {
        res = (f) (fd, s + pos, n - pos);
        switch (res) {
            case -1:
                if (errno == EINTR)
                    continue;
                if ((errno == EAGAIN) || (errno == ENOBUFS)) {
                    (void)poll(&pfd, 1, -1);
                    continue;
                }
                return 0;
            case 0:
                errno = EPIPE;
                return pos;
            default:
                pos += (size_t)res;
        }
    }
    return (pos);
}

int unix_connect(char* path) {
    struct sockaddr_un sun;
    int s;

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
        return (-1);
    (void)fcntl(s, F_SETFD, 1);

    memset(&sun, 0, sizeof(struct sockaddr_un));
    sun.sun_family = AF_UNIX;

    if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) {
        close(s);
        errno = ENAMETOOLONG;
        return (-1);
    }
    if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0) {
        close(s);
        return (-1);
    }

    return (s);
}

#define LINE_REGEX "(\\w+\\s+\\d+\\s+\\d+:\\d+:\\d+)\\s+(\\S+|)\\s+(\\w+)\\[(\\d+)\\]\\s+\\<(\\w+)\\>:\\s(.*)"

ssize_t write_colored(int fd, void* buffer, size_t len) {

    char *escapedBuffer = malloc(len + 1);
    memcpy(escapedBuffer, buffer, len);
    escapedBuffer[len] = '\0';

    NSString *str = [NSString stringWithUTF8String:escapedBuffer];
    free(escapedBuffer);

    NSError *error = nil;
    NSRegularExpression *regex = [NSRegularExpression
                                  regularExpressionWithPattern:@LINE_REGEX
                                  options:NSRegularExpressionCaseInsensitive
                                  error:&error];

    NSArray *matches = [regex matchesInString:str
                                      options:0
                                        range:NSMakeRange(0, [str length])];

    if ([matches count] == 0)
        return write(fd, buffer, len);

    for (NSTextCheckingResult *match in matches) {

        if ([match numberOfRanges] < 6) {
            write(fd, buffer, len); // if entry doesn't match regex, print uncolored
            continue;
        }

        NSRange dateRange    =  [match rangeAtIndex:1];
        NSRange deviceRange  =  [match rangeAtIndex:2];
        NSRange processRange =  [match rangeAtIndex:3];
        NSRange pidRange     =  [match rangeAtIndex:4];
        NSRange typeRange    =  [match rangeAtIndex:5];
        NSRange logRange     =  [match rangeAtIndex:6];

        NSString *date       =  [str substringWithRange:dateRange];
        NSString *device     =  [str substringWithRange:deviceRange];
        NSString *process    =  [str substringWithRange:processRange];
        NSString *pid        =  [str substringWithRange:pidRange];
        NSString *type       =  [str substringWithRange:typeRange];
        NSString *log        =  [str substringWithRange:
                                 NSMakeRange(logRange.location,
                                             [str length] - logRange.location)];

        log = [log stringByTrimmingCharactersInSet:
               [NSCharacterSet newlineCharacterSet]];

        NSMutableString *build = [NSMutableString new];

        [build appendString:@COLOR_DARK_WHITE];
        [build appendString:date];
        [build appendString:@" "];
        [build appendString:device];
        [build appendString:@" "];

        [build appendString:@COLOR_CYAN];
        [build appendString:process];
        [build appendString:@"["];
        [build appendString:pid];
        [build appendString:@"]"];

        char *typeColor = COLOR_DARK_WHITE;
        char *darkTypeColor = COLOR_DARK_WHITE;

        if ([type isEqualToString:@"Notice"]) {
            typeColor = COLOR_GREEN;
            darkTypeColor = COLOR_DARK_GREEN;
        } else if ([type isEqualToString:@"Warning"]) {
            typeColor = COLOR_YELLOW;
            darkTypeColor = COLOR_DARK_YELLOW;
        } else if ([type isEqualToString:@"Error"]) {
            typeColor = COLOR_RED;
            darkTypeColor = COLOR_DARK_RED;
        } else if ([type isEqualToString:@"Debug"]) {
            typeColor = COLOR_MAGENTA;
            darkTypeColor = COLOR_DARK_MAGENTA;
        }

        [build appendString:@(darkTypeColor)];
        [build appendString:@" <"];
        [build appendString:@(typeColor)];
        [build appendString:type];
        [build appendString:@(darkTypeColor)];
        [build appendString:@">"];
        [build appendString:@COLOR_RESET];
        [build appendString:@": "];
        [build appendString:log];

        printf("%s\n", [build UTF8String]);
    }

    return len;
}

@end

是的,我的设备没有越狱。 - Freek Sanders
我在模拟器(XCode 6.1,iOS 8.1)上尝试了您的代码,但它没有起作用,代码找不到套接字的路径 "/var/run/lockdown/syslog.sock" (也许模拟器上套接字的位置不同)。我明天会在真实设备上尝试。这是我在模拟器上使用的测试代码:https://gist.github.com/m-amazirh/1b64d6e5107a74f8ce72在我的情况下,在模拟器上测试时,执行停在第[31]行(https://gist.github.com/m-amazirh/1b64d6e5107a74f8ce72#file-lorgretriever-L31)。错误是**“没有这样的文件或目录”**。 - Mohamed AMAZIRH
@Freek Sanders:仍然无法在iPhone上进行测试,但您说它在您的设备上可以运行,因此我在奖励到期之前授予了您赏金。在我尝试在真实设备上运行代码后,我将使用更多信息更新问题。 - Mohamed AMAZIRH
还没检查过iOS9的测试版(你真是个快手);) - Freek Sanders
1
我无法在iOS 9.2.1上使其工作。我不确定应该怎么做,但我收到了一个“nfd = -1”的错误提示,感觉不对劲。有关这个iOS版本的任何消息吗? - Felipe
显示剩余6条评论

0
请看下面的代码:
 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);

这种方法自iOS 7以来就不再适用了。你只能读取自己的日志条目。 - Helge Becker
这是我首先尝试的方法(我在我的问题中提到了这一点)。我正在寻找替代方案,因为iOS7+上的ASL仅允许访问由您自己的应用程序创建的消息日志(您无法查看其他应用程序创建的消息日志)。这是由于iOS7中引入的沙盒系统。@Freek Sanders提供的示例适用于iOS7+。 - Mohamed AMAZIRH

0

在这一行无法连接到套接字,是否有其他可用的替代方法?

if (connect(s, (struct sockaddr *)&sun, SUN_LEN(&sun)) < 0)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接