Skip to content

Conversation

@denrase
Copy link
Collaborator

@denrase denrase commented Oct 23, 2025

📜 Description

  • Adds capture(log:scope:) methods to Client
  • Adds logger API to Hub
  • Moves attributes enrichment of logs into batcher, so that hub/scope calls also get them.
  • Provides additional workarounds for circular issues regarding Logs an ObjC/Swift
  • Adds public initializers to SentryLog, so users can actually create them for hub/client method usage.

💡 Motivation and Context

Closes #6503

💚 How did you test it?

Unit tests

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

@denrase
Copy link
Collaborator Author

denrase commented Oct 23, 2025

@philipphofmann Hacked this together. Works locally. If there are no other blockers, everything should work out without breaking existing public API.

@codecov
Copy link

codecov bot commented Oct 23, 2025

Codecov Report

❌ Patch coverage is 93.95973% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.119%. Comparing base (6d0b605) to head (7510ff6).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
Sources/Swift/SentryHub.swift 0.000% 5 Missing ⚠️
Sources/Swift/SentryClient.swift 0.000% 2 Missing ⚠️
Sources/Swift/Tools/SentryLogBatcher.swift 98.684% 1 Missing ⚠️
Sources/Swift/Tools/SentryLogger.swift 83.333% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #6518       +/-   ##
=============================================
- Coverage   85.648%   85.119%   -0.529%     
=============================================
  Files          452       452               
  Lines        27655     27688       +33     
  Branches     12118     12124        +6     
=============================================
- Hits         23686     23568      -118     
- Misses        3694      3833      +139     
- Partials       275       287       +12     
Files with missing lines Coverage Δ
SentryTestUtils/Sources/TestClient.swift 86.792% <100.000%> (+0.125%) ⬆️
Sources/Sentry/SentryClient.m 97.431% <100.000%> (-1.640%) ⬇️
Sources/Sentry/SentryHub.m 96.526% <100.000%> (+0.181%) ⬆️
Sources/Sentry/SentrySDKInternal.m 83.673% <ø> (-0.067%) ⬇️
Sources/Swift/Helper/SentrySDK.swift 83.516% <100.000%> (-3.772%) ⬇️
Sources/Swift/Protocol/SentryLog.swift 100.000% <100.000%> (ø)
Sources/Swift/Tools/SentryLogBatcher.swift 98.425% <98.684%> (+0.149%) ⬆️
Sources/Swift/Tools/SentryLogger.swift 97.222% <83.333%> (-2.043%) ⬇️
Sources/Swift/SentryClient.swift 7.894% <0.000%> (-0.439%) ⬇️
Sources/Swift/SentryHub.swift 0.000% <0.000%> (ø)

... and 15 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6d0b605...7510ff6. Read the comment docs.

@denrase denrase changed the title Logs: Hub and Client APIs Structured Logs: Add captureLog to Hub and Client Oct 24, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Oct 24, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1220.14 ms 1258.02 ms 37.88 ms
Size 23.75 KiB 1.00 MiB 1002.61 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3279d4e 1215.76 ms 1256.45 ms 40.69 ms
37183fe 1212.33 ms 1238.92 ms 26.59 ms
80a5166 1224.49 ms 1251.29 ms 26.80 ms
0b5fd21 1237.52 ms 1251.36 ms 13.84 ms
8745cc0 1228.13 ms 1250.48 ms 22.35 ms
ebc72be 1221.24 ms 1249.66 ms 28.42 ms
0b6776b 1230.18 ms 1262.06 ms 31.88 ms
6e99155 1223.96 ms 1249.25 ms 25.29 ms
e8f9a1d 1229.02 ms 1264.17 ms 35.15 ms
535ebd9 1194.59 ms 1219.84 ms 25.26 ms

App size

Revision Plain With Sentry Diff
3279d4e 23.75 KiB 938.32 KiB 914.57 KiB
37183fe 23.75 KiB 913.63 KiB 889.87 KiB
80a5166 23.75 KiB 904.53 KiB 880.78 KiB
0b5fd21 23.75 KiB 912.78 KiB 889.03 KiB
8745cc0 23.74 KiB 971.81 KiB 948.07 KiB
ebc72be 23.75 KiB 908.22 KiB 884.47 KiB
0b6776b 23.75 KiB 968.23 KiB 944.49 KiB
6e99155 23.75 KiB 963.18 KiB 939.43 KiB
e8f9a1d 23.75 KiB 969.78 KiB 946.04 KiB
535ebd9 23.75 KiB 1008.67 KiB 984.92 KiB

Previous results on branch: denrase/logs-in-hub-and-client

Startup times

Revision Plain With Sentry Diff
391bd71 1231.72 ms 1262.83 ms 31.11 ms
db59d5d 1217.41 ms 1240.59 ms 23.18 ms
cf93b3b 1224.50 ms 1246.35 ms 21.85 ms
31d864b 1212.77 ms 1246.85 ms 34.08 ms
08821c7 1206.15 ms 1239.35 ms 33.20 ms
9df70d3 1228.40 ms 1262.55 ms 34.16 ms
a429649 1216.39 ms 1217.77 ms 1.39 ms
225f528 1211.81 ms 1252.58 ms 40.77 ms

