Skip to content
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
196c9aa
feat(metrics): Add integration with installation by SDK
philprime Dec 2, 2025
81d9980
update changelog
philprime Dec 2, 2025
420d68e
update changelog
philprime Dec 2, 2025
dcc65ff
change type of SUT in MetricsIntegrationTests
philprime Dec 2, 2025
46e42f5
Add metrics to TestOptions.removeAllIntegrations
philprime Dec 2, 2025
8dfb9e6
change default value in disableEverything
philprime Dec 2, 2025
1210307
add missing test tear down
philprime Dec 2, 2025
e5611fb
Add enableMetrics to public header
philprime Dec 2, 2025
3ca02d7
refactor(refactor): Add generic internal item batcher
philprime Dec 9, 2025
193c27b
Add SentryItemBatcherTests to enhance item batching functionality
philprime Dec 9, 2025
b1891d3
fixed tests and added more protocols
philprime Dec 9, 2025
e89eab0
Merge remote-tracking branch 'origin/main' into philprime/log-batcher…
philprime Dec 10, 2025
eb09954
refactor item batcher
philprime Dec 10, 2025
cc065bb
refactor item batcher into protocols
philprime Dec 11, 2025
8be32e7
cleanup
philprime Dec 11, 2025
21d4e61
Update Sources/Swift/Protocol/SentryAttribute.swift
philprime Dec 11, 2025
c17ef37
Enhance Batcher and TestCurrentDateProvider functionality
philprime Dec 11, 2025
421210a
Merge branch 'philprime/log-batcher-abstraction' into philprime/metrics
philprime Dec 11, 2025
d3c3b47
Merge branch 'philprime/metrics' into philprime/metrics-bootstrap
philprime Dec 11, 2025
f463844
Merge remote-tracking branch 'origin/main' into philprime/metrics
philprime Dec 11, 2025
6a56d9c
Merge branch 'philprime/metrics' into philprime/metrics-bootstrap
philprime Dec 11, 2025
f17e9e1
Merge remote-tracking branch 'origin/main' into philprime/metrics
philprime Dec 15, 2025
c46d92c
Merge branch 'philprime/metrics' into philprime/metrics-bootstrap
philprime Dec 15, 2025
c69eb95
update changelog
philprime Dec 15, 2025
5f4299a
Remove unneeded code
philprime Dec 15, 2025
46a2f3e
add missing options setter
philprime Dec 15, 2025
6ece2f8
test: Add unit tests for enabling and disabling metrics feature
philprime Dec 15, 2025
1d80fda
test: Update MetricsIntegrationTests to assert integration name
philprime Dec 15, 2025
99f563e
Merge remote-tracking branch 'origin/main' into philprime/metrics-boo…
philprime Dec 16, 2025
bd60a8c
fix(logs): Use sendDefaultPii and span_id for attributes
philprime Dec 16, 2025
3a22103
Update changelog
philprime Dec 16, 2025
23057b4
Merge branch 'philprime/logs-span-id' into philprime/metrics-bootstrap
philprime Dec 16, 2025
e3c7019
update public api
philprime Dec 16, 2025
28fc0dd
Apply suggestions from code review
philprime Dec 16, 2025
3b2eba9
remove scope sendDefaultPii
philprime Dec 17, 2025
ac1b46e
remove scope sendDefaultPii
philprime Dec 17, 2025
872c2d4
Update CHANGELOG.md
philprime Dec 17, 2025
f8dd108
fix test assert
philprime Dec 17, 2025
b092849
Merge remote-tracking branch 'origin/philprime/logs-span-id' into phi…
philprime Dec 17, 2025
5dab77e
move option to experimental
philprime Dec 17, 2025
15f7316
Merge remote-tracking branch 'origin/main' into philprime/metrics-boo…
philprime Dec 17, 2025
0a2b72f
move option to experimental
philprime Dec 17, 2025
86e21d3
cleanup
philprime Dec 17, 2025
7e9e86f
Merge remote-tracking branch 'origin/main' into philprime/metrics-boo…
philprime Dec 18, 2025
14f9cdd
add missing experimental subtype
philprime Dec 18, 2025
e61661b
Merge remote-tracking branch 'origin/main' into philprime/metrics-boo…
philprime Dec 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Add integration to collect Metrics, can be enabled by setting `options.enableMetrics = true` (#6956)

## 9.1.0

> [!Warning]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public enum SentrySDKOverrides: String, CaseIterable {
case .tracing: return SentrySDKOverrides.Tracing.allCases
case .profiling: return SentrySDKOverrides.Profiling.allCases
case .networking: return SentrySDKOverrides.Networking.allCases
case .metrics: return SentrySDKOverrides.Metrics.allCases
}
}

