Skip to content

Commit 723845a

Browse files
committed
feat(metrics): Add integration with installation by SDK
1 parent 03afb63 commit 723845a

File tree

12 files changed

+202
-1
lines changed

12 files changed

+202
-1
lines changed

Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public enum SentrySDKOverrides: String, CaseIterable {
4747
case .tracing: return SentrySDKOverrides.Tracing.allCases
4848
case .profiling: return SentrySDKOverrides.Profiling.allCases
4949
case .networking: return SentrySDKOverrides.Networking.allCases
50+
case .metrics: return SentrySDKOverrides.Metrics.allCases
5051
}
5152
}
5253

@@ -167,6 +168,11 @@ public enum SentrySDKOverrides: String, CaseIterable {
167168
case immediateStop = "--io.sentry.profiling.continuous-profiler-immediate-stop"
168169
}
169170
case profiling = "Profiling"
171+
172+
public enum Metrics: String, SentrySDKOverride {
173+
case enable = "--io.sentry.metrics.enable"
174+
}
175+
case metrics = "Metrics"
170176
}
171177

172178
// MARK: Public flag/variable value access
@@ -348,6 +354,14 @@ extension SentrySDKOverrides.Special {
348354
}
349355
}
350356

357+
extension SentrySDKOverrides.Metrics {
358+
public var overrideType: OverrideType {
359+
switch self {
360+
case .enable: return .boolean
361+
}
362+
}
363+
}
364+
351365
// MARK: Disable Everything Helper
352366

353367
// These are listed exhaustively, without using default cases, so that when new cases are added to the enums above, the compiler helps remind you to annotate what type it is down here.
@@ -429,4 +443,11 @@ extension SentrySDKOverrides.Special {
429443
}
430444
}
431445

