Skip to content

Commit be4a5a3

Browse files
sumeruchatclaude
andauthored
SDK-466 Cache DateFormatter and skip formatting for filtered log levels (#1064)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e901170 commit be4a5a3

4 files changed

Lines changed: 52 additions & 5 deletions

File tree

swift-sdk/Internal/Utilities/IterableLogUtil.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ struct IterableLogUtil {
1616
static var sharedInstance: IterableLogUtil?
1717

1818
func log(level: LogLevel, message: String?, file: String, method: String, line: Int) {
19+
guard logDelegate.shouldLog?(level: level) ?? true else { return }
20+
1921
let logMessage = IterableLogUtil.formatLogMessage(message: message, file: file, method: method, line: line, date: dateProvider.currentDate)
2022
logDelegate.log(level: level, message: logMessage)
2123
}
@@ -49,9 +51,13 @@ struct IterableLogUtil {
4951
}
5052
}
5153

52-
private static func formatDate(date: Date) -> String {
54+
private static let dateFormatter: DateFormatter = {
5355
let formatter = DateFormatter()
5456
formatter.dateFormat = "HH:mm:ss.SSSS"
55-
return formatter.string(from: date)
57+
return formatter
58+
}()
59+
60+
private static func formatDate(date: Date) -> String {
61+
dateFormatter.string(from: date)
5662
}
5763
}

swift-sdk/SDK/IterableConfig.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ public struct IterableAPIMobileFrameworkInfo: Codable {
8585
/// - message: The message to log. The message will include file, method and line of the call.
8686
@objc(log:message:)
8787
func log(level: LogLevel, message: String)
88+
89+
/// Return whether a message at the given level should be formatted and logged.
90+
/// If this optional method is not implemented, all levels will be formatted and logged.
91+
/// - Parameter level: The logging level
92+
@objc(shouldLog:)
93+
optional func shouldLog(level: LogLevel) -> Bool
8894
}
8995

9096
/// The delegate for getting the authentication token

swift-sdk/SDK/IterableLogging.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import os
1313
self.minLogLevel = minLogLevel
1414
}
1515

16+
public func shouldLog(level: LogLevel) -> Bool {
17+
level.rawValue >= minLogLevel.rawValue
18+
}
19+
1620
public func log(level: LogLevel = .info, message: String) {
17-
guard level.rawValue >= minLogLevel.rawValue else {
18-
return
19-
}
21+
guard shouldLog(level: level) else { return }
2022

2123
let markedMessage = IterableLogUtil.markedMessage(level: level, message: message)
2224
os_log("%@", log: OSLog.default, type: OSLogType.error, markedMessage)
@@ -33,6 +35,10 @@ import os
3335

3436
/// Will log nothing
3537
@objc public class NoneLogDelegate: NSObject, IterableLogDelegate {
38+
public func shouldLog(level _: LogLevel) -> Bool {
39+
false
40+
}
41+
3642
public func log(level _: LogLevel = .info, message _: String) {
3743
// Do nothing
3844
}

tests/unit-tests/LoggingTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ import XCTest
77
@testable import IterableSDK
88

99
class LoggingTests: XCTestCase {
10+
private class SpyDateProvider: DateProviderProtocol {
11+
private(set) var currentDateAccessCount = 0
12+
13+
var currentDate: Date {
14+
currentDateAccessCount += 1
15+
return Date(timeIntervalSince1970: 0)
16+
}
17+
}
18+
1019
func testLogging() {
1120
let expectation1 = expectation(description: "debug message")
1221
let expectation2 = expectation(description: "info message")
@@ -48,4 +57,24 @@ class LoggingTests: XCTestCase {
4857

4958
wait(for: [expectation1, expectation2, expectation3], timeout: 10.0)
5059
}
60+
61+
func testDefaultLogDelegateDoesNotFormatFilteredLogLevel() {
62+
let dateProvider = SpyDateProvider()
63+
let logUtil = IterableLogUtil(dateProvider: dateProvider, logDelegate: DefaultLogDelegate(minLogLevel: .error))
64+
65+
logUtil.log(level: .info, message: "filtered", file: #file, method: #function, line: #line)
66+
XCTAssertEqual(dateProvider.currentDateAccessCount, 0)
67+
68+
logUtil.log(level: .error, message: "logged", file: #file, method: #function, line: #line)
69+
XCTAssertEqual(dateProvider.currentDateAccessCount, 1)
70+
}
71+
72+
func testNoneLogDelegateDoesNotFormatMessages() {
73+
let dateProvider = SpyDateProvider()
74+
let logUtil = IterableLogUtil(dateProvider: dateProvider, logDelegate: NoneLogDelegate())
75+
76+
logUtil.log(level: .error, message: "filtered", file: #file, method: #function, line: #line)
77+
78+
XCTAssertEqual(dateProvider.currentDateAccessCount, 0)
79+
}
5180
}

0 commit comments

Comments
 (0)