App size

Revision Plain With Sentry Diff
391bd71 23.75 KiB 1.00 MiB 1004.71 KiB
db59d5d 23.75 KiB 1.01 MiB 1006.79 KiB
cf93b3b 23.75 KiB 1.00 MiB 1003.12 KiB
31d864b 23.75 KiB 1.00 MiB 1003.12 KiB
08821c7 23.75 KiB 1.02 MiB 1017.66 KiB
9df70d3 23.75 KiB 1.01 MiB 1006.51 KiB
a429649 23.75 KiB 1.00 MiB 1002.92 KiB
225f528 23.75 KiB 1.01 MiB 1006.79 KiB

@denrase denrase marked this pull request as ready for review October 24, 2025 14:22
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

# Conflicts:
#	Sources/Sentry/SentryClient.m
#	Sources/Sentry/SentryHub.m
#	Sources/Sentry/include/SentryClient+Logs.h
#	Sources/Swift/Helper/SentrySDK.swift
#	Sources/Swift/Tools/SentryLogBatcher.swift
#	Sources/Swift/Tools/SentryLogger.swift
#	sdk_api.json
@denrase denrase changed the title Structured Logs: Add captureLog to Hub and Client Structured Logs: Add log APIs to Hub and Client Nov 4, 2025
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

Copy link
Member

@philipphofmann philipphofmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We slowly getting to LGTM. Thanks @denrase for including the feedback.

Comment on lines 104 to 106
// Do not use this directly, instead use the non-underscored `captureLog` method that is
// defined through a SentryClient.swift file.
- (void)_swiftCaptureLog:(NSObject *)log withScope:(SentryScope *)scope;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h: Can't we move that to SentryClient+Private.h? If not, please double-check with Noah if he has an idea how to avoid this. I would really like to avoid this. The same applies to the _swiftLogger of the SentryHub.

Copy link
Collaborator Author

@denrase denrase Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is the circular dependency with Swift/ObjC. Checked and this seems to be how it's done elsewhere in the SDK. One solution would be to move SentryLog to ObjC implementations, then it's not needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked, using SentryLog (Swift) in ObjC SentryClientInternal.h and then trying to call it from Swift again does only work for non-SPM build. @noahsmartin Do you have any suggestion on how to better handle this?

Copy link
Collaborator Author

@denrase denrase Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@noahsmartin Pretty much the same approach as we have here #5329, with the difference being that we are here now on an internal class, which does make it more risky, but we'll get a compile issue when we change the method signature, since we are no using dynamism here.

Comment on lines +1100 to +1105
- (void)_swiftCaptureLog:(NSObject *)log withScope:(SentryScope *)scope
{
if ([log isKindOfClass:[SentryLog class]]) {
[self.logBatcher addLog:(SentryLog *)log scope:scope];
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: We use SentryLog below. What drove you to use NSObject here. Can't we use SentryLog?

Suggested change
- (void)_swiftCaptureLog:(NSObject *)log withScope:(SentryScope *)scope
{
if ([log isKindOfClass:[SentryLog class]]) {
[self.logBatcher addLog:(SentryLog *)log scope:scope];
}
}
- (void)_swiftCaptureLog:(SentryLog *)log withScope:(SentryScope *)scope
{
[self.logBatcher addLog:log scope:scope];
}

Copy link
Collaborator Author

@denrase denrase Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, cause this is a Swift Type used in ObjC, once we call the internal hub from Swift (when using SPM), it's not visible.

if (client != nil) {
#if SENTRY_TARGET_REPLAY_SUPPORTED
NSMutableDictionary<NSString *, SentryStructuredLogAttribute *> *mutableAttributes =
[log.attributes mutableCopy];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: We can avoid allocating this mutable copy. We only need to add the sentry.replay_id attribute when SR is active. It would be great to modify the code to do so.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The swift dict is visibla als non-mutable in ObjC. I have added a helper method to set individual attributes.

Comment on lines +34 to +36
// swiftlint:disable force_cast
return SentrySDKInternal.currentHub()._swiftLogger as! SentryLogger
// swiftlint:enable force_cast
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: I would prefer getting rid of this force cast by trying to change the type of the _swiftLogger property to SentryLogger. SentryLogger is public so it should work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above, when using SPM, logger would not be visible here due tu circular dependency between Swift/Objc parts of the SDK.

) {
self.init(
timestamp: Date(),
traceId: SentryId.empty,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, then let's keep it. Please add a comment explaining this.

// that limitation by providing Swift-native methods and properties that use dynamic
// dispatch internally.

#if SWIFT_PACKAGE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@noahsmartin, can you please double-check if this approach works?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is existing code, I just moved it to its own file so it stays on our radar. Circular dependency issue when installing through SPM, before that, the SPM target on CI would not compile.

cursor[bot]

This comment was marked as outdated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Logs: Hub and Client APIs

4 participants