sentry-cocoa
sentry-cocoa copied to clipboard
MetricsKit integration
Description
Hi guys, I would to know if is possible to integrate MetricsKit reports in sentry performance monitoring. Is there a bridge?
Definitely something we're looking into. Not something we'll do in the next couple of months though, but sometime after that, this will become higher priority.
Is there something specific you have in mind? As we're in early stages, feedback can really help us drive the direction we take here
We have implemented MetricKit in our app. One disadvantage of MetricKit is that you can't add custom events or transactions easily, cause it gets a static string for transaction name in signPost, and there's not ability to add transactions with runtime name which is very important.
Beside that, MetricKit works on iOS 13+ and its diagnostics metrics are only on iOS 14+.
Thanks for the input, @ialimz. Those are the primary reasons why we didn't get started with it yet.
The docs of MetricKit state
The system delivers metric reports about the previous 24 hours to a registered app at most once per day, and delivers diagnostic reports immediately in iOS 15 and later and macOS 12 and later.
We could look into how to merge the diagnostic reports that get delivered immediately somehow with transactions.
This is roughly how you can subscribe to the data of MetricKit.
Swift
class AppMetrics: NSObject, MXMetricManagerSubscriber {
func receiveReports() {
let shared = MXMetricManager.shared
shared.add(self)
}
func pauseReports() {
let shared = MXMetricManager.shared
shared.remove(self)
}
// Receive daily metrics.
func didReceive(_ payloads: [MXMetricPayload]) {
// Process metrics.
let enumerator = payloads.first?.applicationLaunchMetrics?.histogrammedTimeToFirstDraw.bucketEnumerator
while let object = enumerator?.nextObject() {
let bucket = object as! MXHistogramBucket<UnitDuration>
// ...
}
}
// Receive diagnostics immediately when available.
func didReceive(_ payloads: [MXDiagnosticPayload]) {
}
}
Objective-C
#import <MetricKit/MetricKit.h>
// ...
API_AVAILABLE(ios(16.0))
@interface SentryAppMetrics : NSObject<MXMetricManagerSubscriber>
@end
API_AVAILABLE(ios(16.0))
@implementation SentryAppMetrics
- (void)didReceiveDiagnosticPayloads:(NSArray<MXDiagnosticPayload *> *)payloads {
for (MXDiagnosticPayload *payload in payloads) {
for (MXAppLaunchDiagnostic * launchDiagnostic in payload.appLaunchDiagnostics) {
NSString *message = [NSString stringWithFormat:@"Launch duration: %f", launchDiagnostic.launchDuration.doubleValue];
[SentrySDK captureMessage:message];
}
}
}
// ...
if (@available(iOS 16.0, *)) {
self.appMetrics = [[SentryAppMetrics alloc] init];
}
@end
Debugging
Plugin a real device and click Simulate MetricKit Payloads in Xcode.

