我们做什么: 我们正在构建一个用于与外部硬件设备通信的应用程序。应用程序可以从外部设备接收日志消息。应用程序已将应用程序事件记录到Sentry项目中。
我们想做什么:
我们希望应用程序将从外部设备接收的日志传递给单独的Sentry项目,而不依赖于应用程序本身记录的任何内容。为实现这一目标,我们创建了一个新项目,并使用这两个项目配置了两个Client
个对象。的DSN。
问题:
事件被记录到正确的项目中,但是面包屑似乎对Client
个对象使用共享存储,因此它们包含来自两个项目的事件。
是否有一种简单的方法可以为两个Client
对象或其BreadcrumbStore
s定义单独的套件/域/文件夹?
我们尝试过:
我们正在研究子类化SentryFileManager
并将其传递给新的BreadcrumbStore
,但对于这样一个微不足道的任务来说似乎不必要地复杂化。
答案 0 :(得分:0)
1)子类SentryFileManager修改其路径
此问题似乎是SentryFileManager
中init(error:)
的硬编码路径属性:
NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
self.sentryPath = [cachePath stringByAppendingPathComponent:@"io.sentry"];
...
self.breadcrumbsPath = [self.sentryPath stringByAppendingPathComponent:@"breadcrumbs"];
...
self.eventsPath = [self.sentryPath stringByAppendingPathComponent:@"events"];
不幸的是,它们都是私有的,因此子类化SentryFileManager
仍然不会让我们访问它们。虽然我不推荐它,但我们最终使用键/值编码来设置它们以绕过编译器的访问控制。
如果目录不存在,请记住创建目录。
这个子类中没有任何东西可以继续存在。它只是使用提供的域名的唯一封装URL覆盖受保护的属性。
class DomainFileManager: SentryFileManager {
private enum Component {
static let sentry = "io.sentry"
static let breadcrumbs = "breadcrumbs"
static let events = "events"
}
private enum Key {
static let sentryPath = "sentryPath"
static let breadcrumbsPath = "breadcrumbsPath"
static let eventsPath = "eventsPath"
}
private static var cacheURL: URL {
return FileManager.default.urls(
for: .cachesDirectory,
in: .userDomainMask
)[0]
}
private let domainURL: URL
private var sentryURL: URL {
return domainURL.appendingPathComponent(Component.sentry)
}
private var breadcrumbsURL: URL {
return sentryURL.appendingPathComponent(Component.breadcrumbs)
}
private var eventsURL: URL {
return sentryURL.appendingPathComponent(Component.events)
}
init(domain: String, error: ()) throws {
domainURL = DomainFileManager.cacheURL.appendingPathComponent(domain)
try super.init(error: error)
setValue(sentryURL.path, forKey: Key.sentryPath)
setValue(breadcrumbsURL.path, forKey: Key.breadcrumbsPath)
setValue(eventsURL.path, forKey: Key.eventsPath)
for url in [sentryURL, breadcrumbsURL, eventsURL] {
if !FileManager.default.fileExists(atPath: url.path) {
try DomainFileManager.createDirectory(atPath: url.path)
}
}
}
}
正如您所看到的,子类化并不是绝对必要的,但其他对象实际上不应该开始弄乱SentryFileManager
的私有属性。也不应该是子类,但它们“真的不应该”少一点。
2)更新客户端痕迹导航商店
然后我们使用我们的子类为外部设备的Sentry客户端定义一个新的BreadcrumbStore
。
let fileManager = try DomainFileManager(domain: "domain", error: ())
client.breadcrumbs = BreadcrumbStore(fileManager: fileManager)
那么,那可能就是全部,不是吗?事实证明它不是。
3)更新客户端文件管理器
事实证明,客户端本身包含一个导致问题的私有文件管理器。突然,面包屑存储在封装的路径中,但事件使用默认的SentryFileManager
存储。
我们必须再次深入研究,并使用键/值编码来规避访问控制。
let fileManager = try DomainFileManager(domain: "domain", error: ())
client.breadcrumbs = BreadcrumbStore(fileManager: fileManager)
client.setValue(fileManager, forKey: "fileManager")
那就是所有人!
答案 1 :(得分:0)
Sentry 3.10 +支持记录到多个项目