이벤트 라이브러리 - Swift SDK
이 페이지의 내용
개요
이벤트 라이브러리를 사용하면 동기화가 활성화된 모바일 애플리케이션을 사용하는 동안 사용자의 활동을 추적할 수 있습니다. 이벤트 라이브러리는 읽기 및 쓰기 트랜잭션(write transaction)을 기록할 수 있습니다. 또한 개발자는 사용자 지정 이벤트를 구성하여 버튼 누름, UI에 표시되는 데이터 또는 기타 중요한 세부 정보를 기록할 수 있습니다.
이벤트 라이브러리를 사용할 때, 기록하고 싶은 이벤트를 지정할 수 있습니다. 이는 두 개의 영역을 여는 것을 의미합니다:
사용자 영역은 사용자가 클라이언트 애플리케이션에서 읽기와 쓰기를 수행하는 곳입니다.
이벤트 라이브러리가 범위 지정 이벤트와 사용자 지정 이벤트를 기록하는 이벤트 영역
두 영역의 데이터가 App Services App에 동기화됩니다. 클라이언트 사용자는 이벤트 영역이나 해당 데이터와 직접 상호 작용하지 않습니다. 이벤트 영역 동기화 사용자는 사용자 영역과 다를 수도 있습니다.
이벤트 라이브러리는 많은 양의 데이터를 생성하기 때문입니다.
클라이언트 장치는 데이터를 저장할 수 있는 충분한 용량이 있어야 합니다.
Realm Mobile Sync의 이벤트 영역 사용량은 사용자 영역의 읽기 및 쓰기보다 많을 것으로 예상됩니다.
앱의 지원 Atlas cluster에는 이벤트 라이브러리에서 생성된 데이터를 처리할 수 있는 충분한 저장 용량이 있어야 합니다.
시작하기 전에
The Event Library stores data in an AuditEvent
collection in your linked Atlas data source. Enable Development Mode in your App Services App to let Atlas create the collection and infer the schema from the uploaded events
중요
파티션 기반 동기화 필요
이벤트 라이브러리는 Flexible Sync를 사용한 AuditEvents
기록을 지원하지 않습니다. 이 기능을 사용하려면 AuditEvent
데이터를 기록하기 위해 파티션 기반 동기화 App Services App 이 필요합니다.
이벤트 기록 활성화
이벤트 기록을 활성화하려면 Realm.Configuration에서 Event.Configuration 속성을 설정합니다 .
다음 두 가지 방법 중 하나로 EventConfiguration
를 초기화할 수 있습니다.
세부 정보를 지정할 필요가 없는 경우 기본값으로 초기화되는 구성을 사용하세요.
이벤트 구성을 사용자 지정하기 위해 추가 매개변수를 전달합니다.
기본 이벤트 구성
특정 매개변수를 지정할 필요가 없는 경우 기본값으로 초기화되는 EventConfiguration
을 사용할 수 있습니다.
var config = user.configuration(partitionValue: "Some partition value") config.eventConfiguration = EventConfiguration()
이벤트 구성에 매개변수 전달
선택적 매개변수를 전달하여 EventConfiguration
을(를) 사용자 지정할 수 있습니다.
metadata
: 각 이벤트에 추가할 메타데이터 필드의 문자열 사전syncUser
: 이벤트 영역 동기화에 사용할 사용자입니다. nil인 경우 기본값은Realm.Configuration
의 사용자입니다.partitionPrefix
: 이벤트 파티션 값에 추가할 문자열 접두사logger
: 이벤트에 사용할 사용자 지정 로거입니다. nil인 경우 기본값은 사용자 영역의 로거입니다.errorHandler
: 이벤트 데이터를 업로드할 때 동기화 오류가 발생하는 경우 호출되는 사용자 지정 오류 핸들러입니다.nil
인 경우 SDK는 이벤트를 기록한 다음abort()
을 호출합니다. 프로덕션 앱은 오류로 인한 중단이 바람직한 동작이 아닌 한 항상errorHandler
이벤트를 정의해야 합니다.
let eventSyncUser = try await app.login(credentials: Credentials.anonymous) var config = user.configuration(partitionValue: "Some partition value") config.eventConfiguration = EventConfiguration(metadata: ["username": "Jason Bourne"], syncUser: eventSyncUser, partitionPrefix: "event-")
이벤트 메타데이터 업데이트
이벤트 기록을 시작한 후에도 메타데이터를 업데이트할 수 있습니다. updateMetadata()
함수를 사용하여 이벤트 구성에 제공된 메타데이터를 새 값으로 바꿉니다.
이벤트 범위가 활성화된 상태에서 메타데이터를 업데이트하는 경우, 이벤트 라이브러리는 다음 이벤트 범위가 시작될 때까지 새 메타데이터를 사용하지 않습니다.
var config = user.configuration(partitionValue: "Some partition value") config.eventConfiguration = EventConfiguration(metadata: ["username": "Jason Bourne"], syncUser: user, partitionPrefix: "event-") let realm = try! Realm(configuration: config) let events = realm.events! let updateUsernameScope = events.beginScope(activity: "Update username") // Call some function that updates the user's username updateUsername() updateUsernameScope.commit() // Update the metadata you supplied with the initial EventConfiguration events.updateMetadata(["username": "John Michael Kane"])
이벤트 기록
이벤트 Realm과 상호 작용
이벤트 구성을 정의한 후에는 Realm 의 새 이벤트 속성을 사용하여 이벤트 기록 기능을 호출할 수 있습니다. 그러면 해당 영역에 연결된 Event
인스턴스가 반환됩니다.
let realm = try! Realm(configuration: config) let events = realm.events!
읽기 또는 쓰기 이벤트 기록
버전 10.36.0에서 변경: 새 스코프 객체인 커밋() 및 취소()에 대한 endscope() 더 이상 사용되지 않습니다.
이벤트 라이브러리는 범위의 컨텍스트 내에서 읽기 및 쓰기 이벤트를 기록합니다. 범위는 이벤트 라이브러리가 영역 활동을 감시하고 기록하는 기간입니다. 다양한 범위를 설정하여 다양한 유형의 이벤트를 기록할 수 있습니다. 예를 들어 "로그인"과 같은 특정 사용자 흐름에 대한 범위, 다양한 화면에 대한 서로 다른 범위, 특정 규정 준수 관련 활동에 대한 서로 다른 범위를 가질 수 있습니다.
주어진 활동 이름으로 새 이벤트 기록을 시작하려면 시작 스코프(활동: "일부 활동") 을 사용합니다. 그러면 나중에 범위를 커밋하거나 취소하는 데 사용할 수 있는 범위 객체가 반환됩니다. 범위를 시작하면 범위 내에서 발생하는 활동이 읽기 또는 쓰기 이벤트로 기록됩니다.
이벤트 읽기: 쿼리를 실행하고 객체를 인스턴스화합니다. 범위가 종료되면 이벤트 영역은 이러한 활동을 읽기 이벤트로 기록합니다.
쓰기 이벤트: 객체 수정. 범위가 종료되면 이벤트 영역은 객체의 초기 상태와 이벤트 범위 중에 변경되는 모든 속성의 새 값을 기록합니다.
beginScope
을(를) 사용하여 이벤트를 기록하면 이벤트 영역이 아직 열려 있지 않은 경우 해당 이벤트 영역이 열립니다. SDK는 백그라운드 스레드에서 이벤트 Realm을 열고 오류 콜백에 오류를 보고합니다.
참고
겹치는 이벤트 범위
둘 이상의 이벤트 범위가 동시에 활성화되는 경우 생성된 이벤트는 모든 활성 범위에서 기록됩니다.
범위에 대한 이벤트 기록을 완료하면 commit()
를 사용하여 범위 내에서 발생한 이벤트를 저장합니다. 기록을 종료하면 이벤트 라이브러리가 이벤트를 로컬 디스크에 저장합니다. 그런 다음 장치가 네트워크에 연결되어 있으면 SDK는 비동기적으로 데이터를 서버로 전송합니다.
// Read event let readEventScope = events.beginScope(activity: "read object") let person = realm.objects(Person.self).first! print("Found this person: \(person.name)") readEventScope.commit() let mutateEventScope = events.beginScope(activity: "mutate object") // Write event try! realm.write { // Change name from "Anthony" to "Tony" person.name = "Tony" } mutateEventScope.commit()
또는 이벤트 범위를 cancel()
할 수 있습니다. 이렇게 하면 이벤트 기록이 중지되고 이벤트가 디스크나 서버에 지속되지 않습니다.
let eventScope = events.beginScope(activity: "read object") let person1 = realm.objects(Person.self).first! print("Found this person: \(person1.name)") eventScope.cancel()
isActive
부울을 사용하여 지정된 범위가 현재 진행 중인지 확인할 수 있습니다. 아직 커밋하거나 취소하지 않은 범위를 시작한 경우 true
를 반환합니다.
let readPersonScope = events.beginScope(activity: "read object") let person2 = realm.objects(Person.self).first! print("Found this person: \(person2.name)") if readPersonScope.isActive { print("The readPersonScope is active") } else { print("The readPersonScope is no longer active") } readPersonScope.cancel()
기록이 끝나면 선택적 완료 블록을 commit()
에 전달할 수 있습니다. SDK는 이벤트 영역 업로드가 완료되었을 때가 아니라 이벤트 데이터가 성공적으로 유지되었을 때 이 차단을 호출합니다.
let mutateScope = events.beginScope(activity: "mutate object with completion") // Write event try! realm.write { // Add a userId person.userId = "tony.stark@starkindustries.com" } mutateScope.commit(completion: { error in if let error = error { print("Error recording write event: \(error.localizedDescription)") return } print("Successfully recorded a write event") })
사용자 지정 이벤트 기록
이벤트 라이브러리를 사용하면 데이터베이스 읽기 및 쓰기와 관련이 없는 버튼 클릭 또는 기타 이벤트를 기록할 수 있습니다. 사용자 지정 이벤트를 기록하려면 recordEvent 를 사용합니다. 이 함수는 다음과 같은 매개변수를 사용합니다.
activity
: 활동 이름입니다. 이는 "user registration"과 같은 임의의 문자열입니다.eventType
: 이벤트 유형입니다. 이는 '누른 제출 버튼'과 같은 임의의 문자열입니다.data
: 이벤트에 대한 선택적 데이터 페이로드입니다.completion
: 선택적 완료 핸들러입니다. 이벤트 라이브러리는 이벤트가 이벤트 영역에 저장되거나 오류가 발생하면 이 완료 차단을 호출합니다. nil 오류는 성공을 나타냅니다.
사용자 지정 이벤트에는 읽기 및 쓰기 이벤트와 같은 범위가 없습니다. 대신 사용자 지정 이벤트를 기록하는 것은 trigger를 실행하는 것과 더 유사합니다.
events.recordEvent(activity: "event", eventType: "custom event")
이벤트 객체 직렬화
JSON 객체 직렬화
이벤트 라이브러리는 각 이벤트 객체를 JSON 객체로 변환합니다. 대부분의 Realm 유형 에는 유사한 JSON 표현이 있습니다. 예를 들어 Realm 문자열 속성은 JSON 문자열이 됩니다.
이벤트 라이브러리는 직접 JSON 유사점이 없는 유형을 다음과 같이 표현합니다.
날짜 | |
데이터 | 이벤트에서 완전히 제외됩니다. |
UUID | RFC-4122로 인코딩됨 string - 호환 . |
ObjectID | ObjectId string 표현으로 인코딩됩니다. |
Decimal128 | 숫자가 아닌 문자열로 인코딩됩니다. JSON 숫자는 공식적으로 무한정 정밀도이지만, 실제로 그렇게 구현되는 경우는 거의 없습니다. |
목록 | 배열로 인코딩됩니다. |
세트 | 배열로 인코딩됩니다. |
사전 | 객체로 인코딩됩니다. |
내장된 객체 | 객체로 인코딩됩니다. |
비포함된 객체 링크는 대상의 프라이머리 키로 인코딩됩니다. 읽기 이벤트에서 링크를 따라가면 전체 객체로 확장됩니다. 링크를 따르지 않으면 이 키가 기본 키로 유지됩니다.
이벤트 직렬화 사용자 지정
이벤트 객체에 대한 JSON 직렬화를 사용자 지정할 수 있습니다. 이벤트 페이로드를 사용자 지정하려면 CustomEventRepresentable 프로토콜을 사용합니다.
객체가 CustomEventRepresentable
을 준수하는 경우 이벤트 라이브러리는 다음을 통해 객체를 직렬화합니다.
접근자 객체 생성
해당 접근자 객체에서
customEventRepresentation
호출원본 객체 대신 결과 직렬화
CustomEventRepresentable
을 준수하려면 객체가 사용자 지정된 직렬화를 정의하는 customEventRepresentation 함수를 구현해야 합니다.
// To customize event serialization, your object must // conform to the `CustomEventRepresentable` protocol. class Person: Object, CustomEventRepresentable { true) var _id: ObjectId (primaryKey: var name: String var employeeId: Int var userId: String? convenience init(name: String, employeeId: Int) { self.init() self.name = name self.employeeId = employeeId } // To conform to `CustomEventRepresentable`, your object // must implement a `customEventRepresentation` func that // defines your customized event serialization func customEventRepresentation() -> String { if employeeId == 0 { return "invalid json" } return "{\"int\": \(employeeId)}" } }
이벤트 Realm 파일 크기
장치가 오랫동안 오프라인 상태인 경우 이벤트 영역이 상당히 커질 수 있습니다.
이를 보완하기 위해 이벤트 라이브러리는 필요에 따라 이벤트 데이터를 여러 파티션으로 자동 분할합니다. 파티션이 최대 크기에 도달하면 이벤트 라이브러리는 이벤트 영역을 닫고 자동으로 새 파티션에 쓰기를 시작합니다.
이벤트 라이브러리는 사용자에게 동기화되지 않은 파티션이 있는지 확인합니다. 일치하는 경우 이벤트 라이브러리는 파일을 열고 데이터를 업로드한 다음 파일을 닫고 삭제합니다. 사용자에게 동기화되지 않은 파티션이 없어질 때까지 이 과정이 반복됩니다.
이벤트 라이브러리 참고
이벤트
이벤트가 저장되는 AuditEvent
컬렉션에는 앱 수신 이벤트에 대한 서버에 정의된 스키마가 있어야 합니다.
스키마에는 다음 필드가 포함되어야 합니다.
ID | _id | ObjectId |
이벤트 유형 | event | 선택적 문자열입니다. 범위 지정 이벤트의 경우 read 또는 write , 사용자 지정 이벤트의 경우 임의의 문자열입니다. |
이벤트 범위 | activity | 선택적 문자열입니다. 이벤트 기록을 시작하기 위해 beginScope() 에 전달된 범위 이름이거나 사용자 지정 이벤트의 경우 임의의 문자열입니다. |
타임스탬프 | timestamp | 이벤트 범위가 종료되고 데이터가 커밋된 기기 현지 시간 또는 이벤트가 서버에 도달한 시간입니다. |
데이터 | data | 이벤트 페이로드입니다. 이는 범위가 지정된 이벤트의 경우 JSON blob이고 사용자 지정 이벤트의 경우 임의 문자열입니다. |
메타 데이터 | metadata key (문자열) | 선택적 메타데이터 사전입니다. 이 사전에 키와 값이 포함된 경우 키는 이벤트 객체의 필드 이름이 되고 모든 이벤트에 대해 값이 해당 필드에 저장됩니다. |
이벤트 페이로드
각 이벤트에는 읽거나 쓰고 있는 객체의 현재 상태를 캡처하는 data
속성에 페이로드가 포함되어 있습니다.
사용자 지정 이벤트의 페이로드는 nil을 포함하여 개발자가 원하는 대로 지정할 수 있습니다.
중요
페이로드는 읽거나 쓰는 객체의 현재 상태를 캡처하기 때문에 매우 많은 양의 데이터를 생성합니다. 그러나 사용자가 보는 정확한 데이터가 서버 측에 절대 존재할 수 없으므로 서버가 아닌 클라이언트에서 이 작업을 수행해야 합니다. 실제로 이는 기기가 오프라인 상태가 될 경우에도 대량의 데이터를 저장할 수 있는 용량을 갖추고 있어야 합니다. 또한, 이벤트 영역에 대한 Realm Mobile Sync 사용량은 사용자 영역에서 사용자가 읽고 쓰는 것보다 훨씬 높을 수 있습니다.
예제
위의 이벤트 기록 예제에서 읽기 및 쓰기 이벤트에 대한 data
페이로드는 다음과 같습니다.
{ "type":"Person", "value": [{ "_id":"62b38b3c10846041166f5deb", "_partition":"", "employeeId":2, "name":"Anthony", "userId":null }] }
{ "Person": { "modifications": [{ "newValue": { "name":"Tony" }, "oldValue":{ "_id":"62b38b3c10846041166f5deb", "_partition":"", "employeeId":2, "name":"Anthony", "userId":null } }] } }