Expand Down Expand Up @@ -167,6 +168,11 @@ public enum SentrySDKOverrides: String, CaseIterable {
case immediateStop = "--io.sentry.profiling.continuous-profiler-immediate-stop"
}
case profiling = "Profiling"

public enum Metrics: String, SentrySDKOverride {
case enable = "--io.sentry.metrics.enable"
}
case metrics = "Metrics"
}

// MARK: Public flag/variable value access
Expand Down Expand Up @@ -348,6 +354,14 @@ extension SentrySDKOverrides.Special {
}
}

extension SentrySDKOverrides.Metrics {
public var overrideType: OverrideType {
switch self {
case .enable: return .boolean
}
}
}

// MARK: Disable Everything Helper

// 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.
Expand Down Expand Up @@ -429,4 +443,11 @@ extension SentrySDKOverrides.Special {
}
}

extension SentrySDKOverrides.Metrics {
public var ignoresDisableEverything: Bool {
switch self {
case .enable: return true
}
}
}
// swiftlint:enable file_length
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,12 @@ public struct SentrySDKWrapper {
options.configureUserFeedback = configureFeedback(config:)
#endif // !os(macOS) && !os(tvOS) && !os(watchOS) && !os(visionOS)

// Integration: Logs
options.enableLogs = true

// Integration: Metrics
options.enableMetrics = SentrySDKOverrides.Metrics.enable.boolValue

// Experimental features
options.enableFileManagerSwizzling = !SentrySDKOverrides.Other.disableFileManagerSwizzling.boolValue
options.experimental.enableUnhandledCPPExceptionsV2 = true
Expand Down
3 changes: 3 additions & 0 deletions Samples/Shared/feature-flags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ schemeTemplates:
"--io.sentry.other.reject-view-hierarchy-in-before-capture-view-hierarchy": false
"--io.sentry.other.reject-all-spans": false

# metrics
"--io.sentry.metrics.enable": false

environmentVariables:
# events
- variable: "--io.sentry.events.sampleRate"
Expand Down
24 changes: 24 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@
D46712622DCD059900D4074A /* SentryRedactDefaultOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46712612DCD059500D4074A /* SentryRedactDefaultOptionsTests.swift */; };
D46712642DCD063800D4074A /* PreviewRedactOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46712632DCD062700D4074A /* PreviewRedactOptionsTests.swift */; };
D468C0622D3669A200964230 /* SentryFileIOTracker+SwiftHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D468C0612D3669A200964230 /* SentryFileIOTracker+SwiftHelpers.swift */; };
D46B041D2EDF168400AF4A0A /* MetricsIntegration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46B041C2EDF167D00AF4A0A /* MetricsIntegration.swift */; };
D46B04202EDF175C00AF4A0A /* MetricsIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46B041F2EDF175600AF4A0A /* MetricsIntegrationTests.swift */; };
D473ACD72D8090FC000F1CC6 /* FileManager+SentryTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D473ACD62D8090FC000F1CC6 /* FileManager+SentryTracing.swift */; };
D480F9D92DE47A50009A0594 /* TestSentryScopePersistentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D480F9D82DE47A48009A0594 /* TestSentryScopePersistentStore.swift */; };
D480F9DB2DE47AF2009A0594 /* SentryScopePersistentStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D480F9DA2DE47AEB009A0594 /* SentryScopePersistentStoreTests.swift */; };
Expand Down Expand Up @@ -2146,6 +2148,8 @@
D46712612DCD059500D4074A /* SentryRedactDefaultOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRedactDefaultOptionsTests.swift; sourceTree = "<group>"; };
D46712632DCD062700D4074A /* PreviewRedactOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewRedactOptionsTests.swift; sourceTree = "<group>"; };
D468C0612D3669A200964230 /* SentryFileIOTracker+SwiftHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SentryFileIOTracker+SwiftHelpers.swift"; sourceTree = "<group>"; };
D46B041C2EDF167D00AF4A0A /* MetricsIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetricsIntegration.swift; sourceTree = "<group>"; };
D46B041F2EDF175600AF4A0A /* MetricsIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetricsIntegrationTests.swift; sourceTree = "<group>"; };
D46D45E12D5F3FD600A1CB35 /* Sentry_Base.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sentry_Base.xctestplan; sourceTree = "<group>"; };
D46D45E92D5F411700A1CB35 /* SentrySwiftUI_Base.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = SentrySwiftUI_Base.xctestplan; path = Plans/SentrySwiftUI_Base.xctestplan; sourceTree = SOURCE_ROOT; };
D473ACD62D8090FC000F1CC6 /* FileManager+SentryTracing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+SentryTracing.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3522,6 +3526,7 @@
F498EBA52EE0B8E400F57509 /* SentrySwiftIntegrationInstallerTests.swift */,
843FB3422D156B9900558F18 /* Feedback */,
7BF6505D292B77D100BBA5A8 /* MetricKit */,
D46B041E2EDF173A00AF4A0A /* Metrics */,
D808FB85281AB2EF009A2A33 /* UIEvents */,
D8AB40D92806EBDC00E5E9F7 /* Screenshot */,
0A9BF4E528A123070068D266 /* ViewHierarchy */,
Expand Down Expand Up @@ -4394,6 +4399,22 @@
path = IO;
sourceTree = "<group>";
};
D46B04162EDF167800AF4A0A /* Metrics */ = {
isa = PBXGroup;
children = (
D46B041C2EDF167D00AF4A0A /* MetricsIntegration.swift */,
);
path = Metrics;
sourceTree = "<group>";
};
D46B041E2EDF173A00AF4A0A /* Metrics */ = {
isa = PBXGroup;
children = (
D46B041F2EDF175600AF4A0A /* MetricsIntegrationTests.swift */,
);
path = Metrics;
sourceTree = "<group>";
};
D46D45E22D5F3FD600A1CB35 /* Plans */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4879,6 +4900,7 @@
isa = PBXGroup;
children = (
925189AB2EDDA6A300557BD1 /* Log */,
D46B04162EDF167800AF4A0A /* Metrics */,
FAB0073C2E9F47DE001C806A /* Session */,
FAE579B42E7DBE9400B710F9 /* SentryGlobalEventProcessor.swift */,
FAD882C12EDAADF90055AA44 /* SwiftAsyncIntegration.swift */,
Expand Down Expand Up @@ -6195,6 +6217,7 @@
62E59A5A2E8FB85300DB7A7B /* SentryTracePropagation.m in Sources */,
FAB007522E9FE2FF001C806A /* SentrySwizzleWrapper.swift in Sources */,
62E300942D5202890037AA3F /* SentryExceptionCodable.swift in Sources */,
D46B041D2EDF168400AF4A0A /* MetricsIntegration.swift in Sources */,
0A2D8D5B289815C0008720F6 /* SentryBaseIntegration.m in Sources */,
639FCF991EBC7B9700778193 /* SentryEvent.m in Sources */,
D820CDB72BB1895F00BA339D /* SentrySessionReplayIntegration.m in Sources */,
Expand Down Expand Up @@ -6282,6 +6305,7 @@
7BFAA6E7297AA16A00E7E02E /* SentryCrashMonitor_CppException_Tests.mm in Sources */,
9286059929A50BAB00F96038 /* SentryGeoTests.swift in Sources */,
621655662DB12A8900810504 /* SentryCrashMach-OTests.m in Sources */,
D46B04202EDF175C00AF4A0A /* MetricsIntegrationTests.swift in Sources */,
62B220BB2E93A9EC004620FF /* SentryTracePropagationTests.swift in Sources */,
D8B76B0828081461000A58C4 /* TestSentryScreenshotProvider.swift in Sources */,
A8AFFCD22907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions SentryTestUtils/Sources/TestOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public extension Options {
attachViewHierarchy = false
enableUIViewControllerTracing = false
#endif
enableMetrics = false
}

static func noIntegrations() -> Options {
Expand Down
3 changes: 3 additions & 0 deletions Sources/Sentry/SentryOptionsInternal.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ + (BOOL)validateOptions:(NSDictionary<NSString *, id> *)options

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

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

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

Expand Down
3 changes: 2 additions & 1 deletion Sources/Swift/Core/Integrations/Integrations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ private struct AnyIntegration {

var integrations: [AnyIntegration] = [
.init(SwiftAsyncIntegration.self),
.init(SentryAutoSessionTrackingIntegration.self)
.init(SentryAutoSessionTrackingIntegration.self),
.init(MetricsIntegration.self)
]

#if os(iOS) && !SENTRY_NO_UIKIT
Expand Down
3 changes: 3 additions & 0 deletions Sources/Swift/Helper/SentryEnabledFeaturesBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import Foundation
if options.experimental.enableUnhandledCPPExceptionsV2 {
features.append("unhandledCPPExceptionsV2")
}
if options.enableMetrics {
features.append("metrics")
}

return features
}
Expand Down
13 changes: 13 additions & 0 deletions Sources/Swift/Integrations/Metrics/MetricsIntegration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
final class MetricsIntegration<Dependencies>: NSObject, SwiftIntegration {
init?(with options: Options, dependencies: Dependencies) {
guard options.enableMetrics else { return nil }

SentrySDKLog.debug("Integration initialized")
}

func uninstall() {}

static var name: String {
"MetricsIntegration"
}
}
5 changes: 5 additions & 0 deletions Sources/Swift/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@
/// @note Default value is @c false.
@objc public var enableLogs: Bool = false

/// When enabled, the SDK sends metrics to Sentry. Metrics can be captured using the SentrySDK.metrics
/// API, which allows you to send, view and query counters, gauges and measurements.
/// @note Default value is @c false.
@objc public var enableMetrics: Bool = false

/// Use this callback to drop or modify a log before the SDK sends it to Sentry. Return nil to
/// drop the log.
@objc public var beforeSendLog: ((SentryLog) -> SentryLog?)?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,30 @@ final class SentryEnabledFeaturesBuilderTests: XCTestCase {
// -- Assert --
XCTAssert(features.contains("unhandledCPPExceptionsV2"))
}

func testEnableMetrics_isEnabled_shouldAddFeature() throws {
// -- Arrange --
let options = Options()

options.enableMetrics = true

// -- Act --
let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)

// -- Assert --
XCTAssert(features.contains("metrics"))
}

func testEnableMetrics_isDisabled_shouldNotAddFeature() throws {
// -- Arrange --
let options = Options()

options.enableMetrics = false

// -- Act --
let features = SentryEnabledFeaturesBuilder.getEnabledFeatures(options: options)

// -- Assert --
XCTAssertFalse(features.contains("metrics"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Foundation
@_spi(Private) @testable import Sentry
@_spi(Private) import SentryTestUtils
import XCTest

class MetricsIntegrationTests: XCTestCase {

override func tearDown() {
super.tearDown()
clearTestState()
}

// MARK: - Tests

func testStartSDK_whenIntegrationIsNotEnabled_shouldNotBeInstalled() {
// -- Act --
startSDK(isEnabled: false)

// -- Assert --
XCTAssertEqual(SentrySDKInternal.currentHub().trimmedInstalledIntegrationNames().count, 0)
}

func testStartSDK_whenIntegrationIsEnabled_shouldBeInstalled() {
// -- Act --
startSDK(isEnabled: true)

// -- Assert --
XCTAssertEqual(SentrySDKInternal.currentHub().trimmedInstalledIntegrationNames().first, "Metrics")
}

// MARK: - Helpers

private func startSDK(isEnabled: Bool, configure: ((Options) -> Void)? = nil) {
SentrySDK.start {
$0.dsn = TestConstants.dsnForTestCase(type: MetricsIntegrationTests.self)
$0.removeAllIntegrations()

$0.enableMetrics = isEnabled

configure?($0)
}
}
}
5 changes: 5 additions & 0 deletions Tests/SentryTests/SentryOptionsTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ - (void)testEnableLogs
[self testBooleanField:@"enableLogs" defaultValue:NO];
}

- (void)testEnableMetrics
{
[self testBooleanField:@"enableMetrics" defaultValue:NO];
}

- (void)testEnableAutoBreadcrumbTracking
{
[self testBooleanField:@"enableAutoBreadcrumbTracking"];
Expand Down
76 changes: 76 additions & 0 deletions sdk_api.json
Original file line number Diff line number Diff line change
Expand Up @@ -45757,6 +45757,82 @@
}
]
},
{
"kind": "Var",
"name": "enableMetrics",
"printedName": "enableMetrics",
"children": [
{
"kind": "TypeNominal",
"name": "Bool",
"printedName": "Swift.Bool",
"usr": "s:Sb"
}
],
"declKind": "Var",
"usr": "c:@M@Sentry@objc(cs)SentryOptions(py)enableMetrics",
"mangledName": "$s6Sentry7OptionsC13enableMetricsSbvp",
"moduleName": "Sentry",
"declAttributes": [
"Final",
"ObjC",
"HasStorage"
],
"hasStorage": true,
"accessors": [
{
"kind": "Accessor",
"name": "Get",
"printedName": "Get()",
"children": [
{
"kind": "TypeNominal",
"name": "Bool",
"printedName": "Swift.Bool",
"usr": "s:Sb"
}
],
"declKind": "Accessor",
"usr": "c:@M@Sentry@objc(cs)SentryOptions(im)enableMetrics",
"mangledName": "$s6Sentry7OptionsC13enableMetricsSbvg",
"moduleName": "Sentry",
"implicit": true,
"declAttributes": [
"Final",
"ObjC"
],
"accessorKind": "get"
},
{
"kind": "Accessor",
"name": "Set",
"printedName": "Set()",
"children": [
{
"kind": "TypeNominal",
"name": "Void",
"printedName": "()"
},
{
"kind": "TypeNominal",
"name": "Bool",
"printedName": "Swift.Bool",
"usr": "s:Sb"
}
],
"declKind": "Accessor",
"usr": "c:@M@Sentry@objc(cs)SentryOptions(im)setEnableMetrics:",
"mangledName": "$s6Sentry7OptionsC13enableMetricsSbvs",
"moduleName": "Sentry",
"implicit": true,
"declAttributes": [
"Final",
"ObjC"
],
"accessorKind": "set"
}
]
},
{
"kind": "Var",
"name": "beforeSendLog",
Expand Down
Loading