Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an overload to FirebaseCrashlytics.recordException to attach additional custom key value pairs #6528

Merged
merged 50 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
71fff26
Initial implementation of recording a custom key value pair in record…
tejasd Nov 20, 2024
981a51e
Fix unit tests affected by EventMetadata
tejasd Nov 21, 2024
81fd3fa
Add copyright header to EventMetadata
tejasd Nov 21, 2024
2e39254
Update api.txt file
tejasd Nov 21, 2024
f6196e2
Add a JvmOverload in EventMetadata to use the default value for userInfo
tejasd Nov 21, 2024
38a4a26
Add a unit test to verify the behavior of userInfo keys
tejasd Nov 21, 2024
7c422bb
Update documentation of EventMetadata
tejasd Nov 21, 2024
9f99b44
Remove TODO
tejasd Nov 21, 2024
bb3aae2
Additional documentation for EventMetadata
tejasd Nov 21, 2024
c02234e
Add details to CHANGELOG
tejasd Nov 21, 2024
1b5f09e
Merge branch 'main' into td/record-exception
tejasd Nov 21, 2024
590cc9a
Merge branch 'main' into td/record-exception
tejasd Nov 25, 2024
5fdeade
Refactor the merging of event and global keys into a method, and add …
tejasd Nov 25, 2024
dfaf14d
Add a TODO
tejasd Nov 25, 2024
8a3b6e9
Revert CHANGELOG
tejasd Nov 26, 2024
f30f48c
Merge branch 'main' into td/record-exception
tejasd Nov 26, 2024
19fce3e
Fix typo
tejasd Nov 26, 2024
92e133a
Fix CHANGELOG
tejasd Nov 26, 2024
4d58ecd
unused import
tejasd Nov 26, 2024
f465408
Refactor the method to merge event and global keys
tejasd Nov 26, 2024
d0d7c53
return unmodifiable map
tejasd Nov 26, 2024
4e4f1bf
Fix accidental new lines
tejasd Nov 26, 2024
b0a3bfc
Add missing continue
tejasd Nov 26, 2024
abd31d3
Update unit tests
tejasd Nov 26, 2024
16648c0
Explicitly differentiate between internal and external keys in the Se…
tejasd Nov 26, 2024
2c4942f
Change back behavior in empty event keys, and add additional unit tests
tejasd Nov 26, 2024
9cd5814
Add extra tests and fix a bug in adding event keys
tejasd Nov 27, 2024
ca6f434
additional unit test changes
tejasd Nov 27, 2024
12142f5
additional unit test changes
tejasd Nov 27, 2024
d13605e
Rename userInfo in EventMetadata to additionalCustomKeys
tejasd Nov 27, 2024
c3cf46b
Update javadoc
tejasd Nov 27, 2024
4471d23
Update comment
tejasd Nov 27, 2024
bbfc5e8
more javadoc updates
tejasd Nov 27, 2024
dcc33e6
Rename userInfo to eventKeys where applicable
tejasd Nov 27, 2024
af2ddb1
update doc
tejasd Nov 27, 2024
85179cc
Merge branch 'main' into td/record-exception
tejasd Nov 27, 2024
c88649e
Remove LinkedHashMap TODO.
tejasd Nov 27, 2024
b384a7c
Update the public API
tejasd Nov 27, 2024
658f870
Restore null throwable loggingin the original recordException
tejasd Nov 27, 2024
6144c29
Update api.txt
tejasd Nov 27, 2024
bf9d546
Merge branch 'main' into td/record-exception
tejasd Nov 28, 2024
dda33f3
Merge branch 'main' into td/record-exception
tejasd Nov 29, 2024
c285209
Fix brackets
tejasd Dec 3, 2024
72ff0c8
Update logging
tejasd Dec 3, 2024
142ed35
Merge branch 'main' into td/record-exception
tejasd Dec 3, 2024
d53c1f5
Chnage visibility of EventMetadata
tejasd Dec 3, 2024
c94e370
Fix space in log
tejasd Dec 3, 2024
cdcdc9c
Merge branch 'main' into td/record-exception
tejasd Dec 5, 2024
3d3d1d4
Add changelog
tejasd Dec 5, 2024
79417ac
Reword changelog
tejasd Dec 5, 2024
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
3 changes: 2 additions & 1 deletion firebase-crashlytics/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Unreleased

