You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Objective-C的os_log API获取iOS设备日志

Objective-C 基于OSLog API实现iOS日志采集方案

iOS 10开始苹果废弃了原有的ASL日志接口,改用OSLog作为系统日志框架,以下是使用OSLog采集日志用于远程上报的实现方案:

权限与版本说明

  • 仅iOS 10及以上系统支持OSLog相关能力
  • 普通沙箱应用默认仅可采集当前应用自身输出的OSLog日志,若需采集全系统日志,需要特殊系统授权(仅支持MDM管控应用、企业内部定制系统应用,普通App Store上架应用无法获取该权限)
  • iOS 15及以上系统提供了公开的日志读取接口,iOS 14及以下版本需使用私有API实现日志读取,私有API存在App Store审核被拒风险,仅适合企业内部分发场景使用

iOS 15+ 公开API实现方案

苹果在iOS 15推出了OSLogStore公开类用于读取系统存储的OSLog日志,Objective-C调用示例如下:

#import <Foundation/Foundation.h>
#import <OSLog/OSLogStore.h>
#import <OSLog/OSLogEntry.h>

/// 采集最近1小时内的OSLog日志
/// - Parameter completion: 采集完成回调,返回格式化后的日志数组或错误信息
- (void)collectRecentOSLogsWithCompletion:(void(^)(NSArray<NSString *> * _Nullable logs, NSError * _Nullable error))completion {
    NSError *initError = nil;
    // 初始化日志存储实例,OSLogStoreScopeSystem表示读取系统维度日志,普通应用默认仅能拿到自身进程日志
    OSLogStore *logStore = [[OSLogStore alloc] initWithScope:OSLogStoreScopeSystem error:&initError];
    if (!logStore) {
        completion(nil, initError);
        return;
    }
    
    // 配置查询条件:仅查询最近1小时的日志
    NSTimeInterval timeRange = 60 * 60;
    NSDate *startTime = [NSDate dateWithTimeIntervalSinceNow:-timeRange];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"date >= %@", startTime];
    // 若仅需采集当前应用日志,可新增条件:@"process == %@", [[NSProcessInfo processInfo] processName]
    
    NSError *queryError = nil;
    NSMutableArray<NSString *> *logResult = [NSMutableArray array];
    // 遍历匹配的日志条目
    [logStore enumerateEntriesWithPredicate:predicate options:0 error:&queryError usingBlock:^(OSLogEntry * _Nonnull entry, BOOL * _Nonnull stop) {
        // 按需拼接日志字段,可扩展进程ID、子系统、类别、日志级别等信息
        NSString *formattedLog = [NSString stringWithFormat:@"[%@] [%@:%d] %@", 
            entry.date, 
            entry.process, 
            entry.processIdentifier,
            entry.composedMessage];
        [logResult addObject:formattedLog];
    }];
    
    if (queryError) {
        completion(nil, queryError);
        return;
    }
    completion(logResult.copy, nil);
}

iOS 10~14 兼容实现方案

iOS 14及以下没有公开的OSLog读取接口,需要通过动态加载私有API实现日志采集,实现示例如下:

#import <Foundation/Foundation.h>
#include <dlfcn.h>

// 私有接口枚举定义
typedef NS_ENUM(uint32_t, OSLogCopyType) {
    OSLogCopyTypeInfo = 1 << 4,
    OSLogCopyTypeError = 1 << 5,
    OSLogCopyTypeFault = 1 << 6
};

typedef void (^OSLogEnumerateBlock)(NSDictionary *entry, BOOL *stop);

// 私有方法指针声明
static NSArray* (*os_log_copy_entries)(NSDate *start, NSDate *end, OSLogCopyType type, NSError **error) = NULL;
static void (*os_log_enumerate_entries)(NSArray *entries, OSLogEnumerateBlock block) = NULL;

/// 动态加载OSLog私有API
+ (void)loadPrivateAPI {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        void *libHandle = dlopen("/usr/lib/system/libsystem_trace.dylib", RTLD_LAZY);
        if (libHandle) {
            os_log_copy_entries = dlsym(libHandle, "os_log_copy_entries");
            os_log_enumerate_entries = dlsym(libHandle, "os_log_enumerate_entries");
        }
    });
}

/// 采集iOS 14及以下系统的OSLog日志
- (NSArray<NSString *> *)collectLegacyOSLogsWithError:(NSError **)error {
    [Self loadPrivateAPI];
    if (!os_log_copy_entries || !os_log_enumerate_entries) {
        if (error) {
            *error = [NSError errorWithDomain:@"OSLogCollect" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"私有API加载失败"}];
        }
        return nil;
    }
    
    // 查询最近1小时日志
    NSDate *startTime = [NSDate dateWithTimeIntervalSinceNow:-3600];
    NSArray *entries = os_log_copy_entries(startTime, nil, OSLogCopyTypeInfo | OSLogCopyTypeError, error);
    if (!entries) {
        return nil;
    }
    
    NSMutableArray *logs = [NSMutableArray array];
    os_log_enumerate_entries(entries, ^(NSDictionary *entry, BOOL *stop) {
        NSString *logMsg = entry[@"composedMessage"];
        NSString *process = entry[@"process"];
        NSDate *logDate = entry[@"date"];
        NSString *formattedLog = [NSString stringWithFormat:@"[%@] [%@] %@", logDate, process, logMsg];
        [logs addObject:formattedLog];
    });
    return logs.copy;
}

上报优化建议

  • 日志采集逻辑放在子线程执行,避免阻塞主线程UI交互
  • 采集到的日志先做本地缓存、压缩,再批量上报,降低流量损耗和上报请求次数
  • 敏感信息采集前需做脱敏处理,符合隐私合规要求

内容的提问来源于stack exchange,提问作者John_S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 17:48:04