[英]Logging to multiple Sentry projects from a single iOS application
What we do: We are building an app used to communicate with an external hardware device. 我们的工作:我们正在构建一个用于与外部硬件设备进行通信的应用程序。 The application can receive log messages from the external device. 该应用程序可以从外部设备接收日志消息。 The application already logs application events to a Sentry project. 该应用程序已经将应用程序事件记录到Sentry项目中。
What we want to do: We want the application to pass on the logs received from the external device to a separate Sentry project, independent of anything logged by the application itself. 我们想做什么:我们希望应用程序将从外部设备接收的日志传递到单独的Sentry项目,而与应用程序本身记录的所有内容无关。 To achieve this, we have created a new project, and configured two Client
objects using the two projects' DSNs. 为此,我们创建了一个新项目,并使用两个项目的DSN配置了两个Client
对象。
The issue: Events are logged to the correct project, but the breadcrumbs appears to use a shared storage for both the Client
objects, so they contain events from both projects. 问题:事件被记录到正确的项目中,但是面包屑似乎对两个Client
对象都使用了共享存储,因此它们包含两个项目中的事件。
Is there an easy way to define separate suites/domains/folders for the two Client
objects or their BreadcrumbStore
s? 是否有一种简单的方法来为两个Client
对象或它们的BreadcrumbStore
定义单独的套件/域/文件夹?
We have tried: We're looking into subclassing SentryFileManager
and passing it to a new BreadcrumbStore
, but it seems unnecessarily complicated for such a trivial task. 我们已经尝试过:我们正在研究对SentryFileManager
进行子类SentryFileManager
并将其传递给新的BreadcrumbStore
,但是对于这种琐碎的任务而言,它似乎不必要地复杂。
1) Subclass SentryFileManager to modify its paths 1)子类SentryFileManager修改其路径
The issue here appears to be SentryFileManager
's hard coded path properties in init(error:)
: 这里的问题似乎是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"];
Unfortunately, they are all private, so subclassing SentryFileManager
still won't give us access to them. 不幸的是,它们都是私有的,因此子类化SentryFileManager
仍然无法使我们访问它们。 Although I wouldn't recommended it, we ended up setting them using key/value coding to circumvent the compiler's access control. 尽管我不推荐这样做,但是我们最终还是使用键/值编码来设置它们,以规避编译器的访问控制。
Remember to create the directories if they don't exist. 如果目录不存在,请记住要创建它们。
There is nothing exiting going on in this subclass. 此子类中没有任何退出。 It simply overwrites the protected properties with unique, encapsulated URLs for the provided domain name. 它仅使用提供的域名的唯一封装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)
}
}
}
}
As you can see, subclassing isn't strictly necessary, but other objects really shouldn't start messing with the SentryFileManager
s private properties. 正如您所看到的,子类化不是严格必需的,但是其他对象确实不应该开始与SentryFileManager
的私有属性混淆。 Neither should subclasses, but they "really shouldn't" a bit less. 子类都不应该,但是它们“确实不应该”少一些。
2) Update the clients breadcrumb store 2)更新客户面包屑商店
Then we define a new BreadcrumbStore
for the external device's Sentry client using our subclass. 然后,使用子类为外部设备的Sentry客户端定义一个新的BreadcrumbStore
。
let fileManager = try DomainFileManager(domain: "domain", error: ())
client.breadcrumbs = BreadcrumbStore(fileManager: fileManager)
So, thats probably all, isn't it? 所以,大概就这些了,不是吗? Turns out it isn't. 事实并非如此。
3) Update the clients file manager 3)更新客户端文件管理器
It turns out that the client itself contains a private file manager that causes trouble. 事实证明,客户端本身包含一个引起麻烦的专用文件管理器。 Suddenly the breadcrumbs are stored at out encapsulated paths, but events are stored using the default SentryFileManager
. 面包屑突然存储在未封装的路径中,但事件使用默认的SentryFileManager
存储。
Once again we have to dive into the grit and circumvent the access control using key/value coding. 再一次,我们必须深入了解,使用键/值编码来规避访问控制。
let fileManager = try DomainFileManager(domain: "domain", error: ())
client.breadcrumbs = BreadcrumbStore(fileManager: fileManager)
client.setValue(fileManager, forKey: "fileManager")
And thats all folks! 那就是所有人!
Sentry 3.10 +支持记录到多个项目
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.