446+
extension SentrySDKOverrides.Metrics {
447+
public var ignoresDisableEverything: Bool {
448+
switch self {
449+
case .enable: return false
450+
}
451+
}
452+
}
432453
// swiftlint:enable file_length

Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,12 @@ public struct SentrySDKWrapper {
156156
options.configureUserFeedback = configureFeedback(config:)
157157
#endif // !os(macOS) && !os(tvOS) && !os(watchOS) && !os(visionOS)
158158

159+
// Integration: Logs
159160
options.enableLogs = true
160161

162+
// Integration: Metrics
163+
options.enableMetrics = SentrySDKOverrides.Metrics.enable.boolValue
164+
161165
// Experimental features
162166
options.enableFileManagerSwizzling = !SentrySDKOverrides.Other.disableFileManagerSwizzling.boolValue
163167
options.experimental.enableUnhandledCPPExceptionsV2 = true

Samples/Shared/feature-flags.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ schemeTemplates:
8282
"--io.sentry.other.reject-view-hierarchy-in-before-capture-view-hierarchy": false
8383
"--io.sentry.other.reject-all-spans": false
8484

85+
# metrics
86+
"--io.sentry.metrics.enable": false
87+
8588
environmentVariables:
8689
# events
8790
- variable: "--io.sentry.events.sampleRate"

Sentry.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,8 @@
782782
D46712622DCD059900D4074A /* SentryRedactDefaultOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46712612DCD059500D4074A /* SentryRedactDefaultOptionsTests.swift */; };
783783
D46712642DCD063800D4074A /* PreviewRedactOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46712632DCD062700D4074A /* PreviewRedactOptionsTests.swift */; };
784784
D468C0622D3669A200964230 /* SentryFileIOTracker+SwiftHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D468C0612D3669A200964230 /* SentryFileIOTracker+SwiftHelpers.swift */; };
785+
D46B041D2EDF168400AF4A0A /* MetricsIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46B041C2EDF167D00AF4A0A /* MetricsIntegration.swift */; };
786+
D46B04202EDF175C00AF4A0A /* MetricsIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46B041F2EDF175600AF4A0A /* MetricsIntegrationTests.swift */; };
785787
D473ACD72D8090FC000F1CC6 /* FileManager+SentryTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D473ACD62D8090FC000F1CC6 /* FileManager+SentryTracing.swift */; };
786788
D480F9D92DE47A50009A0594 /* TestSentryScopePersistentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D480F9D82DE47A48009A0594 /* TestSentryScopePersistentStore.swift */; };
787789
D480F9DB2DE47AF2009A0594 /* SentryScopePersistentStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D480F9DA2DE47AEB009A0594 /* SentryScopePersistentStoreTests.swift */; };
@@ -2143,6 +2145,8 @@
21432145
D46712612DCD059500D4074A /* SentryRedactDefaultOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRedactDefaultOptionsTests.swift; sourceTree = "<group>"; };
21442146
D46712632DCD062700D4074A /* PreviewRedactOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewRedactOptionsTests.swift; sourceTree = "<group>"; };
21452147
D468C0612D3669A200964230 /* SentryFileIOTracker+SwiftHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SentryFileIOTracker+SwiftHelpers.swift"; sourceTree = "<group>"; };
2148+
D46B041C2EDF167D00AF4A0A /* MetricsIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetricsIntegration.swift; sourceTree = "<group>"; };
2149+
D46B041F2EDF175600AF4A0A /* MetricsIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetricsIntegrationTests.swift; sourceTree = "<group>"; };
21462150
D46D45E12D5F3FD600A1CB35 /* Sentry_Base.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sentry_Base.xctestplan; sourceTree = "<group>"; };
21472151
D46D45E92D5F411700A1CB35 /* SentrySwiftUI_Base.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = SentrySwiftUI_Base.xctestplan; path = Plans/SentrySwiftUI_Base.xctestplan; sourceTree = SOURCE_ROOT; };
21482152
D473ACD62D8090FC000F1CC6 /* FileManager+SentryTracing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+SentryTracing.swift"; sourceTree = "<group>"; };
@@ -3510,6 +3514,7 @@
35103514
children = (
35113515
843FB3422D156B9900558F18 /* Feedback */,
35123516
7BF6505D292B77D100BBA5A8 /* MetricKit */,
3517+
D46B041E2EDF173A00AF4A0A /* Metrics */,
35133518
D808FB85281AB2EF009A2A33 /* UIEvents */,
35143519
D8AB40D92806EBDC00E5E9F7 /* Screenshot */,
35153520
0A9BF4E528A123070068D266 /* ViewHierarchy */,
@@ -4361,6 +4366,22 @@
43614366
path = IO;
43624367
sourceTree = "<group>";
43634368
};
4369+
D46B04162EDF167800AF4A0A /* Metrics */ = {
4370+
isa = PBXGroup;
4371+
children = (
4372+
D46B041C2EDF167D00AF4A0A /* MetricsIntegration.swift */,
4373+
);
4374+
path = Metrics;
4375+
sourceTree = "<group>";
4376+
};
4377+
D46B041E2EDF173A00AF4A0A /* Metrics */ = {
4378+
isa = PBXGroup;
4379+
children = (
4380+
D46B041F2EDF175600AF4A0A /* MetricsIntegrationTests.swift */,
4381+
);
4382+
path = Metrics;
4383+
sourceTree = "<group>";
4384+
};
43644385
D46D45E22D5F3FD600A1CB35 /* Plans */ = {
43654386
isa = PBXGroup;
43664387
children = (
@@ -4828,6 +4849,7 @@
48284849
D8CAC02D2BA0663E00E38F34 /* Integrations */ = {
48294850
isa = PBXGroup;
48304851
children = (
4852+
D46B04162EDF167800AF4A0A /* Metrics */,
48314853
FAB0073C2E9F47DE001C806A /* Session */,
48324854
FAE579B42E7DBE9400B710F9 /* SentryGlobalEventProcessor.swift */,
48334855
FAD882C12EDAADF90055AA44 /* SwiftAsyncIntegration.swift */,
@@ -6139,6 +6161,7 @@
61396161
62E59A5A2E8FB85300DB7A7B /* SentryTracePropagation.m in Sources */,
61406162
FAB007522E9FE2FF001C806A /* SentrySwizzleWrapper.swift in Sources */,
61416163
62E300942D5202890037AA3F /* SentryExceptionCodable.swift in Sources */,
6164+
D46B041D2EDF168400AF4A0A /* MetricsIntegration.swift in Sources */,
61426165
0A2D8D5B289815C0008720F6 /* SentryBaseIntegration.m in Sources */,
61436166
639FCF991EBC7B9700778193 /* SentryEvent.m in Sources */,
61446167
D820CDB72BB1895F00BA339D /* SentrySessionReplayIntegration.m in Sources */,
@@ -6225,6 +6248,7 @@
62256248
7BFAA6E7297AA16A00E7E02E /* SentryCrashMonitor_CppException_Tests.mm in Sources */,
62266249
9286059929A50BAB00F96038 /* SentryGeoTests.swift in Sources */,
62276250
621655662DB12A8900810504 /* SentryCrashMach-OTests.m in Sources */,
6251+
D46B04202EDF175C00AF4A0A /* MetricsIntegrationTests.swift in Sources */,
62286252
62B220BB2E93A9EC004620FF /* SentryTracePropagationTests.swift in Sources */,
62296253
D8B76B0828081461000A58C4 /* TestSentryScreenshotProvider.swift in Sources */,
62306254
A8AFFCD22907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift in Sources */,

Sources/Sentry/SentryOptionsInternal.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ + (BOOL)validateOptions:(NSDictionary<NSString *, id> *)options
9696

9797
[self setBool:options[@"enableLogs"] block:^(BOOL value) { sentryOptions.enableLogs = value; }];
9898

99+
[self setBool:options[@"enableMetrics"]
100+
block:^(BOOL value) { sentryOptions.enableMetrics = value; }];
101+
99102
[self setBool:options[@"enableNetworkBreadcrumbs"]
100103
block:^(BOOL value) { sentryOptions.enableNetworkBreadcrumbs = value; }];
101104

Sources/Swift/Core/Integrations/Integrations.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ private struct AnyIntegration {
3434
@_spi(Private) @objc public final class SentrySwiftIntegrationInstaller: NSObject {
3535
@objc public class func install(with options: Options) {
3636
let dependencies = SentryDependencyContainer.sharedInstance()
37-
let commonIntegrations: [AnyIntegration] = [.init(SwiftAsyncIntegration.self)]
37+
let commonIntegrations: [AnyIntegration] = [
38+
.init(MetricsIntegration.self),
39+
.init(SwiftAsyncIntegration.self)
40+
]
3841
#if os(iOS) && !SENTRY_NO_UIKIT
3942
let integrations: [AnyIntegration] = commonIntegrations + [.init(UserFeedbackIntegration<SentryDependencyContainer>.self)]
4043
#else

Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ import Foundation
4545
if options.experimental.enableUnhandledCPPExceptionsV2 {
4646
features.append("unhandledCPPExceptionsV2")
4747
}
48+
if options.enableMetrics {
49+
features.append("metrics")
50+
}
4851

4952
return features
5053
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
final class MetricsIntegration<Dependencies>: NSObject, SwiftIntegration {
2+
init?(with options: Options, dependencies: Dependencies) {
3+
guard options.enableMetrics else { return nil }
4+
5+
SentrySDKLog.debug("Integration initialized")
6+
}
7+
8+
func uninstall() {}
9+
10+
static var name: String {
11+
"SentryMetricsIntegration"
12+
}
13+
}

Sources/Swift/Options.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@
130130
/// @note Default value is @c false.
131131
@objc public var enableLogs: Bool = false
132132

133+
/// When enabled, the SDK sends metrics to Sentry. Metrics can be captured using the SentrySDK.metrics
134+
/// API, which allows you to send, view and query counters, gauges and measurements.
135+
/// @note Default value is @c false.
136+
@objc public var enableMetrics: Bool = false
137+
133138
/// Use this callback to drop or modify a log before the SDK sends it to Sentry. Return nil to
134139
/// drop the log.
135140
@objc public var beforeSendLog: ((SentryLog) -> SentryLog?)?
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Foundation
2+
@_spi(Private) @testable import Sentry
3+
@_spi(Private) import SentryTestUtils
4+
import XCTest
5+
6+
class MetricsIntegrationTests: XCTestCase {
7+
8+
func testStartSDK_whenIntegrationIsNotEnabled_shouldNotBeInstalled() {
9+
// -- Act --
10+
startSDK(isEnabled: false)
11+
12+
// -- Assert --
13+
XCTAssertEqual(SentrySDKInternal.currentHub().trimmedInstalledIntegrationNames().count, 0)
14+
}
15+
16+
func testStartSDK_whenIntegrationIsEnabled_shouldBeInstalled() {
17+
// -- Act --
18+
startSDK(isEnabled: true)
19+
20+
// -- Assert --
21+
XCTAssertEqual(SentrySDKInternal.currentHub().trimmedInstalledIntegrationNames().count, 1)
22+
}
23+
24+
// MARK: - Helpers
25+
26+
private func startSDK(isEnabled: Bool, configure: ((Options) -> Void)? = nil) {
27+
SentrySDK.start {
28+
$0.dsn = TestConstants.dsnForTestCase(type: MetricsIntegrationTests.self)
29+
$0.removeAllIntegrations()
30+
31+
$0.enableMetrics = isEnabled
32+
33+
configure?($0)
34+
}
35+
SentrySDKInternal.currentHub().startSession()
36+
}
37+
38+
private func getSut() throws -> MetricsIntegration<Dependencies> {
39+
return try XCTUnwrap(SentrySDKInternal.currentHub().installedIntegrations().first as? MetricsIntegration)
40+
}
41+
}

0 commit comments

Comments
 (0)