Skip to content

Commit 229d597

Browse files
authored
Fix encoding for Session Events (#4870)
1 parent 188f623 commit 229d597

File tree

9 files changed

+162
-55
lines changed

9 files changed

+162
-55
lines changed

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/EventGDTLogger.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.firebase.sessions
1818

19+
import android.util.Log
1920
import com.google.android.datatransport.*
2021
import com.google.android.datatransport.TransportFactory
2122
import com.google.firebase.inject.Provider
@@ -53,11 +54,14 @@ internal class EventGDTLogger(private val transportFactoryProvider: Provider<Tra
5354
}
5455

5556
private fun encode(value: SessionEvent): ByteArray {
56-
return SessionEvents.SESSION_EVENT_ENCODER.encode(value).toByteArray()
57+
val jsonEvent = SessionEvents.SESSION_EVENT_ENCODER.encode(value)
58+
Log.d(TAG, "Encoded Session Start event $jsonEvent")
59+
return jsonEvent.toByteArray()
5760
}
5861

5962
companion object {
60-
// TODO What do we put for the AQS Log Source
63+
private const val TAG = "EventGDTLogger"
64+
6165
private const val AQS_LOG_SOURCE = "FIREBASE_APPQUALITY_SESSION"
6266
}
6367
}

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionCoordinator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ internal class SessionCoordinator(
5050
try {
5151
eventGDTLogger.log(sessionEvent)
5252

53-
Log.i(TAG, "Logged Session Start event: $sessionEvent")
53+
Log.i(TAG, "Logged Session Start event: ${sessionEvent.sessionData.sessionId}")
5454
} catch (e: RuntimeException) {
5555
Log.w(TAG, "Failed to log Session Start event: ", e)
5656
}

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionEvent.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,41 @@ internal data class SessionInfo(
5959
/** What order this Session came in this run of the app. For the first Session this will be 0. */
6060
val sessionIndex: Int,
6161

62+
/** Tracks when the event was initiated */
63+
var eventTimestampUs: Long,
64+
65+
/** Data collection status of the dependent product SDKs. */
66+
var dataCollectionStatus: DataCollectionStatus = DataCollectionStatus(),
67+
6268
/** Identifies a unique device+app installation: go/firebase-installations */
6369
var firebaseInstallationId: String = "",
6470
)
71+
72+
/** Contains the data collection state for all dependent SDKs and sampling info */
73+
internal data class DataCollectionStatus(
74+
val performance: DataCollectionState = DataCollectionState.COLLECTION_ENABLED,
75+
val crashlytics: DataCollectionState = DataCollectionState.COLLECTION_ENABLED,
76+
val sessionSamplingRate: Double = 1.0,
77+
)
78+
79+
/** Enum denoting different data collection states. */
80+
internal enum class DataCollectionState(override val number: Int) : NumberedEnum {
81+
COLLECTION_UNKNOWN(0),
82+
83+
// This product SDK is not present in this version of the app.
84+
COLLECTION_SDK_NOT_INSTALLED(1),
85+
86+
// The product SDK is present and collecting all product-level events.
87+
COLLECTION_ENABLED(2),
88+
89+
// The product SDK is present but data collection for it has been locally
90+
// disabled.
91+
COLLECTION_DISABLED(3),
92+
93+
// The product SDK is present but data collection has been remotely disabled.
94+
COLLECTION_DISABLED_REMOTE(4),
95+
96+
// Indicates that the product SDK is present, but session data is being
97+
// collected, but the product-level events are not being uploaded.
98+
COLLECTION_SAMPLED(5),
99+
}

firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionEvents.kt

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ internal object SessionEvents {
3939
run {
4040
ctx.add(FieldDescriptor.of("event_type"), sessionEvent.eventType)
4141
ctx.add(FieldDescriptor.of("session_data"), sessionEvent.sessionData)
42+
ctx.add(FieldDescriptor.of("application_info"), sessionEvent.applicationInfo)
4243
}
4344
}
4445

@@ -53,6 +54,42 @@ internal object SessionEvents {
5354
FieldDescriptor.of("firebase_installation_id"),
5455
sessionInfo.firebaseInstallationId
5556
)
57+
ctx.add(FieldDescriptor.of("event_timestamp_us"), sessionInfo.eventTimestampUs)
58+
ctx.add(FieldDescriptor.of("data_collection_status"), sessionInfo.dataCollectionStatus)
59+
}
60+
}
61+
62+
it.registerEncoder(DataCollectionStatus::class.java) {
63+
dataCollectionStatus: DataCollectionStatus,
64+
ctx: ObjectEncoderContext ->
65+
run {
66+
ctx.add(FieldDescriptor.of("performance"), dataCollectionStatus.performance)
67+
ctx.add(FieldDescriptor.of("crashlytics"), dataCollectionStatus.crashlytics)
68+
ctx.add(
69+
FieldDescriptor.of("session_sampling_rate"),
70+
dataCollectionStatus.sessionSamplingRate
71+
)
72+
}
73+
}
74+
75+
it.registerEncoder(ApplicationInfo::class.java) {
76+
applicationInfo: ApplicationInfo,
77+
ctx: ObjectEncoderContext ->
78+
run {
79+
ctx.add(FieldDescriptor.of("app_id"), applicationInfo.appId)
80+
ctx.add(FieldDescriptor.of("device_model"), applicationInfo.deviceModel)
81+
ctx.add(FieldDescriptor.of("session_sdk_version"), applicationInfo.sessionSdkVersion)
82+
ctx.add(FieldDescriptor.of("log_environment"), applicationInfo.logEnvironment)
83+
ctx.add(FieldDescriptor.of("android_app_info"), applicationInfo.androidAppInfo)
84+
}
85+
}
86+
87+
it.registerEncoder(AndroidApplicationInfo::class.java) {
88+
androidAppInfo: AndroidApplicationInfo,
89+
ctx: ObjectEncoderContext ->
90+
run {
91+
ctx.add(FieldDescriptor.of("package_name"), androidAppInfo.packageName)
92+
ctx.add(FieldDescriptor.of("version_name"), androidAppInfo.versionName)
5693
}
5794
}
5895
}
@@ -63,14 +100,19 @@ internal object SessionEvents {
63100
*
64101
* Some mutable fields, e.g. firebaseInstallationId, get populated later.
65102
*/
66-
fun startSession(firebaseApp: FirebaseApp, sessionDetails: SessionDetails) =
103+
fun startSession(
104+
firebaseApp: FirebaseApp,
105+
sessionDetails: SessionDetails,
106+
currentTimeUs: Long = System.currentTimeMillis() * 1000
107+
) =
67108
SessionEvent(
68109
eventType = EventType.SESSION_START,
69110
sessionData =
70111
SessionInfo(
71112
sessionDetails.sessionId,
72113
sessionDetails.firstSessionId,
73114
sessionDetails.sessionIndex,
115+
currentTimeUs,
74116
),
75117
applicationInfo = getApplicationInfo(firebaseApp)
76118
)

firebase-sessions/src/test/kotlin/com/google/firebase/sessions/EventGDTLoggerTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class EventGDTLoggerTest {
3838
val sessionEvent =
3939
SessionEvents.startSession(
4040
FakeFirebaseApp.fakeFirebaseApp(),
41-
TestSessionEventData.TEST_SESSION_DETAILS
41+
TestSessionEventData.TEST_SESSION_DETAILS,
42+
TestSessionEventData.TEST_SESSION_TIMESTAMP_US,
4243
)
4344
val fakeTransportFactory = FakeTransportFactory()
4445
val fakeTransportFactoryProvider = FakeProvider(fakeTransportFactory as TransportFactory)

firebase-sessions/src/test/kotlin/com/google/firebase/sessions/SessionCoordinatorTest.kt

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package com.google.firebase.sessions
1919
import androidx.test.ext.junit.runners.AndroidJUnit4
2020
import com.google.common.truth.Truth.assertThat
2121
import com.google.firebase.sessions.testing.FakeEventGDTLogger
22+
import com.google.firebase.sessions.testing.FakeFirebaseApp
2223
import com.google.firebase.sessions.testing.FakeFirebaseInstallations
24+
import com.google.firebase.sessions.testing.TestSessionEventData
2325
import kotlinx.coroutines.ExperimentalCoroutinesApi
2426
import kotlinx.coroutines.test.StandardTestDispatcher
2527
import kotlinx.coroutines.test.runCurrent
@@ -42,22 +44,10 @@ class SessionCoordinatorTest {
4244

4345
// Construct an event with no fid set.
4446
val sessionEvent =
45-
SessionEvent(
46-
eventType = EventType.SESSION_START,
47-
sessionData =
48-
SessionInfo(
49-
sessionId = "id",
50-
firstSessionId = "first",
51-
sessionIndex = 3,
52-
),
53-
applicationInfo =
54-
ApplicationInfo(
55-
appId = "",
56-
deviceModel = "",
57-
sessionSdkVersion = "",
58-
logEnvironment = LogEnvironment.LOG_ENVIRONMENT_PROD,
59-
androidAppInfo = AndroidApplicationInfo(packageName = "", versionName = "")
60-
)
47+
SessionEvents.startSession(
48+
FakeFirebaseApp.fakeFirebaseApp(),
49+
TestSessionEventData.TEST_SESSION_DETAILS,
50+
TestSessionEventData.TEST_SESSION_TIMESTAMP_US,
6151
)
6252

6353
sessionCoordinator.attemptLoggingSessionEvent(sessionEvent)

firebase-sessions/src/test/kotlin/com/google/firebase/sessions/SessionEventEncoderTest.kt

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,61 @@ package com.google.firebase.sessions
1818

1919
import androidx.test.ext.junit.runners.AndroidJUnit4
2020
import com.google.common.truth.Truth.assertThat
21+
import com.google.firebase.FirebaseApp
2122
import com.google.firebase.sessions.SessionEvents.SESSION_EVENT_ENCODER
23+
import com.google.firebase.sessions.testing.FakeFirebaseApp
24+
import com.google.firebase.sessions.testing.TestSessionEventData
25+
import org.junit.After
2226
import org.junit.Test
2327
import org.junit.runner.RunWith
2428

2529
@RunWith(AndroidJUnit4::class)
2630
class SessionEventEncoderTest {
31+
32+
@After
33+
fun cleanUp() {
34+
FirebaseApp.clearInstancesForTest()
35+
}
36+
2737
@Test
2838
fun sessionEvent_encodesToJson() {
2939
val sessionEvent =
30-
SessionEvent(
31-
eventType = EventType.SESSION_START,
32-
sessionData =
33-
SessionInfo(
34-
sessionId = "id",
35-
firstSessionId = "first",
36-
sessionIndex = 9,
37-
firebaseInstallationId = "fid"
38-
),
39-
applicationInfo =
40-
ApplicationInfo(
41-
appId = "",
42-
deviceModel = "",
43-
sessionSdkVersion = "",
44-
logEnvironment = LogEnvironment.LOG_ENVIRONMENT_PROD,
45-
AndroidApplicationInfo(packageName = "", versionName = ""),
46-
)
40+
SessionEvents.startSession(
41+
FakeFirebaseApp.fakeFirebaseApp(),
42+
TestSessionEventData.TEST_SESSION_DETAILS,
43+
TestSessionEventData.TEST_SESSION_TIMESTAMP_US,
4744
)
4845

4946
val json = SESSION_EVENT_ENCODER.encode(sessionEvent)
5047

5148
assertThat(json)
5249
.isEqualTo(
5350
"""
54-
{
55-
"event_type":1,
56-
"session_data":{
57-
"session_id":"id",
58-
"first_session_id":"first",
59-
"session_index":9,
60-
"firebase_installation_id":"fid"
51+
{
52+
"event_type":1,
53+
"session_data":{
54+
"session_id":"a1b2c3",
55+
"first_session_id":"a1a1a1",
56+
"session_index":3,
57+
"firebase_installation_id":"",
58+
"event_timestamp_us":12340000,
59+
"data_collection_status":{
60+
"performance":2,
61+
"crashlytics":2,
62+
"session_sampling_rate":1.0
63+
}
64+
},
65+
"application_info":{
66+
"app_id":"1:12345:android:app",
67+
"device_model":"",
68+
"session_sdk_version":"0.1.0",
69+
"log_environment":3,
70+
"android_app_info":{
71+
"package_name":"com.google.firebase.sessions.test",
72+
"version_name":"1.0.0"
73+
}
74+
}
6175
}
62-
}
6376
"""
6477
.lines()
6578
.joinToString("") { it.trim() }
@@ -76,6 +89,7 @@ class SessionEventEncoderTest {
7689
sessionId = "",
7790
firstSessionId = "",
7891
sessionIndex = 0,
92+
eventTimestampUs = 0,
7993
),
8094
applicationInfo =
8195
ApplicationInfo(
@@ -92,15 +106,31 @@ class SessionEventEncoderTest {
92106
assertThat(json)
93107
.isEqualTo(
94108
"""
95-
{
96-
"event_type":0,
97-
"session_data":{
98-
"session_id":"",
99-
"first_session_id":"",
100-
"session_index":0,
101-
"firebase_installation_id":""
109+
{
110+
"event_type":0,
111+
"session_data":{
112+
"session_id":"",
113+
"first_session_id":"",
114+
"session_index":0,
115+
"firebase_installation_id":"",
116+
"event_timestamp_us":0,
117+
"data_collection_status":{
118+
"performance":2,
119+
"crashlytics":2,
120+
"session_sampling_rate":1.0
121+
}
122+
},
123+
"application_info":{
124+
"app_id":"",
125+
"device_model":"",
126+
"session_sdk_version":"",
127+
"log_environment":3,
128+
"android_app_info":{
129+
"package_name":"",
130+
"version_name":""
131+
}
132+
}
102133
}
103-
}
104134
"""
105135
.lines()
106136
.joinToString("") { it.trim() }

firebase-sessions/src/test/kotlin/com/google/firebase/sessions/SessionEventTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class SessionEventTest {
3232
val sessionEvent =
3333
SessionEvents.startSession(
3434
FakeFirebaseApp.fakeFirebaseApp(),
35-
TestSessionEventData.TEST_SESSION_DETAILS
35+
TestSessionEventData.TEST_SESSION_DETAILS,
36+
TestSessionEventData.TEST_SESSION_TIMESTAMP_US,
3637
)
3738

3839
assertThat(sessionEvent).isEqualTo(TestSessionEventData.EXPECTED_DEFAULT_SESSION_EVENT)

firebase-sessions/src/test/kotlin/com/google/firebase/sessions/testing/TestSessionEventData.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ internal object TestSessionEventData {
2929
sessionIndex = 3,
3030
)
3131

32+
const val TEST_SESSION_TIMESTAMP_US: Long = 12340000
33+
3234
val EXPECTED_DEFAULT_SESSION_EVENT =
3335
SessionEvent(
3436
eventType = EventType.SESSION_START,
@@ -37,6 +39,8 @@ internal object TestSessionEventData {
3739
sessionId = "a1b2c3",
3840
firstSessionId = "a1a1a1",
3941
sessionIndex = 3,
42+
firebaseInstallationId = "",
43+
eventTimestampUs = TestSessionEventData.TEST_SESSION_TIMESTAMP_US,
4044
),
4145
applicationInfo =
4246
ApplicationInfo(

0 commit comments

Comments
 (0)