Skip to content

Commit

Permalink
fix: Use the same SdkInfo for envelope header and event (#4629)
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich authored Dec 16, 2024
1 parent 419f1d4 commit 716a5b0
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 121 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Fixes

- `SentrySdkInfo.packages` should be an array (#4626)
- Use the same SdkInfo for envelope header and event (#4629)

### Internal

Expand Down
20 changes: 2 additions & 18 deletions Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#import "SentryRandom.h"
#import "SentrySDK+Private.h"
#import "SentryScope+Private.h"
#import "SentrySdkInfo.h"
#import "SentrySerialization.h"
#import "SentrySession.h"
#import "SentryStacktraceBuilder.h"
Expand Down Expand Up @@ -880,24 +881,7 @@ - (void)setSdk:(SentryEvent *)event
return;
}

NSMutableArray<NSString *> *integrations =
[SentrySDK.currentHub trimmedInstalledIntegrationNames];

#if SENTRY_HAS_UIKIT
if (self.options.enablePreWarmedAppStartTracing) {
[integrations addObject:@"PreWarmedAppStartTracing"];
}
#endif

NSArray<NSString *> *features =
[SentryEnabledFeaturesBuilder getEnabledFeaturesWithOptions:self.options];

event.sdk = @{
@"name" : SentryMeta.sdkName,
@"version" : SentryMeta.versionString,
@"integrations" : integrations,
@"features" : features
};
event.sdk = [[[SentrySdkInfo alloc] initWithOptions:self.options] serialize];
}

- (void)setUserInfo:(NSDictionary *)userInfo withEvent:(SentryEvent *)event
Expand Down
4 changes: 1 addition & 3 deletions Sources/Sentry/SentryEnvelope.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#import "SentryEvent.h"
#import "SentryLog.h"
#import "SentryMessage.h"
#import "SentryMeta.h"
#import "SentryMsgPackSerializer.h"
#import "SentrySdkInfo.h"
#import "SentrySerialization.h"
Expand All @@ -30,8 +29,7 @@ - (instancetype)initWithId:(SentryId *_Nullable)eventId
- (instancetype)initWithId:(nullable SentryId *)eventId
traceContext:(nullable SentryTraceContext *)traceContext
{
SentrySdkInfo *sdkInfo = [[SentrySdkInfo alloc] initWithName:SentryMeta.sdkName
andVersion:SentryMeta.versionString];
SentrySdkInfo *sdkInfo = [SentrySdkInfo global];
self = [self initWithId:eventId sdkInfo:sdkInfo traceContext:traceContext];
return self;
}
Expand Down
89 changes: 66 additions & 23 deletions Sources/Sentry/SentrySdkInfo.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#import "SentrySdkInfo.h"
#import "SentryClient+Private.h"
#import "SentryHub+Private.h"
#import "SentryMeta.h"
#import "SentryOptions.h"
#import "SentrySDK+Private.h"
#import "SentrySwift.h"
#import <Foundation/Foundation.h>

typedef NS_ENUM(NSUInteger, SentryPackageManagerOption) {
Expand Down Expand Up @@ -33,48 +39,83 @@ @interface SentrySdkInfo ()

@implementation SentrySdkInfo

- (instancetype)initWithName:(NSString *)name andVersion:(NSString *)version
+ (instancetype)global
{
return [[SentrySdkInfo alloc] initWithOptions:[SentrySDK.currentHub getClient].options];
}

- (instancetype)initWithOptions:(SentryOptions *)options
{

NSArray<NSString *> *features =
[SentryEnabledFeaturesBuilder getEnabledFeaturesWithOptions:options];

NSMutableArray<NSString *> *integrations =
[SentrySDK.currentHub trimmedInstalledIntegrationNames];

#if SENTRY_HAS_UIKIT
if (options.enablePreWarmedAppStartTracing) {
[integrations addObject:@"PreWarmedAppStartTracing"];
}
#endif

return [self initWithName:SentryMeta.sdkName
version:SentryMeta.versionString
integrations:integrations
features:features];
}

- (instancetype)initWithName:(NSString *)name
version:(NSString *)version
integrations:(NSArray<NSString *> *)integrations
features:(NSArray<NSString *> *)features
{
if (self = [super init]) {
_name = name ?: @"";
_version = version ?: @"";
_packageManager = SENTRY_PACKAGE_INFO;
_integrations = integrations ?: @[];
_features = features ?: @[];
}

return self;
}

- (instancetype)initWithDict:(NSDictionary *)dict
{
return [self initWithDictInternal:dict orDefaults:nil];
}

- (instancetype)initWithDict:(NSDictionary *)dict orDefaults:(SentrySdkInfo *)info;
{
return [self initWithDictInternal:dict orDefaults:info];
}

- (instancetype)initWithDictInternal:(NSDictionary *)dict orDefaults:(SentrySdkInfo *_Nullable)info;
{
NSString *name = @"";
NSString *version = @"";
NSMutableSet<NSString *> *integrations = [[NSMutableSet alloc] init];
NSMutableSet<NSString *> *features = [[NSMutableSet alloc] init];

if (nil != dict[@"sdk"] && [dict[@"sdk"] isKindOfClass:[NSDictionary class]]) {
NSDictionary<NSString *, id> *sdkInfoDict = dict[@"sdk"];
if ([sdkInfoDict[@"name"] isKindOfClass:[NSString class]]) {
name = sdkInfoDict[@"name"];
} else if (info && info.name) {
name = info.name;
if ([dict[@"name"] isKindOfClass:[NSString class]]) {
name = dict[@"name"];
}

if ([dict[@"version"] isKindOfClass:[NSString class]]) {
version = dict[@"version"];
}

if ([dict[@"integrations"] isKindOfClass:[NSArray class]]) {
for (id item in dict[@"integrations"]) {
if ([item isKindOfClass:[NSString class]]) {
[integrations addObject:item];
}
}
}

if ([sdkInfoDict[@"version"] isKindOfClass:[NSString class]]) {
version = sdkInfoDict[@"version"];
} else if (info && info.version) {
version = info.version;
if ([dict[@"features"] isKindOfClass:[NSArray class]]) {
for (id item in dict[@"features"]) {
if ([item isKindOfClass:[NSString class]]) {
[features addObject:item];
}
}
}

return [self initWithName:name andVersion:version];
return [self initWithName:name
version:version
integrations:[integrations allObjects]
features:[features allObjects]];
}

- (nullable NSString *)getPackageName:(SentryPackageManagerOption)packageManager
Expand All @@ -96,6 +137,8 @@ - (nullable NSString *)getPackageName:(SentryPackageManagerOption)packageManager
NSMutableDictionary *sdk = @{
@"name" : self.name,
@"version" : self.version,
@"integrations" : self.integrations,
@"features" : self.features,
}
.mutableCopy;
if (self.packageManager != SentryPackageManagerUnkown) {
Expand All @@ -110,7 +153,7 @@ - (nullable NSString *)getPackageName:(SentryPackageManagerOption)packageManager
}
}

return @{ @"sdk" : sdk };
return sdk;
}

@end
Expand Down
4 changes: 2 additions & 2 deletions Sources/Sentry/SentrySerialization.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ + (NSData *_Nullable)dataWithEnvelope:(SentryEnvelope *)envelope

SentrySdkInfo *sdkInfo = envelope.header.sdkInfo;
if (nil != sdkInfo) {
[serializedData addEntriesFromDictionary:[sdkInfo serialize]];
[serializedData setValue:[sdkInfo serialize] forKey:@"sdk"];
}

SentryTraceContext *traceContext = envelope.header.traceContext;
Expand Down Expand Up @@ -111,7 +111,7 @@ + (SentryEnvelope *_Nullable)envelopeWithData:(NSData *)data

SentrySdkInfo *sdkInfo = nil;
if (nil != headerDictionary[@"sdk"]) {
sdkInfo = [[SentrySdkInfo alloc] initWithDict:headerDictionary];
sdkInfo = [[SentrySdkInfo alloc] initWithDict:headerDictionary[@"sdk"]];
}

SentryTraceContext *traceContext = nil;
Expand Down
28 changes: 25 additions & 3 deletions Sources/Sentry/include/SentrySdkInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#import <Foundation/Foundation.h>

@class SentryOptions;

NS_ASSUME_NONNULL_BEGIN

/**
Expand All @@ -22,6 +24,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface SentrySdkInfo : NSObject <SentryInternalSerializable>
SENTRY_NO_INIT

+ (instancetype)global;

/**
* The name of the SDK. Examples: sentry.cocoa, sentry.cocoa.vapor, ...
*/
Expand All @@ -34,13 +38,31 @@ SENTRY_NO_INIT
*/
@property (nonatomic, readonly, copy) NSString *version;

/**
* A list of names identifying enabled integrations. The list should
* have all enabled integrations, including default integrations. Default
* integrations are included because different SDK releases may contain different
* default integrations.
*/
@property (nonatomic, readonly, copy) NSArray<NSString *> *integrations;

/**
* A list of feature names identifying enabled SDK features. This list
* should contain all enabled SDK features. On some SDKs, enabling a feature in the
* options also adds an integration. We encourage tracking such features with either
* integrations or features but not both to reduce the payload size.
*/
@property (nonatomic, readonly, copy) NSArray<NSString *> *features;

- (instancetype)initWithOptions:(SentryOptions *)options;

- (instancetype)initWithName:(NSString *)name
andVersion:(NSString *)version NS_DESIGNATED_INITIALIZER;
version:(NSString *)version
integrations:(NSArray<NSString *> *)integrations
features:(NSArray<NSString *> *)features NS_DESIGNATED_INITIALIZER;

- (instancetype)initWithDict:(NSDictionary *)dict;

- (instancetype)initWithDict:(NSDictionary *)dict orDefaults:(SentrySdkInfo *)info;

@end

NS_ASSUME_NONNULL_END
2 changes: 1 addition & 1 deletion Tests/SentryTests/Helper/SentryFileManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class SentryFileManagerTests: XCTestCase {
}

func testStoreInvalidEnvelope_ReturnsNil() {
let sdkInfoWithInvalidJSON = SentrySdkInfo(name: SentryInvalidJSONString() as String, andVersion: "8.0.0")
let sdkInfoWithInvalidJSON = SentrySdkInfo(name: SentryInvalidJSONString() as String, version: "8.0.0", integrations: [], features: [])
let headerWithInvalidJSON = SentryEnvelopeHeader(id: nil, sdkInfo: sdkInfoWithInvalidJSON, traceContext: nil)

let envelope = SentryEnvelope(header: headerWithInvalidJSON, items: [])
Expand Down
19 changes: 15 additions & 4 deletions Tests/SentryTests/Helper/SentrySerializationTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@testable import Sentry
import SentryTestUtils
import XCTest

class SentrySerializationTests: XCTestCase {
Expand All @@ -7,7 +8,17 @@ class SentrySerializationTests: XCTestCase {
static var invalidData = "hi".data(using: .utf8)!
static var traceContext = TraceContext(trace: SentryId(), publicKey: "PUBLIC_KEY", releaseName: "RELEASE_NAME", environment: "TEST", transaction: "transaction", userSegment: "some segment", sampleRate: "0.25", sampled: "true", replayId: nil)
}


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

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

func testSerializationFailsWithInvalidJSONObject() {
let json: [String: Any] = [
"valid object": "hi, i'm a valid object",
Expand All @@ -24,7 +35,7 @@ class SentrySerializationTests: XCTestCase {
}

func testEnvelopeWithData_InvalidEnvelopeHeaderJSON_ReturnsNil() {
let sdkInfoWithInvalidJSON = SentrySdkInfo(name: SentryInvalidJSONString() as String, andVersion: "8.0.0")
let sdkInfoWithInvalidJSON = SentrySdkInfo(name: SentryInvalidJSONString() as String, version: "8.0.0", integrations: [], features: [])
let headerWithInvalidJSON = SentryEnvelopeHeader(id: nil, sdkInfo: sdkInfoWithInvalidJSON, traceContext: nil)

let envelope = SentryEnvelope(header: headerWithInvalidJSON, items: [])
Expand Down Expand Up @@ -125,7 +136,7 @@ class SentrySerializationTests: XCTestCase {
}

func testEnvelopeWithData_WithSdkInfo_ReturnsSDKInfo() throws {
let sdkInfo = SentrySdkInfo(name: "sentry.cocoa", andVersion: "5.0.1")
let sdkInfo = SentrySdkInfo(name: "sentry.cocoa", version: "5.0.1", integrations: [], features: [])
let envelopeHeader = SentryEnvelopeHeader(id: nil, sdkInfo: sdkInfo, traceContext: nil)
let envelope = SentryEnvelope(header: envelopeHeader, singleItem: createItemWithEmptyAttachment())

Expand Down Expand Up @@ -524,7 +535,7 @@ class SentrySerializationTests: XCTestCase {
}

private func assertDefaultSdkInfoSet(deserializedEnvelope: SentryEnvelope) {
let sdkInfo = SentrySdkInfo(name: SentryMeta.sdkName, andVersion: SentryMeta.versionString)
let sdkInfo = SentrySdkInfo(name: SentryMeta.sdkName, version: SentryMeta.versionString, integrations: [], features: [])
XCTAssertEqual(sdkInfo, deserializedEnvelope.header.sdkInfo)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ class SentryNSURLRequestBuilderTests: XCTestCase {
private func givenEnvelopeWithInvalidData() -> SentryEnvelope {
let sdkInfoWithInvalidJSON = SentrySdkInfo(
name: SentryInvalidJSONString() as String,
andVersion: "8.0.0"
version: "8.0.0",
integrations: [],
features: []
)
let headerWithInvalidJSON = SentryEnvelopeHeader(
id: nil,
Expand Down
6 changes: 3 additions & 3 deletions Tests/SentryTests/Protocol/SentryEnvelopeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ class SentryEnvelopeTests: XCTestCase {
clearTestState()
}

private let defaultSdkInfo = SentrySdkInfo(name: SentryMeta.sdkName, andVersion: SentryMeta.versionString)
private let defaultSdkInfo = SentrySdkInfo(name: SentryMeta.sdkName, version: SentryMeta.versionString, integrations: [], features: [])

func testSentryEnvelopeFromEvent() throws {
let event = Event()

Expand Down Expand Up @@ -147,7 +147,7 @@ class SentryEnvelopeTests: XCTestCase {

func testInitSentryEnvelopeHeader_SetIdAndSdkInfo() {
let eventId = SentryId()
let sdkInfo = SentrySdkInfo(name: "sdk", andVersion: "1.2.3-alpha.0")
let sdkInfo = SentrySdkInfo(name: "sdk", version: "1.2.3-alpha.0", integrations: [], features: [])

let envelopeHeader = SentryEnvelopeHeader(id: eventId, sdkInfo: sdkInfo, traceContext: nil)
XCTAssertEqual(eventId, envelopeHeader.eventId)
Expand Down
12 changes: 12 additions & 0 deletions Tests/SentryTests/Protocol/SentrySdkInfo+Equality.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ - (BOOL)isEqual:(id _Nullable)object
return NO;
}

if (![[NSSet setWithArray:self.integrations]
isEqualToSet:[NSSet setWithArray:otherSdkInfo.integrations]]) {
return NO;
}

if (![[NSSet setWithArray:self.features]
isEqualToSet:[NSSet setWithArray:otherSdkInfo.features]]) {
return NO;
}

return YES;
}

Expand All @@ -28,6 +38,8 @@ - (NSUInteger)hash

hash = hash * 23 + [self.name hash];
hash = hash * 23 + [self.version hash];
hash = hash * 23 + [self.integrations hash];
hash = hash * 23 + [self.features hash];

return hash;
}
Expand Down
Loading

0 comments on commit 716a5b0

Please sign in to comment.