Skip to content

Commit ea2e54c

Browse files
authored
Add beforeSendLog callback to SentryOptions (#5678)
1 parent ae16459 commit ea2e54c

17 files changed

+9117
-4744
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
### Features
1616

1717
- Add a new prebuilt framework with arm64e and remove it from the regular one (#5788)
18+
- Add `beforeSendLog` callback to `SentryOptions` (#5678)
1819

1920
### Fixes
2021

Sentry.xcodeproj/project.pbxproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,6 @@
795795
9264E1EB2E2E385E00B077CF /* SentryLogMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9264E1EA2E2E385B00B077CF /* SentryLogMessage.swift */; };
796796
9264E1ED2E2E397C00B077CF /* SentryLogMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9264E1EC2E2E397400B077CF /* SentryLogMessageTests.swift */; };
797797
92672BB629C9A2A9006B021C /* SentryBreadcrumb+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92672BB529C9A2A9006B021C /* SentryBreadcrumb+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
798-
926C89732E26A30C006F3154 /* SentryScope+PrivateSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 926C89722E26A30C006F3154 /* SentryScope+PrivateSwift.h */; };
799798
927A5CC42DD7626B00B82404 /* SentryEnvelopeItemHeaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927A5CC32DD7626400B82404 /* SentryEnvelopeItemHeaderTests.swift */; };
800799
928207C42E251B8F009285A4 /* SentryScope+PrivateSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 928207C32E251B8F009285A4 /* SentryScope+PrivateSwift.h */; };
801800
9286059529A5096600F96038 /* SentryGeo.h in Headers */ = {isa = PBXBuildFile; fileRef = 9286059429A5096600F96038 /* SentryGeo.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -2119,7 +2118,6 @@
21192118
9264E1EA2E2E385B00B077CF /* SentryLogMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryLogMessage.swift; sourceTree = "<group>"; };
21202119
9264E1EC2E2E397400B077CF /* SentryLogMessageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryLogMessageTests.swift; sourceTree = "<group>"; };
21212120
92672BB529C9A2A9006B021C /* SentryBreadcrumb+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SentryBreadcrumb+Private.h"; path = "include/HybridPublic/SentryBreadcrumb+Private.h"; sourceTree = "<group>"; };
2122-
926C89722E26A30C006F3154 /* SentryScope+PrivateSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryScope+PrivateSwift.h"; path = "include/SentryScope+PrivateSwift.h"; sourceTree = "<group>"; };
21232121
927A5CC32DD7626400B82404 /* SentryEnvelopeItemHeaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryEnvelopeItemHeaderTests.swift; sourceTree = "<group>"; };
21242122
928207C32E251B8F009285A4 /* SentryScope+PrivateSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryScope+PrivateSwift.h"; path = "include/SentryScope+PrivateSwift.h"; sourceTree = "<group>"; };
21252123
9286059429A5096600F96038 /* SentryGeo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryGeo.h; path = Public/SentryGeo.h; sourceTree = "<group>"; };
@@ -4736,7 +4734,6 @@
47364734
F474CB872E2EC5040001DF41 /* Recovered References */ = {
47374735
isa = PBXGroup;
47384736
children = (
4739-
926C89722E26A30C006F3154 /* SentryScope+PrivateSwift.h */,
47404737
);
47414738
name = "Recovered References";
47424739
sourceTree = "<group>";
@@ -4943,7 +4940,6 @@
49434940
63FE713F20DA4C1100CDBAE8 /* SentryCrashStackCursor_SelfThread.h in Headers */,
49444941
639FCFA41EBC809A00778193 /* SentryStacktrace.h in Headers */,
49454942
620379DB2AFE1415005AC0C1 /* SentryBuildAppStartSpans.h in Headers */,
4946-
926C89732E26A30C006F3154 /* SentryScope+PrivateSwift.h in Headers */,
49474943
63FE716320DA4C1100CDBAE8 /* SentryCrashDynamicLinker.h in Headers */,
49484944
D4AF00232D2E931000F5F3D7 /* SentryNSFileManagerSwizzling.h in Headers */,
49494945
639FCF981EBC7B9700778193 /* SentryEvent.h in Headers */,

Sources/Sentry/Public/SentryDefines.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
@class SentryEvent;
7676
@class SentrySamplingContext;
7777
@class SentryUserFeedbackConfiguration;
78+
@class SentryLog;
7879
@protocol SentrySpan;
7980

8081
/**
@@ -107,6 +108,14 @@ typedef SentryEvent *_Nullable (^SentryBeforeSendEventCallback)(SentryEvent *_No
107108
*/
108109
typedef id<SentrySpan> _Nullable (^SentryBeforeSendSpanCallback)(id<SentrySpan> _Nonnull span);
109110

111+
#if !SWIFT_PACKAGE
112+
/**
113+
* Use this block to drop or modify a log before the SDK sends it to Sentry. Return @c nil to drop
114+
* the log.
115+
*/
116+
typedef SentryLog *_Nullable (^SentryBeforeSendLogCallback)(SentryLog *_Nonnull log);
117+
#endif // !SWIFT_PACKAGE
118+
110119
/**
111120
* Block can be used to decide if the SDK should capture a screenshot or not. Return @c true if the
112121
* SDK should capture a screenshot, return @c false if not. This callback doesn't work for crashes.

Sources/Sentry/Public/SentryOptions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ NS_SWIFT_NAME(Options)
156156
*/
157157
@property (nullable, nonatomic, copy) SentryBeforeSendSpanCallback beforeSendSpan NS_SWIFT_SENDABLE;
158158

159+
#if !SWIFT_PACKAGE
160+
/**
161+
* Use this callback to drop or modify a log before the SDK sends it to Sentry. Return @c nil to
162+
* drop the log.
163+
*/
164+
@property (nullable, nonatomic, copy) SentryBeforeSendLogCallback beforeSendLog NS_SWIFT_SENDABLE;
165+
#endif // !SWIFT_PACKAGE
166+
159167
/**
160168
* This block can be used to modify the event before it will be serialized and sent.
161169
*/

Sources/Sentry/SentryOptions.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,26 @@ @implementation SentryOptions {
2727
#if !SDK_V9
2828
BOOL _enableTracingManual;
2929
#endif // !SDK_V9
30+
#if SWIFT_PACKAGE || SENTRY_TEST
31+
id _beforeSendLogDynamic;
32+
#endif // SWIFT_PACKAGE || SENTRY_TEST
3033
}
3134

35+
#if SWIFT_PACKAGE || SENTRY_TEST
36+
// Provide explicit implementation for SPM builds where the property is excluded from header
37+
// Use id to avoid typedef dependency, Swift extension provides type safety
38+
- (id)beforeSendLogDynamic
39+
{
40+
return _beforeSendLogDynamic;
41+
}
42+
43+
- (void)setBeforeSendLogDynamic:(id)beforeSendLogDynamic
44+
{
45+
_beforeSendLogDynamic = beforeSendLogDynamic;
46+
}
47+
48+
#endif // SWIFT_PACKAGE || SENTRY_TEST
49+
3250
+ (NSArray<NSString *> *)defaultIntegrations
3351
{
3452
NSArray<Class> *defaultIntegrationClasses = [SentryOptionsInternal defaultIntegrationClasses];
Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,80 @@
1-
struct SentryLog: Codable {
2-
let timestamp: Date
3-
let traceId: SentryId
4-
let level: SentryLog.Level
5-
let body: String
6-
let attributes: [String: SentryLog.Attribute]
7-
let severityNumber: Int?
1+
/// A structured log entry that captures log data with associated attribute metadata.
2+
///
3+
/// Use the `options.beforeSendLog` callback to modify or filter log data.
4+
@objc
5+
@objcMembers
6+
public final class SentryLog: NSObject {
7+
/// The timestamp when the log event occurred
8+
public var timestamp: Date
9+
/// The trace ID to associate this log with distributed tracing
10+
public var traceId: SentryId
11+
/// The severity level of the log entry
12+
public var level: Level
13+
/// The main log message content
14+
public var body: String
15+
/// A dictionary of structured attributes added to the log entry
16+
public var attributes: [String: Attribute]
17+
/// Numeric representation of the severity level (Int)
18+
public var severityNumber: NSNumber?
819

9-
private enum CodingKeys: String, CodingKey {
10-
case timestamp
11-
case traceId = "trace_id"
12-
case level
13-
case body
14-
case attributes
15-
case severityNumber = "severity_number"
16-
}
17-
18-
/// The traceId is initially an empty default value and is populated during processing;
19-
/// by the time processing completes, it is guaranteed to be a valid non-empty trace id.
20-
init(
20+
internal init(
2121
timestamp: Date,
2222
traceId: SentryId,
23-
level: SentryLog.Level,
23+
level: Level,
2424
body: String,
25-
attributes: [String: SentryLog.Attribute],
26-
severityNumber: Int? = nil
25+
attributes: [String: Attribute],
26+
severityNumber: NSNumber? = nil
2727
) {
2828
self.timestamp = timestamp
2929
self.traceId = traceId
3030
self.level = level
3131
self.body = body
3232
self.attributes = attributes
33-
self.severityNumber = severityNumber ?? level.toSeverityNumber()
33+
self.severityNumber = severityNumber ?? NSNumber(value: level.toSeverityNumber())
34+
super.init()
35+
}
36+
}
37+
38+
// MARK: - Internal Codable Support
39+
@_spi(Private) extension SentryLog: Codable {
40+
private enum CodingKeys: String, CodingKey {
41+
case timestamp
42+
case traceId = "trace_id"
43+
case level
44+
case body
45+
case attributes
46+
case severityNumber = "severity_number"
3447
}
3548

36-
init(from decoder: any Decoder) throws {
49+
@_spi(Private) public convenience init(from decoder: any Decoder) throws {
3750
let container = try decoder.container(keyedBy: CodingKeys.self)
3851

39-
timestamp = try container.decode(Date.self, forKey: .timestamp)
52+
let timestamp = try container.decode(Date.self, forKey: .timestamp)
4053
let traceIdString = try container.decode(String.self, forKey: .traceId)
41-
traceId = SentryId(uuidString: traceIdString)
42-
level = try container.decode(SentryLog.Level.self, forKey: .level)
43-
body = try container.decode(String.self, forKey: .body)
44-
attributes = try container.decode([String: SentryLog.Attribute].self, forKey: .attributes)
45-
severityNumber = try container.decodeIfPresent(Int.self, forKey: .severityNumber)
54+
let traceId = SentryId(uuidString: traceIdString)
55+
let level = try container.decode(Level.self, forKey: .level)
56+
let body = try container.decode(String.self, forKey: .body)
57+
let attributes = try container.decode([String: Attribute].self, forKey: .attributes)
58+
let severityNumber = try container.decodeIfPresent(Int.self, forKey: .severityNumber).map { NSNumber(value: $0) }
59+
60+
self.init(
61+
timestamp: timestamp,
62+
traceId: traceId,
63+
level: level,
64+
body: body,
65+
attributes: attributes,
66+
severityNumber: severityNumber
67+
)
4668
}
4769

48-
func encode(to encoder: any Encoder) throws {
70+
@_spi(Private) public func encode(to encoder: any Encoder) throws {
4971
var container = encoder.container(keyedBy: CodingKeys.self)
5072

5173
try container.encode(timestamp, forKey: .timestamp)
5274
try container.encode(traceId.sentryIdString, forKey: .traceId)
5375
try container.encode(level, forKey: .level)
5476
try container.encode(body, forKey: .body)
5577
try container.encode(attributes, forKey: .attributes)
56-
try container.encodeIfPresent(severityNumber, forKey: .severityNumber)
78+
try container.encodeIfPresent(severityNumber?.intValue, forKey: .severityNumber)
5779
}
5880
}

0 commit comments

Comments
 (0)