Skip to content

Commit bccd232

Browse files
zhu-xiaoweixiaoweii
andauthored
feat: add error code and clickstream error event (#31)
Co-authored-by: xiaoweii <xiaoweii@amazom.com>
1 parent 9e33285 commit bccd232

File tree

10 files changed

+186
-95
lines changed

10 files changed

+186
-95
lines changed

Sources/Clickstream/AWSClickstreamPlugin+ClientBehavior.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,20 @@ extension AWSClickstreamPlugin {
3838
log.warn("Cannot record events. Clickstream is disabled")
3939
return
4040
}
41-
let clickstreamEvent = analyticsClient.createEvent(withEventType: event.name)
42-
if let attributes = event.attribute {
43-
clickstreamEvent.addAttribute(attributes)
44-
}
4541

46-
Task {
47-
do {
48-
try await analyticsClient.record(clickstreamEvent)
49-
} catch {
50-
log.error("Record event error:\(error)")
42+
let isValidEventName = analyticsClient.checkEventName(event.name)
43+
if isValidEventName {
44+
let clickstreamEvent = analyticsClient.createEvent(withEventType: event.name)
45+
if let attributes = event.attribute {
46+
clickstreamEvent.addAttribute(attributes)
47+
}
48+
49+
Task {
50+
do {
51+
try await analyticsClient.record(clickstreamEvent)
52+
} catch {
53+
log.error("Record event error:\(error)")
54+
}
5155
}
5256
}
5357
}

Sources/Clickstream/Dependency/Clickstream/Analytics/AnalyticsClient.swift

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ protocol AnalyticsClientBehaviour {
1515
func updateUserId(_ id: String?)
1616
func updateUserAttributes()
1717

18+
func checkEventName(_ eventName: String) -> Bool
1819
func createEvent(withEventType eventType: String) -> ClickstreamEvent
1920
func record(_ event: ClickstreamEvent) async throws
2021
func submitEvents(isBackgroundMode: Bool)
@@ -43,17 +44,17 @@ class AnalyticsClient: AnalyticsClientBehaviour {
4344

4445
func addGlobalAttribute(_ attribute: AttributeValue, forKey key: String) {
4546
let eventError = Event.checkAttribute(currentNumber: globalAttributes.count, key: key, value: attribute)
46-
if eventError != nil {
47-
globalAttributes[eventError!.errorType] = eventError!.errorMessage
47+
if eventError.errorCode > 0 {
48+
recordEventError(eventError)
4849
} else {
4950
globalAttributes[key] = attribute
5051
}
5152
}
5253

5354
func addUserAttribute(_ attribute: AttributeValue, forKey key: String) {
5455
let eventError = Event.checkUserAttribute(currentNumber: userAttributes.count, key: key, value: attribute)
55-
if eventError != nil {
56-
globalAttributes[eventError!.errorType] = eventError!.errorMessage
56+
if eventError.errorCode > 0 {
57+
recordEventError(eventError)
5758
} else {
5859
var userAttribute = JsonObject()
5960
if let attributeValue = attribute as? Double {
@@ -102,9 +103,6 @@ class AnalyticsClient: AnalyticsClientBehaviour {
102103
// MARK: - Event recording
103104

104105
func createEvent(withEventType eventType: String) -> ClickstreamEvent {
105-
let (isValid, errorType) = Event.isValidEventType(eventType: eventType)
106-
precondition(isValid, errorType)
107-
108106
let event = ClickstreamEvent(eventType: eventType,
109107
appId: clickstream.configuration.appId,
110108
uniqueId: clickstream.userUniqueId,
@@ -114,6 +112,15 @@ class AnalyticsClient: AnalyticsClientBehaviour {
114112
return event
115113
}
116114

115+
func checkEventName(_ eventName: String) -> Bool {
116+
let eventError = Event.checkEventType(eventType: eventName)
117+
if eventError.errorCode > 0 {
118+
recordEventError(eventError)
119+
return false
120+
}
121+
return true
122+
}
123+
117124
func record(_ event: ClickstreamEvent) async throws {
118125
for (key, attribute) in globalAttributes {
119126
event.addGlobalAttribute(attribute, forKey: key)
@@ -124,7 +131,22 @@ class AnalyticsClient: AnalyticsClientBehaviour {
124131
try eventRecorder.save(event)
125132
}
126133

134+
func recordEventError(_ eventError: Event.EventError) {
135+
Task {
136+
do {
137+
let event = createEvent(withEventType: Event.PresetEvent.CLICKSTREAM_ERROR)
138+
event.addAttribute(eventError.errorCode, forKey: Event.ReservedAttribute.ERROR_CODE)
139+
event.addAttribute(eventError.errorMessage, forKey: Event.ReservedAttribute.ERROR_MESSAGE)
140+
try await record(event)
141+
} catch {
142+
log.error("Failed to record event with error:\(error)")
143+
}
144+
}
145+
}
146+
127147
func submitEvents(isBackgroundMode: Bool = false) {
128148
eventRecorder.submitEvents(isBackgroundMode: isBackgroundMode)
129149
}
130150
}
151+
152+
extension AnalyticsClient: ClickstreamLogger {}

Sources/Clickstream/Dependency/Clickstream/AutoRecord/AutoRecordEventClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class AutoRecordEventClient {
203203
do {
204204
try await clickstream.analyticsClient.record(event)
205205
} catch {
206-
log.error("Record event error:\(error)")
206+
log.error("Failed to record event with error:\(error)")
207207
}
208208
}
209209
}

Sources/Clickstream/Dependency/Clickstream/Event/ClickstreamEvent.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class ClickstreamEvent: AnalyticsPropertiesModel, Hashable {
4545

4646
func addAttribute(_ attribute: AttributeValue, forKey key: String) {
4747
let eventError = Event.checkAttribute(currentNumber: attributes.count, key: key, value: attribute)
48-
if eventError != nil, key != Event.ReservedAttribute.EXCEPTION_STACK {
49-
attributes[eventError!.errorType] = eventError!.errorMessage
48+
if eventError.errorCode > 0, key != Event.ReservedAttribute.EXCEPTION_STACK {
49+
attributes[Event.ReservedAttribute.ERROR_CODE] = eventError.errorCode
50+
attributes[Event.ReservedAttribute.ERROR_MESSAGE] = eventError.errorMessage
5051
} else {
5152
attributes[key] = attribute
5253
}

Sources/Clickstream/Dependency/Clickstream/Event/Event.swift

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ enum Event {
1515
/// - key: attribute key
1616
/// - value: attribute value
1717
/// - Returns: the ErrorType
18-
static func checkAttribute(currentNumber: Int, key: String, value: AttributeValue) -> EventError? {
18+
static func checkAttribute(currentNumber: Int, key: String, value: AttributeValue) -> EventError {
1919
if currentNumber >= Limit.MAX_NUM_OF_ATTRIBUTES {
2020
let errorMsg = """
2121
reached the max number of attributes limit (\(Limit.MAX_NUM_OF_ATTRIBUTES)).\
2222
and the attribute: \(key) will not be recorded
2323
"""
2424
log.error(errorMsg)
2525
let errorString = "attribute name: \(key)"
26-
return EventError(errorType: ErrorType.ATTRIBUTE_SIZE_EXCEED,
26+
return EventError(errorCode: ErrorCode.ATTRIBUTE_SIZE_EXCEED,
2727
errorMessage: "\(errorString.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
2828
}
2929
let nameLength = key.utf8.count
@@ -34,7 +34,7 @@ enum Event {
3434
"""
3535
log.error(errorMsg)
3636
let errorString = "attribute name length is:(\(nameLength)) name is: \(key)"
37-
return EventError(errorType: ErrorType.ATTRIBUTE_NAME_LENGTH_EXCEED,
37+
return EventError(errorCode: ErrorCode.ATTRIBUTE_NAME_LENGTH_EXCEED,
3838
errorMessage: "\(errorString.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
3939
}
4040
if !isValidName(name: key) {
@@ -44,7 +44,7 @@ enum Event {
4444
so the attribute will not be recorded
4545
"""
4646
log.error(errorMsg)
47-
return EventError(errorType: ErrorType.ATTRIBUTE_NAME_INVALID,
47+
return EventError(errorCode: ErrorCode.ATTRIBUTE_NAME_INVALID,
4848
errorMessage: "\(key.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
4949
}
5050
if let value = value as? String {
@@ -57,11 +57,11 @@ enum Event {
5757
"""
5858
log.error(errorMsg)
5959
let errrorString = "attribute name: \(key), attribute value: \(value)"
60-
return EventError(errorType: ErrorType.ATTRIBUTE_VALUE_LENGTH_EXCEED,
60+
return EventError(errorCode: ErrorCode.ATTRIBUTE_VALUE_LENGTH_EXCEED,
6161
errorMessage: "\(errrorString.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
6262
}
6363
}
64-
return nil
64+
return EventError(errorCode: ErrorCode.NO_ERROR, errorMessage: "")
6565
}
6666

6767
/// Check the user attribute error.
@@ -70,15 +70,15 @@ enum Event {
7070
/// - key: attribute key
7171
/// - value: attribute value
7272
/// - Returns: the ErrorType
73-
static func checkUserAttribute(currentNumber: Int, key: String, value: AttributeValue) -> EventError? {
73+
static func checkUserAttribute(currentNumber: Int, key: String, value: AttributeValue) -> EventError {
7474
if currentNumber >= Limit.MAX_NUM_OF_USER_ATTRIBUTES {
7575
let errorMsg = """
7676
reached the max number of user attributes limit (\(Limit.MAX_NUM_OF_USER_ATTRIBUTES)).\
7777
and the user attribute: \(key) will not be recorded
7878
"""
7979
log.error(errorMsg)
8080
let errorString = "attribute name: \(key)"
81-
return EventError(errorType: ErrorType.ATTRIBUTE_SIZE_EXCEED,
81+
return EventError(errorCode: ErrorCode.USER_ATTRIBUTE_SIZE_EXCEED,
8282
errorMessage: "\(errorString.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))...")
8383
}
8484
let nameLength = key.utf8.count
@@ -90,7 +90,7 @@ enum Event {
9090
"""
9191
log.error(errorMsg)
9292
let errorString = "user attribute name length is:(\(nameLength)) name is: \(key)"
93-
return EventError(errorType: ErrorType.ATTRIBUTE_NAME_LENGTH_EXCEED,
93+
return EventError(errorCode: ErrorCode.USER_ATTRIBUTE_NAME_LENGTH_EXCEED,
9494
errorMessage: "\(errorString.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
9595
}
9696
if !isValidName(name: key) {
@@ -100,7 +100,7 @@ enum Event {
100100
so the attribute will not be recorded
101101
"""
102102
log.error(errorMsg)
103-
return EventError(errorType: ErrorType.ATTRIBUTE_NAME_INVALID,
103+
return EventError(errorCode: ErrorCode.USER_ATTRIBUTE_NAME_INVALID,
104104
errorMessage: "\(key.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
105105
}
106106
if let value = value as? String {
@@ -113,31 +113,33 @@ enum Event {
113113
"""
114114
log.error(errorMsg)
115115
let errrorString = "attribute name: \(key), attribute value: \(value)"
116-
return EventError(errorType: ErrorType.ATTRIBUTE_VALUE_LENGTH_EXCEED,
116+
return EventError(errorCode: ErrorCode.USER_ATTRIBUTE_VALUE_LENGTH_EXCEED,
117117
errorMessage: "\(errrorString.prefix(Limit.MAX_LENGTH_OF_ERROR_VALUE))")
118118
}
119119
}
120-
return nil
120+
return EventError(errorCode: ErrorCode.NO_ERROR, errorMessage: "")
121121
}
122122

123123
/// Check the event name whether valide
124124
/// - Parameter eventType: the event name
125-
/// - Returns: the eventType is valide and the error type
126-
static func isValidEventType(eventType: String) -> (Bool, String) {
125+
/// - Returns: the EventError object
126+
static func checkEventType(eventType: String) -> EventError {
127127
if eventType.utf8.count > Event.Limit.MAX_EVENT_TYPE_LENGTH {
128128
let errorMsg = """
129129
Event name is too long, the max event type length is \
130130
\(Limit.MAX_EVENT_TYPE_LENGTH) characters. event name: \(eventType)
131131
"""
132-
return (false, errorMsg)
132+
log.error(errorMsg)
133+
return EventError(errorCode: ErrorCode.EVENT_NAME_LENGTH_EXCEED, errorMessage: errorMsg)
133134
} else if !isValidName(name: eventType) {
134135
let errorMsg = """
135136
Event name can only contains uppercase and lowercase letters, underscores, number,\
136137
and is not start with a number. event name: \(eventType)
137138
"""
138-
return (false, errorMsg)
139+
log.error(errorMsg)
140+
return EventError(errorCode: ErrorCode.EVENT_NAME_INVALID, errorMessage: errorMsg)
139141
}
140-
return (true, "")
142+
return EventError(errorCode: ErrorCode.NO_ERROR, errorMessage: "")
141143
}
142144

143145
/// Verify the string whether only contains number, uppercase and lowercase letters,
@@ -173,6 +175,8 @@ enum Event {
173175
static let EXCEPTION_NAME = "_exception_name"
174176
static let EXCEPTION_REASON = "_exception_reason"
175177
static let EXCEPTION_STACK = "_excepiton_stack"
178+
static let ERROR_CODE = "_error_code"
179+
static let ERROR_MESSAGE = "_error_message"
176180
}
177181

178182
enum User {
@@ -217,20 +221,28 @@ enum Event {
217221
static let APP_START = "_app_start"
218222
static let APP_END = "_app_end"
219223
static let APP_EXCEPTION = "_app_exception"
224+
static let CLICKSTREAM_ERROR = "_clickstream_error"
220225
}
221226

222-
enum ErrorType {
223-
static let ATTRIBUTE_NAME_INVALID = "_error_name_invalid"
224-
static let ATTRIBUTE_NAME_LENGTH_EXCEED = "_error_name_length_exceed"
225-
static let ATTRIBUTE_VALUE_LENGTH_EXCEED = "_error_value_length_exceed"
226-
static let ATTRIBUTE_SIZE_EXCEED = "_error_attribute_size_exceed"
227+
enum ErrorCode {
228+
static let NO_ERROR = 0
229+
static let EVENT_NAME_INVALID = 1_001
230+
static let EVENT_NAME_LENGTH_EXCEED = 1_002
231+
static let ATTRIBUTE_NAME_LENGTH_EXCEED = 2_001
232+
static let ATTRIBUTE_NAME_INVALID = 2_002
233+
static let ATTRIBUTE_VALUE_LENGTH_EXCEED = 2_003
234+
static let ATTRIBUTE_SIZE_EXCEED = 2_004
235+
static let USER_ATTRIBUTE_SIZE_EXCEED = 3_001
236+
static let USER_ATTRIBUTE_NAME_LENGTH_EXCEED = 3_002
237+
static let USER_ATTRIBUTE_NAME_INVALID = 3_003
238+
static let USER_ATTRIBUTE_VALUE_LENGTH_EXCEED = 3_004
227239
}
228240

229241
class EventError {
230-
let errorType: String
242+
let errorCode: Int
231243
let errorMessage: String
232-
init(errorType: String, errorMessage: String) {
233-
self.errorType = errorType
244+
init(errorCode: Int, errorMessage: String) {
245+
self.errorCode = errorCode
234246
self.errorMessage = errorMessage
235247
}
236248
}

0 commit comments

Comments
 (0)