MXMetricPayload
Daily
- cellularConditionMetrics: MXCellularConditionMetric
- cpuMetrics: MXCPUMetric
- applicationLaunchMetrics: MXAppLaunchMetric
- applicationResponsivenessMetrics: MXAppResponsivenessMetric
- ...
MXDiagnosticPayload
Daily
Can we convert stack traces coming from MetricKit into Sentry events?
Can we convert stack traces coming from MetricKit into Sentry events?
I'd love it if this is possible.
I wrote up a state of the union of what MetricKit provides and what gaps/holes we currently do not track. Please let me know how we could best proceed 👍
Thanks a lot, @filip-doordash, for sharing your document.
I took a look at the MXCrashDiagnostic. The MXCallStackTree has one field JSONRepresentation, which contains the information on the stack trace. We would need to parse this JSON and somehow convert it into a SentryEvent. It seems like this should be possible, but I'm not 100% sure yet if we get all the data to symbolicate the stacktrace in Sentry. So I'm pretty sure it's possible, but I'm not sure about the effort.
A significant downside with MetricKit is its delay of 24 to 48 hours. That's why we didn't adopt it yet because that delay could destroy your business if the roof is on fire. Furthermore, we cannot attach as much context as we can when creating the events in real time. One idea just popped into my head: why not send both? We could add an integration for MetricKit disabled by default, so you get all issues with less context and keep all the other features of the SentrySDK. Does that make sense, or do you wish to replace Sentry crash reporting with MetricKit MXCrashDiagnostic, @filip-doordash?
Useful resources:
- https://www.chimehq.com/blog/metrickit-crash-reporting
- https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report
- https://github.com/ChimeHQ/Meter
I don't think I'd want to utilize MetricKit for MXCrashDiagnostic. I think our primary targets are:
but your strategy remains the same! we need to symbolicate the stack traces regardless
Thanks for clarifying that, @filip-doordash. Yes, the items you mentioned totally make sense, and the 24 to 48 hour delay won't be a huge deal for these.
I mainly see this as augmenting what's already available; eg. supplying breadcrumbs for CPU exceptions/disk errors/hang/app exit/cellular condition events, adding battery/CPU/GPU/memory/IO gauges, improving Sentry performance metrics with app launch times/FPS/animation performance.
@philipphofmann, eventually, I think a mix between MXCrashDiagnostic & Sentry's crash reporting service could be helpful. Primarily for OOM crashes, as you mentioned in Jan 2021, but other exceptions too.
I mean, if Sentry deduplicates crashes anyways, what's the harm? :)
For example, in the case of a memory leak, Sentry could report high-level details by saying, "hey, we're running out of memory on X app version", while MetricKit takes ~24-48h to gather the details of exactly why. It could be a great combo!
Nonetheless, hang rates, CPU exceptions, and disk write exceptions should all be unique call stacks that we could look at first. Let me know if I can help!
Thanks for the update, @filip-doordash. I hope I have the bandwidth to look closely at this in one or two weeks.
Symbolication Investigation
Our symbolication minimum needs frame.instruction_addr, and debug_image.debug_id , and depending on the addr_mode also debugImage.image_addr.
The MetricKit payload provides a stacktrace for MXDiagnostics in the form of a MXCallStackTree.
{
"callStackTree" : {
"callStackPerThread" : true,
"callStacks" : [
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "70B89F27-1634-3580-A695-57CDB41D7743",
"offsetIntoBinaryTextSegment" : 165304,
"sampleCount" : 1,
"binaryName" : "MetricKitTestApp",
"address" : 7170766264
"subFrames" : [
{
"binaryUUID" : "77A62F2E-8212-30F3-84C1-E8497440ACF8",
"offsetIntoBinaryTextSegment" : 6948,
"sampleCount" : 1,
"binaryName" : "libdyld.dylib",
"address" : 7170808612
}
]
}
]
},
{
"threadAttributed" : true,
"callStackRootFrames" : [
...
binaryName and binaryUUID should map to our code_file and debug_id. I assume the address is absolute for the frame. Though offsetIntoBinaryTextSegment is an odd name. We want the load addr of the binary, because the text segment could, in theory, be at an arbitrary offset. So address should map to our frame.instruction_addr, and debugImage.image_addr should be address - offsetIntoBinaryTextSegment. We still need to validate that.
My current problem is that receiving a MXDiagnosticPayload via Xcode debug Simulate MeticKit Payload didn't work for me. Xcode only sends MXMetricPayloads for me.
We could also look into the on device symbolication of Meter if we don't make it work with the approach above.
Thanks, @Swatinem, for the help with this investigation.
Context
Adding the proper context to the events the Cocoa SDK will generate will be a challenge, as the events will be from the past, and the current context could be outdated. The MXMetaData provides some context, but we might need some type of local cache for context data that changes.
As receiving an MXDiagnosticPayload via Xcode debug Simulate MeticKit Payload didn't work, I opened a PR to collect MetricKit payloads with our iOS-Swift sample app with https://github.com/getsentry/sentry-cocoa/pull/2316.
Important note
Apple can’t provide reports if users don’t share the data and statistics with app developers. If a user reports a crash and you don’t have a corresponding crash report, ask the user to share the crash data with app developers. Crash and energy data are automatically sent if you distribute an app using TestFlight but not if you distribute an app through the App Store. Metrics data is only shared for apps distributed through the App Store.
https://help.apple.com/xcode/mac/current/#/deve2819c518
With https://github.com/getsentry/sentry-cocoa/pull/2316 we started to collect payloads from MetricKit via TestFlight. So far we have only received crash data. So the statement below seems to be true.
Crash and energy data are automatically sent if you distribute an app using TestFlight but not if you distribute an app through the App Store. Metrics data is only shared for apps distributed through the App Store.
MXDiagnosticPayload
{
"timeStampEnd" : "2022-10-24 08:16:00",
"timeStampBegin" : "2022-10-24 08:16:00",
"crashDiagnostics" : [
{
"version" : "1.0.0",
"callStackTree" : {
"callStacks" : [
{
"threadAttributed" : true,
"callStackRootFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 356604,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "68AB9876-503C-3D49-8FA2-E9684BB9EF4D",
"offsetIntoBinaryTextSegment" : 46940,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 2422520,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 256936,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 2421720,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 2420076,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 2419728,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 2418760,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 1036904,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 1033860,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 1030468,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 1028096,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 1322340,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 14195248,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 6624888,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 13175044,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 13171408,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 877100,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 927252,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 419100,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 507576,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 528868,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "03732BA5-1132-35B4-B09D-8DD49807D246",
"offsetIntoBinaryTextSegment" : 4968,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 3812744,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 3811820,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "68AB9876-503C-3D49-8FA2-E9684BB9EF4D",
"offsetIntoBinaryTextSegment" : 35508,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7AA46EB1-80B2-342B-9E99-BE07DBD5696C",
"offsetIntoBinaryTextSegment" : 88392,
"sampleCount" : 1,
"binaryName" : "dyld",
"address" : 8243059016
}
],
"binaryName" : "iOS-Swift",
"address" : 4343155380
}
],
"binaryName" : "UIKitCore",
"address" : 7774915052
}
],
"binaryName" : "UIKitCore",
"address" : 7774915976
}
],
"binaryName" : "GraphicsServices",
"address" : 8690783080
}
],
"binaryName" : "CoreFoundation",
"address" : 7736447460
}
],
"binaryName" : "CoreFoundation",
"address" : 7736426168
}
],
"binaryName" : "CoreFoundation",
"address" : 7736337692
}
],
"binaryName" : "CoreFoundation",
"address" : 7736845844
}
],
"binaryName" : "CoreFoundation",
"address" : 7736795692
}
],
"binaryName" : "UIKitCore",
"address" : 7784274640
}
],
"binaryName" : "UIKitCore",
"address" : 7784278276
}
],
"binaryName" : "UIKitCore",
"address" : 7777728120
}
],
"binaryName" : "UIKitCore",
"address" : 7785298480
}
],
"binaryName" : "UIKitCore",
"address" : 7772425572
}
],
"binaryName" : "UIKitCore",
"address" : 7772131328
}
],
"binaryName" : "UIKitCore",
"address" : 7772133700
}
],
"binaryName" : "UIKitCore",
"address" : 7772137092
}
],
"binaryName" : "UIKitCore",
"address" : 7772140136
}
],
"binaryName" : "UIKitCore",
"address" : 7773521992
}
],
"binaryName" : "UIKitCore",
"address" : 7773522960
}
],
"binaryName" : "UIKitCore",
"address" : 7773523308
}
],
"binaryName" : "UIKitCore",
"address" : 7773524952
}
],
"binaryName" : "Sentry",
"address" : 4344949672
}
],
"binaryName" : "UIKitCore",
"address" : 7773525752
}
],
"binaryName" : "iOS-Swift",
"address" : 4343166812
}
],
"binaryName" : "Sentry",
"address" : 4345049340
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2960,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020590992
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2960,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020590992
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2960,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020590992
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2960,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020590992
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2960,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020590992
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 2888,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 77832,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 78408,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 4236,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 503296,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 507972,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 528868,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "AA92CD58-561A-3414-92F4-B4120298B39A",
"offsetIntoBinaryTextSegment" : 268312,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "AA92CD58-561A-3414-92F4-B4120298B39A",
"offsetIntoBinaryTextSegment" : 268032,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 5077132,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "AA92CD58-561A-3414-92F4-B4120298B39A",
"offsetIntoBinaryTextSegment" : 371944,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5836,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593868
}
],
"binaryName" : "Foundation",
"address" : 7640116456
}
],
"binaryName" : "UIKitCore",
"address" : 7776180364
}
],
"binaryName" : "Foundation",
"address" : 7640012544
}
],
"binaryName" : "Foundation",
"address" : 7640012824
}
],
"binaryName" : "CoreFoundation",
"address" : 7736447460
}
],
"binaryName" : "CoreFoundation",
"address" : 7736426564
}
],
"binaryName" : "CoreFoundation",
"address" : 7736421888
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749809804
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883976
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883400
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749808456
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 4104,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "82C0F938-E277-3165-A614-70151C651798",
"offsetIntoBinaryTextSegment" : 22560,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "82C0F938-E277-3165-A614-70151C651798",
"offsetIntoBinaryTextSegment" : 105244,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 288440,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5836,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593868
}
],
"binaryName" : "Sentry",
"address" : 4344981176
}
],
"binaryName" : "libsystem_c.dylib",
"address" : 7858481948
}
],
"binaryName" : "libsystem_c.dylib",
"address" : 7858399264
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749809672
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 2888,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 77832,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 78408,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 4236,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 208772,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5836,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593868
}
],
"binaryName" : "Sentry",
"address" : 4344901508
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749809804
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883976
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883400
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749808456
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D98C7F75-298C-3D09-81BE-A7A32189FC4F",
"offsetIntoBinaryTextSegment" : 220248,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D4C8ECC5-27DD-3C4A-9529-1E43D1B43F4B",
"offsetIntoBinaryTextSegment" : 13016,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 4652488,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "23A203ED-E917-3A52-9A18-78776489BEBB",
"offsetIntoBinaryTextSegment" : 284444,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "23A203ED-E917-3A52-9A18-78776489BEBB",
"offsetIntoBinaryTextSegment" : 401824,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "23A203ED-E917-3A52-9A18-78776489BEBB",
"offsetIntoBinaryTextSegment" : 19940,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 520660,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "23A203ED-E917-3A52-9A18-78776489BEBB",
"offsetIntoBinaryTextSegment" : 31024,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 519456,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "7B942FA4-CB76-3375-9972-F58C14492FB4",
"offsetIntoBinaryTextSegment" : 4335044,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "B3A78098-C0FB-3DCD-B1AC-0712762510DB",
"offsetIntoBinaryTextSegment" : 5592,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "B3A78098-C0FB-3DCD-B1AC-0712762510DB",
"offsetIntoBinaryTextSegment" : 20288,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "B3A78098-C0FB-3DCD-B1AC-0712762510DB",
"offsetIntoBinaryTextSegment" : 207324,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 7128,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 18036,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5848,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593880
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020606068
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020595160
}
],
"binaryName" : "libobjc.A.dylib",
"address" : 7622584796
}
],
"binaryName" : "libobjc.A.dylib",
"address" : 7622397760
}
],
"binaryName" : "libobjc.A.dylib",
"address" : 7622383064
}
],
"binaryName" : "UIKitCore",
"address" : 7775438276
}
],
"binaryName" : "CoreFoundation",
"address" : 7736438048
}
],
"binaryName" : "CoreGraphics",
"address" : 7764789552
}
],
"binaryName" : "CoreFoundation",
"address" : 7736439252
}
],
"binaryName" : "CoreGraphics",
"address" : 7764778468
}
],
"binaryName" : "CoreGraphics",
"address" : 7765160352
}
],
"binaryName" : "CoreGraphics",
"address" : 7765042972
}
],
"binaryName" : "UIKitCore",
"address" : 7775755720
}
],
"binaryName" : "IOSurface",
"address" : 8231461592
}
],
"binaryName" : "IOKit",
"address" : 7868210264
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 4104,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "82C0F938-E277-3165-A614-70151C651798",
"offsetIntoBinaryTextSegment" : 22560,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "AA92CD58-561A-3414-92F4-B4120298B39A",
"offsetIntoBinaryTextSegment" : 728416,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 119364,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "AA92CD58-561A-3414-92F4-B4120298B39A",
"offsetIntoBinaryTextSegment" : 371944,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5836,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593868
}
],
"binaryName" : "Foundation",
"address" : 7640116456
}
],
"binaryName" : "Sentry",
"address" : 4344812100
}
],
"binaryName" : "Foundation",
"address" : 7640472928
}
],
"binaryName" : "libsystem_c.dylib",
"address" : 7858399264
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749809672
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 2888,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 77832,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 78408,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 4236,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 503296,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 507972,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "42C5C917-0447-3995-B50F-DE4D132C2435",
"offsetIntoBinaryTextSegment" : 528868,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "35605DE3-3723-335A-83D9-6F35F2989935",
"offsetIntoBinaryTextSegment" : 2444204,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "AA92CD58-561A-3414-92F4-B4120298B39A",
"offsetIntoBinaryTextSegment" : 371944,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5836,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593868
}
],
"binaryName" : "Foundation",
"address" : 7640116456
}
],
"binaryName" : "CFNetwork",
"address" : 7756692396
}
],
"binaryName" : "CoreFoundation",
"address" : 7736447460
}
],
"binaryName" : "CoreFoundation",
"address" : 7736426564
}
],
"binaryName" : "CoreFoundation",
"address" : 7736421888
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749809804
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883976
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883400
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749808456
}
]
},
{
"threadAttributed" : false,
"callStackRootFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 2888,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 77832,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "D3EB8B56-7C22-3265-A985-A436BC8CAF15",
"offsetIntoBinaryTextSegment" : 53664,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 390608,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 300040,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 84896,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "BF11D1BA-4690-38C9-9E08-946A3768A67B",
"offsetIntoBinaryTextSegment" : 86448,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 5836,
"sampleCount" : 1,
"subFrames" : [
{
"binaryUUID" : "E0674D94-1A29-36B9-A1F9-CA129F0CFC7E",
"offsetIntoBinaryTextSegment" : 2980,
"sampleCount" : 1,
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020591012
}
],
"binaryName" : "libsystem_pthread.dylib",
"address" : 9020593868
}
],
"binaryName" : "Sentry",
"address" : 4344779184
}
],
"binaryName" : "Sentry",
"address" : 4344777632
}
],
"binaryName" : "Sentry",
"address" : 4344992776
}
],
"binaryName" : "Sentry",
"address" : 4345083344
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749859232
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749883400
}
],
"binaryName" : "libsystem_kernel.dylib",
"address" : 8749808456
}
]
}
],
"callStackPerThread" : true
},
"diagnosticMetaData" : {
"appBuildVersion" : "876",
"appVersion" : "7.28.0",
"regionFormat" : "AT",
"exceptionType" : 6,
"osVersion" : "iPhone OS 16.0.3 (20A392)",
"deviceType" : "iPhone13,2",
"bundleIdentifier" : "io.sentry.sample.iOS-Swift",
"exceptionCode" : 1,
"signal" : 5,
"platformArchitecture" : "arm64e"
}
}
]
}
MXMetricPayload
{
"locationActivityMetrics" : {
"cumulativeBestAccuracyForNavigationTime" : "20 sec",
"cumulativeBestAccuracyTime" : "30 sec",
"cumulativeHundredMetersAccuracyTime" : "30 sec",
"cumulativeNearestTenMetersAccuracyTime" : "30 sec",
"cumulativeKilometerAccuracyTime" : "20 sec",
"cumulativeThreeKilometersAccuracyTime" : "20 sec"
},
"cellularConditionMetrics" : {
"cellConditionTime" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 20,
"bucketStart" : "1 bars",
"bucketEnd" : "1 bars"
},
"1" : {
"bucketCount" : 30,
"bucketStart" : "2 bars",
"bucketEnd" : "2 bars"
},
"2" : {
"bucketCount" : 50,
"bucketStart" : "3 bars",
"bucketEnd" : "3 bars"
}
}
}
},
"metaData" : {
"appBuildVersion" : "1",
"osVersion" : "iPhone OS 16.0.3 (20A392)",
"regionFormat" : "AT",
"platformArchitecture" : "arm64e",
"bundleIdentifier" : "io.sentry.sample.iOS-Swift",
"deviceType" : "iPhone13,2"
},
"gpuMetrics" : {
"cumulativeGPUTime" : "20 sec"
},
"memoryMetrics" : {
"peakMemoryUsage" : "200000 kB",
"averageSuspendedMemory" : {
"averageValue" : "100000 kB",
"standardDeviation" : 0,
"sampleCount" : 500
}
},
"applicationExitMetrics" : {
"backgroundExitData" : {
"cumulativeAppWatchdogExitCount" : 1,
"cumulativeMemoryResourceLimitExitCount" : 1,
"cumulativeBackgroundURLSessionCompletionTimeoutExitCount" : 1,
"cumulativeBackgroundFetchCompletionTimeoutExitCount" : 1,
"cumulativeAbnormalExitCount" : 1,
"cumulativeSuspendedWithLockedFileExitCount" : 1,
"cumulativeIllegalInstructionExitCount" : 1,
"cumulativeMemoryPressureExitCount" : 1,
"cumulativeBadAccessExitCount" : 1,
"cumulativeCPUResourceLimitExitCount" : 1,
"cumulativeBackgroundTaskAssertionTimeoutExitCount" : 1,
"cumulativeNormalAppExitCount" : 1
},
"foregroundExitData" : {
"cumulativeBadAccessExitCount" : 1,
"cumulativeAbnormalExitCount" : 1,
"cumulativeMemoryResourceLimitExitCount" : 1,
"cumulativeNormalAppExitCount" : 1,
"cumulativeCPUResourceLimitExitCount" : 1,
"cumulativeIllegalInstructionExitCount" : 1,
"cumulativeAppWatchdogExitCount" : 1
}
},
"displayMetrics" : {
"averagePixelLuminance" : {
"averageValue" : "50 apl",
"standardDeviation" : 0,
"sampleCount" : 500
}
},
"signpostMetrics" : [
{
"signpostIntervalData" : {
"histogrammedSignpostDurations" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 50,
"bucketStart" : "0 ms",
"bucketEnd" : "100 ms"
},
"1" : {
"bucketCount" : 60,
"bucketStart" : "100 ms",
"bucketEnd" : "400 ms"
},
"2" : {
"bucketCount" : 30,
"bucketStart" : "400 ms",
"bucketEnd" : "700 ms"
}
}
},
"signpostCumulativeHitchTimeRatio" : "50 ms per s",
"signpostCumulativeCPUTime" : "30000 ms",
"signpostAverageMemory" : "100000 kB",
"signpostCumulativeLogicalWrites" : "600 kB"
},
"signpostCategory" : "TestSignpostCategory1",
"signpostName" : "TestSignpostName1",
"totalSignpostCount" : 30
},
{
"signpostIntervalData" : {
"histogrammedSignpostDurations" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 60,
"bucketStart" : "0 ms",
"bucketEnd" : "200 ms"
},
"1" : {
"bucketCount" : 70,
"bucketStart" : "201 ms",
"bucketEnd" : "300 ms"
},
"2" : {
"bucketCount" : 80,
"bucketStart" : "301 ms",
"bucketEnd" : "500 ms"
}
}
},
"signpostCumulativeCPUTime" : "50000 ms",
"signpostAverageMemory" : "60000 kB",
"signpostCumulativeLogicalWrites" : "700 kB"
},
"signpostCategory" : "TestSignpostCategory2",
"signpostName" : "TestSignpostName2",
"totalSignpostCount" : 40
}
],
"cpuMetrics" : {
"cumulativeCPUTime" : "100 sec",
"cumulativeCPUInstructions" : "100 kiloinstructions"
},
"networkTransferMetrics" : {
"cumulativeCellularDownload" : "80000 kB",
"cumulativeWifiDownload" : "60000 kB",
"cumulativeCellularUpload" : "70000 kB",
"cumulativeWifiUpload" : "50000 kB"
},
"diskIOMetrics" : {
"cumulativeLogicalWrites" : "1300 kB"
},
"applicationLaunchMetrics" : {
"histogrammedTimeToFirstDrawKey" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 50,
"bucketStart" : "1000 ms",
"bucketEnd" : "1010 ms"
},
"1" : {
"bucketCount" : 60,
"bucketStart" : "2000 ms",
"bucketEnd" : "2010 ms"
},
"2" : {
"bucketCount" : 30,
"bucketStart" : "3000 ms",
"bucketEnd" : "3010 ms"
}
}
},
"histogrammedResumeTime" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 60,
"bucketStart" : "200 ms",
"bucketEnd" : "210 ms"
},
"1" : {
"bucketCount" : 70,
"bucketStart" : "300 ms",
"bucketEnd" : "310 ms"
},
"2" : {
"bucketCount" : 80,
"bucketStart" : "500 ms",
"bucketEnd" : "510 ms"
}
}
},
"histogrammedExtendedLaunch" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 50,
"bucketStart" : "1000 ms",
"bucketEnd" : "1010 ms"
},
"1" : {
"bucketCount" : 60,
"bucketStart" : "2000 ms",
"bucketEnd" : "2010 ms"
},
"2" : {
"bucketCount" : 30,
"bucketStart" : "3000 ms",
"bucketEnd" : "3010 ms"
}
}
},
"histogrammedOptimizedTimeToFirstDrawKey" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 50,
"bucketStart" : "1000 ms",
"bucketEnd" : "1010 ms"
},
"1" : {
"bucketCount" : 60,
"bucketStart" : "2000 ms",
"bucketEnd" : "2010 ms"
},
"2" : {
"bucketCount" : 30,
"bucketStart" : "3000 ms",
"bucketEnd" : "3010 ms"
}
}
}
},
"applicationTimeMetrics" : {
"cumulativeForegroundTime" : "700 sec",
"cumulativeBackgroundTime" : "40 sec",
"cumulativeBackgroundAudioTime" : "30 sec",
"cumulativeBackgroundLocationTime" : "30 sec"
},
"timeStampEnd" : "2022-10-20 23:59:00",
"animationMetrics" : {
"scrollHitchTimeRatio" : "1000 ms per s"
},
"applicationResponsivenessMetrics" : {
"histogrammedAppHangTime" : {
"histogramNumBuckets" : 3,
"histogramValue" : {
"0" : {
"bucketCount" : 50,
"bucketStart" : "0 ms",
"bucketEnd" : "100 ms"
},
"1" : {
"bucketCount" : 60,
"bucketStart" : "100 ms",
"bucketEnd" : "400 ms"
},
"2" : {
"bucketCount" : 30,
"bucketStart" : "400 ms",
"bucketEnd" : "700 ms"
}
}
}
},
"appVersion" : "7.28.0",
"timeStampBegin" : "2022-10-20 00:00:00"
}
Adding the SentryContext and scope to these payloads is going to be a challenge, indeed. The timeStampBegin and timeStampEnd, seem to be the only way to map our context to that payload. The only idea to make this work for me right now is to keep a versioned cache of the context. We would need to store all changes in the context of the disk. Or we go ahead with only attaching app, and device context, etc. , which doesn't frequently change in the first iteration. Breadcrumbs and attachments won't work for MetricKit events, but we could make it work for user, tags, environment and dist.
Let me know if I could help with anything!
@filip-doordash, do you maybe have some sample payloads without any details about Doordash you can share? I'm primarily interested in the meta data that it contains.
Sure! I copied your code from #2316 and included it in our next release. I should get data in the next couple of weeks (releases take a while!).
I'll post a redacted version of the data when it arrives.
Thank you very much, @filip-doordash 🥳 .
@philipphofmann I've attached 20 MXDiagnosticPayload samples. Let me know if that is sufficient or if you need more samples.
Thank you @filip-doordash 😀🙏. The 20 samples are sufficient for now.