Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,4 @@ analyzer

# Output folder for Sentry local builds
XCFrameworkBuildPath/
*.xcresult
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Unreleased

### Fixes

- Change default attributes of Logs to only include user attributes when `options.sendDefaultPii = true` (#7055)
- Rename log attribute `sentry.trace.parent_span_id` to `span_id` (#7055)

## 9.1.0

> [!Warning]
Expand Down
2 changes: 2 additions & 0 deletions Sources/Swift/Tools/Batcher/Batcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ protocol BatcherProtocol<Item, Scope>: AnyObject {

final class Batcher<Buffer: BatchBuffer<Item>, Item: BatcherItem, Scope: BatcherScope>: BatcherProtocol {
struct Config: BatcherConfig {
let sendDefaultPii: Bool

let flushTimeout: TimeInterval
let maxItemCount: Int
let maxBufferSizeBytes: Int
Expand Down
2 changes: 2 additions & 0 deletions Sources/Swift/Tools/Batcher/BatcherConfig.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
protocol BatcherConfig<Item> {
associatedtype Item

var sendDefaultPii: Bool { get }

var flushTimeout: TimeInterval { get }
var maxItemCount: Int { get }
var maxBufferSizeBytes: Int { get }
Expand Down
5 changes: 4 additions & 1 deletion Sources/Swift/Tools/Batcher/BatcherScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ extension BatcherScope {
attributes["sentry.release"] = .init(string: releaseName)
}
if let span = self.span {
attributes["sentry.trace.parent_span_id"] = .init(string: span.spanId.sentrySpanIdString)
attributes["span_id"] = .init(string: span.spanId.sentrySpanIdString)
}
}

Expand Down Expand Up @@ -72,6 +72,9 @@ extension BatcherScope {
}

private func addUserAttributes(to attributes: inout [String: SentryAttribute], config: any BatcherConfig) {
guard config.sendDefaultPii else {
return
}
if let userId = userObject?.userId {
attributes["user.id"] = .init(string: userId)
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Swift/Tools/SentryLogBatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import Foundation
) {
self.batcher = Batcher(
config: .init(
sendDefaultPii: options.sendDefaultPii,
flushTimeout: flushTimeout,
maxItemCount: maxLogCount,
maxBufferSizeBytes: maxBufferSizeBytes,
Expand Down
8 changes: 6 additions & 2 deletions Tests/SentryTests/Batcher/BatcherScopeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ final class BatcherScopeTests: XCTestCase {
private struct TestConfig: BatcherConfig {
typealias Item = TestItem

let sendDefaultPii: Bool

let flushTimeout: TimeInterval
let maxItemCount: Int
let maxBufferSizeBytes: Int
Expand All @@ -47,6 +49,7 @@ final class BatcherScopeTests: XCTestCase {
var userObject: User?
var contextStore: [String: [String: Any]] = [:]
var attributes: [String: Any] = [:]
var sendDefaultPii = true

func getContextForKey(_ key: String) -> [String: Any]? {
return contextStore[key]
Expand Down Expand Up @@ -145,7 +148,7 @@ final class BatcherScopeTests: XCTestCase {
scope.applyToItem(&item, config: config, metadata: metadata)

// -- Assert --
XCTAssertEqual(item.attributes["sentry.trace.parent_span_id"]?.value as? String, span.spanId.sentrySpanIdString)
XCTAssertEqual(item.attributes["span_id"]?.value as? String, span.spanId.sentrySpanIdString)
}

func testApplyToItem_withoutSpan_shouldNotAddParentSpanId() {
Expand Down Expand Up @@ -654,7 +657,7 @@ final class BatcherScopeTests: XCTestCase {
XCTAssertEqual(item.attributes["sentry.sdk.version"]?.value as? String, SentryMeta.versionString)
XCTAssertEqual(item.attributes["sentry.environment"]?.value as? String, "production")
XCTAssertEqual(item.attributes["sentry.release"]?.value as? String, "1.0.0")
XCTAssertEqual(item.attributes["sentry.trace.parent_span_id"]?.value as? String, span.spanId.sentrySpanIdString)
XCTAssertEqual(item.attributes["span_id"]?.value as? String, span.spanId.sentrySpanIdString)

// OS attributes
XCTAssertEqual(item.attributes["os.name"]?.value as? String, "iOS")
Expand Down Expand Up @@ -712,6 +715,7 @@ final class BatcherScopeTests: XCTestCase {

private func createTestConfig() -> TestConfig {
return TestConfig(
sendDefaultPii: true,
flushTimeout: 0.1,
maxItemCount: 10,
maxBufferSizeBytes: 8_000,
Expand Down
4 changes: 3 additions & 1 deletion Tests/SentryTests/Batcher/BatcherTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ private struct TestScope: BatcherScope {
var userObject: User?
var contextStore: [String: [String: Any]] = [:]
var attributes: [String: Any] = [:]

init(propagationContextTraceIdString: String = SentryId().sentryIdString) {
self.propagationContextTraceIdString = propagationContextTraceIdString
}
Expand Down Expand Up @@ -89,12 +89,14 @@ final class BatcherTests: XCTestCase {
}

private func getSut(
sendDefaultPii: Bool = false,
flushTimeout: TimeInterval = 0.1,
maxItemCount: Int = 10,
maxBufferSizeBytes: Int = 8_000,
beforeSendItem: ((TestItem) -> TestItem?)? = nil
) -> Batcher<MockBuffer, TestItem, TestScope> {
var config = Batcher<MockBuffer, TestItem, TestScope>.Config(
sendDefaultPii: sendDefaultPii,
flushTimeout: flushTimeout,
maxItemCount: maxItemCount,
maxBufferSizeBytes: maxBufferSizeBytes,
Expand Down
51 changes: 43 additions & 8 deletions Tests/SentryTests/SentryLogBatcherTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ final class SentryLogBatcherTests: XCTestCase {
XCTAssertEqual(attributes["sentry.sdk.version"]?.value as? String, SentryMeta.versionString)
XCTAssertEqual(attributes["sentry.environment"]?.value as? String, "test-environment")
XCTAssertEqual(attributes["sentry.release"]?.value as? String, "1.0.0")
XCTAssertEqual(attributes["sentry.trace.parent_span_id"]?.value as? String, span.spanId.sentrySpanIdString)
XCTAssertEqual(attributes["span_id"]?.value as? String, span.spanId.sentrySpanIdString)
}

func testAddLog_DoesNotAddNilDefaultAttributes() throws {
Expand All @@ -344,7 +344,7 @@ final class SentryLogBatcherTests: XCTestCase {
let attributes = capturedLog.attributes

XCTAssertNil(attributes["sentry.release"])
XCTAssertNil(attributes["sentry.trace.parent_span_id"])
XCTAssertNil(attributes["span_id"])
XCTAssertEqual(attributes["sentry.sdk.name"]?.value as? String, SentryMeta.sdkName)
XCTAssertEqual(attributes["sentry.sdk.version"]?.value as? String, SentryMeta.versionString)
XCTAssertNotNil(attributes["sentry.environment"])
Expand All @@ -368,35 +368,70 @@ final class SentryLogBatcherTests: XCTestCase {
XCTAssertEqual(capturedLog.traceId, expectedTraceId)
}

func testAddLog_AddsUserAttributes() throws {
func testAddLog_whenSendDefaultPiiTrue_shouldAddUserAttributes() throws {
// -- Arrange --
options.sendDefaultPii = true

let user = User()
user.userId = "123"
user.email = "test@test.com"
user.name = "test-name"
scope.setUser(user)

let sut = getSut()
let log = createTestLog(body: "Test log message with user")

// -- Act --
sut.addLog(log, scope: scope)
sut.captureLogs()

// -- Assert --
let capturedLogs = testDelegate.getCapturedLogs()
let capturedLog = try XCTUnwrap(capturedLogs.first)
let attributes = capturedLog.attributes

XCTAssertEqual(attributes["user.id"]?.value as? String, "123")
XCTAssertEqual(attributes["user.name"]?.value as? String, "test-name")
XCTAssertEqual(attributes["user.email"]?.value as? String, "test@test.com")
}

func testAddLog_DoesNotAddNilUserAttributes() throws {

func testAddLog_whenSendDefaultPiiFalse_shouldNotAddUserAttributes() throws {
// -- Arrange --
let installationId = SentryInstallation.id(withCacheDirectoryPath: options.cacheDirectoryPath)
options.sendDefaultPii = false

let user = User()
user.userId = "123"
user.email = "test@test.com"
user.name = "test-name"
scope.setUser(user)

let sut = getSut()
let log = createTestLog(body: "Test log message with user")

// -- Act --
sut.addLog(log, scope: scope)
sut.captureLogs()

// -- Assert --
let capturedLogs = testDelegate.getCapturedLogs()
let capturedLog = try XCTUnwrap(capturedLogs.first)
let attributes = capturedLog.attributes

// The installation id is used as a fallback for the user.id
XCTAssertEqual(attributes["user.id"]?.value as? String, installationId)
XCTAssertNil(attributes["user.name"])
XCTAssertNil(attributes["user.email"])
}

func testAddLog_whenSendDefaultPiiTrue_shouldNotAddNilUserAttributes() throws {
// -- Arrange --
options.sendDefaultPii = true

let user = User()
user.userId = "123"
scope.setUser(user)

let sut = getSut()
let log = createTestLog(body: "Test log message with partial user")

Expand Down
2 changes: 1 addition & 1 deletion Tests/SentryTests/SentryScopeSwiftTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ class SentryScopeSwiftTests: XCTestCase {
XCTAssertEqual(try XCTUnwrap(scope.serialize() as? [String: AnyHashable]), snapshot)
XCTAssertNotEqual(try XCTUnwrap(scope.serialize() as? [String: AnyHashable]), try XCTUnwrap(cloned.serialize() as? [String: AnyHashable]))
}

func testApplyToEvent() {
let actual = fixture.scope.applyTo(event: fixture.event, maxBreadcrumbs: 10)
let actualContext = actual?.context as? [String: [String: String]]
Expand Down
Loading