* [feature] Added an overload for `recordException` that allows logging additional custom
keys to the non fatal event [#3551]

# 19.3.0
* [fixed] Fixed inefficiency in the Kotlin `FirebaseCrashlytics.setCustomKeys` extension.
Expand Down
3 changes: 2 additions & 1 deletion firebase-crashlytics/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ package com.google.firebase.crashlytics {
method public void deleteUnsentReports();
method public boolean didCrashOnPreviousExecution();
method @NonNull public static com.google.firebase.crashlytics.FirebaseCrashlytics getInstance();
method public boolean isCrashlyticsCollectionEnabled();
method public void log(@NonNull String);
method public void recordException(@NonNull Throwable);
method public void recordException(@NonNull Throwable, @NonNull com.google.firebase.crashlytics.CustomKeysAndValues);
method public void sendUnsentReports();
method public boolean isCrashlyticsCollectionEnabled();
method public void setCrashlyticsCollectionEnabled(boolean);
method public void setCrashlyticsCollectionEnabled(@Nullable Boolean);
method public void setCustomKey(@NonNull String, boolean);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import com.google.firebase.crashlytics.internal.NativeSessionFileProvider;
import com.google.firebase.crashlytics.internal.analytics.AnalyticsEventLogger;
import com.google.firebase.crashlytics.internal.concurrency.CrashlyticsWorkers;
import com.google.firebase.crashlytics.internal.metadata.EventMetadata;
import com.google.firebase.crashlytics.internal.metadata.LogFileManager;
import com.google.firebase.crashlytics.internal.metadata.UserMetadata;
import com.google.firebase.crashlytics.internal.model.CrashlyticsReport;
Expand All @@ -57,6 +58,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -216,14 +218,14 @@ public void testWriteNonFatal_callsSessionReportingCoordinatorPersistNonFatal()
when(mockSessionReportingCoordinator.listSortedOpenSessionIds())
.thenReturn(new TreeSet<>(Collections.singleton(sessionId)));

controller.writeNonFatalException(thread, nonFatal);
controller.writeNonFatalException(thread, nonFatal, Map.of());
crashlyticsWorkers.common.submit(() -> controller.doCloseSessions(testSettingsProvider));

crashlyticsWorkers.common.await();
crashlyticsWorkers.diskWrite.await();

verify(mockSessionReportingCoordinator)
.persistNonFatalEvent(eq(nonFatal), eq(thread), eq(sessionId), anyLong());
.persistNonFatalEvent(eq(nonFatal), eq(thread), any(EventMetadata.class));
}

@SdkSuppress(minSdkVersion = 30) // ApplicationExitInfo
Expand Down Expand Up @@ -377,7 +379,7 @@ public void testLoggedExceptionsAfterCrashOk() {
testSettingsProvider, Thread.currentThread(), new RuntimeException());

// This should not throw.
controller.writeNonFatalException(Thread.currentThread(), new RuntimeException());
controller.writeNonFatalException(Thread.currentThread(), new RuntimeException(), Map.of());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,143 @@ public void testCustomAttributes() throws Exception {
assertEquals(longValue, metadata.getCustomKeys().get(key1));
}

@Test
public void testCustomAttributes_retrievedWithEmptyEventKeys() throws Exception {
UserMetadata metadata = crashlyticsCore.getController().getUserMetadata();

assertTrue(metadata.getCustomKeys(Map.of()).isEmpty());

final String id = "id012345";
crashlyticsCore.setUserId(id);
crashlyticsWorkers.common.await();
assertEquals(id, metadata.getUserId());

final StringBuffer idBuffer = new StringBuffer(id);
while (idBuffer.length() < UserMetadata.MAX_ATTRIBUTE_SIZE) {
idBuffer.append("0");
}
final String longId = idBuffer.toString();
final String superLongId = longId + "more chars";

crashlyticsCore.setUserId(superLongId);
crashlyticsWorkers.common.await();
assertEquals(longId, metadata.getUserId());

final String key1 = "key1";
final String value1 = "value1";
crashlyticsCore.setCustomKey(key1, value1);
crashlyticsWorkers.common.await();
assertEquals(value1, metadata.getCustomKeys(Map.of()).get(key1));

// Adding an existing key with the same value should return false
assertFalse(metadata.setCustomKey(key1, value1));
assertTrue(metadata.setCustomKey(key1, "someOtherValue"));
assertTrue(metadata.setCustomKey(key1, value1));
assertFalse(metadata.setCustomKey(key1, value1));

final String longValue = longId.replaceAll("0", "x");
final String superLongValue = longValue + "some more chars";

// test truncation of custom keys and attributes
crashlyticsCore.setCustomKey(superLongId, superLongValue);
crashlyticsWorkers.common.await();
assertNull(metadata.getCustomKeys(Map.of()).get(superLongId));
assertEquals(longValue, metadata.getCustomKeys().get(longId));

// test the max number of attributes. We've already set 2.
for (int i = 2; i < UserMetadata.MAX_ATTRIBUTES; ++i) {
final String key = "key" + i;
final String value = "value" + i;
crashlyticsCore.setCustomKey(key, value);
crashlyticsWorkers.common.await();
assertEquals(value, metadata.getCustomKeys(Map.of()).get(key));
}
// should be full now, extra key, value pairs will be dropped.
final String key = "new key";
crashlyticsCore.setCustomKey(key, "some value");
crashlyticsWorkers.common.await();
assertFalse(metadata.getCustomKeys(Map.of()).containsKey(key));

// should be able to update existing keys
crashlyticsCore.setCustomKey(key1, longValue);
crashlyticsWorkers.common.await();
assertEquals(longValue, metadata.getCustomKeys(Map.of()).get(key1));

// when we set a key to null, it should still exist with an empty value
crashlyticsCore.setCustomKey(key1, null);
crashlyticsWorkers.common.await();
assertEquals("", metadata.getCustomKeys(Map.of()).get(key1));

// keys and values are trimmed.
crashlyticsCore.setCustomKey(" " + key1 + " ", " " + longValue + " ");
crashlyticsWorkers.common.await();
assertTrue(metadata.getCustomKeys(Map.of()).containsKey(key1));
assertEquals(longValue, metadata.getCustomKeys(Map.of()).get(key1));
}

@Test
public void testCustomKeysMergedWithEventKeys() throws Exception {
UserMetadata metadata = crashlyticsCore.getController().getUserMetadata();

Map<String, String> keysAndValues = new HashMap<>();
keysAndValues.put("customKey1", "value");
keysAndValues.put("customKey2", "value");
keysAndValues.put("customKey3", "value");

crashlyticsCore.setCustomKeys(keysAndValues);
crashlyticsWorkers.common.await();

Map<String, String> eventKeysAndValues = new HashMap<>();
eventKeysAndValues.put("eventKey1", "eventValue");
eventKeysAndValues.put("eventKey2", "eventValue");

// Tests reading custom keys with event keys.
assertEquals(keysAndValues.size(), metadata.getCustomKeys().size());
assertEquals(keysAndValues.size(), metadata.getCustomKeys(Map.of()).size());
assertEquals(
keysAndValues.size() + eventKeysAndValues.size(),
metadata.getCustomKeys(eventKeysAndValues).size());

// Tests event keys don't add to custom keys in future reads.
assertEquals(keysAndValues.size(), metadata.getCustomKeys().size());
assertEquals(keysAndValues.size(), metadata.getCustomKeys(Map.of()).size());

// Tests additional event keys.
eventKeysAndValues.put("eventKey3", "eventValue");
eventKeysAndValues.put("eventKey4", "eventValue");
assertEquals(
keysAndValues.size() + eventKeysAndValues.size(),
metadata.getCustomKeys(eventKeysAndValues).size());

// Tests overriding custom key with event keys.
keysAndValues.put("eventKey1", "value");
crashlyticsCore.setCustomKeys(keysAndValues);
crashlyticsWorkers.common.await();

assertEquals("value", metadata.getCustomKeys().get("eventKey1"));
assertEquals("value", metadata.getCustomKeys(Map.of()).get("eventKey1"));
assertEquals("eventValue", metadata.getCustomKeys(eventKeysAndValues).get("eventKey1"));

// Test the event key behavior when the count of custom keys is max.
for (int i = keysAndValues.size(); i < UserMetadata.MAX_ATTRIBUTES; ++i) {
final String key = "key" + i;
final String value = "value" + i;
crashlyticsCore.setCustomKey(key, value);
crashlyticsWorkers.common.await();
assertEquals(value, metadata.getCustomKeys().get(key));
}

assertEquals(UserMetadata.MAX_ATTRIBUTES, metadata.getCustomKeys().size());

// Tests event keys override global custom keys when the key exists.
assertEquals("value", metadata.getCustomKeys().get("eventKey1"));
assertEquals("value", metadata.getCustomKeys(Map.of()).get("eventKey1"));
assertEquals("eventValue", metadata.getCustomKeys(eventKeysAndValues).get("eventKey1"));

// Test when event keys *don't* override global custom keys.
assertNull(metadata.getCustomKeys(eventKeysAndValues).get("eventKey2"));
}

@Test
public void testBulkCustomKeys() throws Exception {
final double DELTA = 1e-15;
Expand Down
Loading
Loading