From 43ba279b5e8c5a09b4ec9681fef7a0e7797b19f2 Mon Sep 17 00:00:00 2001 From: Joseph Rodiz Date: Tue, 7 Apr 2026 10:38:00 -0600 Subject: [PATCH] Allow custom attributes on built-in traces via global attribute API Resolves firebase/firebase-android-sdk#6664. FirebasePerformance already had putAttribute/getAttribute/removeAttribute/ getAttributes backed by a ConcurrentHashMap, but they were @hide and not wired into built-in trace serialization. This change makes them public and ensures global attributes are included on all traces (built-in and custom). Changes: - Make global attribute methods (putAttribute, removeAttribute, getAttribute, getAttributes) public on FirebasePerformance - Expose MAX_TRACE_CUSTOM_ATTRIBUTES, MAX_ATTRIBUTE_KEY_LENGTH, MAX_ATTRIBUTE_VALUE_LENGTH as public constants on FirebasePerformance - Update api.txt with the expanded public API surface - Merge global attributes in TraceMetricBuilder (screen + custom Trace objects) - Add global attributes to AppStartTrace (_app_start) - Add global attributes to AppStateMonitor.sendSessionLog() (_fs, _bs) - Merge global attributes in NetworkRequestMetricBuilder (auto + manual HTTP) - Trace/request-level attributes take precedence over global on key conflicts Test coverage (TraceMetric.custom_attributes): - AppStartTraceTest: global attrs on _app_start - AppStateMonitorTest: global attrs on _app_in_foreground, _app_in_background, and screen traces (_st_*) - TraceMetricBuilderTest: global attrs merged, trace-level overrides global - NetworkRequestMetricBuilderTest: global attrs on network requests, per-request overrides global - TransportManagerTest: global attrs on built-in traces at ApplicationInfo level --- firebase-perf/CHANGELOG.md | 1 + firebase-perf/api.txt | 4 ++ .../firebase/perf/FirebasePerformance.java | 10 +-- .../perf/application/AppStateMonitor.java | 7 +++ .../firebase/perf/metrics/AppStartTrace.java | 7 +++ .../metrics/NetworkRequestMetricBuilder.java | 11 +++- .../perf/metrics/TraceMetricBuilder.java | 11 +++- .../perf/application/AppStateMonitorTest.java | 61 +++++++++++++++++++ .../perf/metrics/AppStartTraceTest.java | 29 +++++++++ .../NetworkRequestMetricBuilderTest.java | 29 +++++++++ .../perf/metrics/TraceMetricBuilderTest.java | 58 ++++++++++++++++++ .../perf/transport/TransportManagerTest.java | 42 +++++++++++++ 12 files changed, 261 insertions(+), 9 deletions(-) diff --git a/firebase-perf/CHANGELOG.md b/firebase-perf/CHANGELOG.md index 966a91944e3..03e8cf74f54 100644 --- a/firebase-perf/CHANGELOG.md +++ b/firebase-perf/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- [feature] Added support for custom attributes on built-in traces. Global attributes set via `FirebasePerformance.getInstance().putAttribute()` are now included in all built-in traces (`_app_start`, `_app_in_foreground`, `_app_in_background`, screen traces) and network requests. [#6664] - [changed] Bumped internal dependencies. # 22.0.4 diff --git a/firebase-perf/api.txt b/firebase-perf/api.txt index 13dfb7dcbea..d22c80e12c6 100644 --- a/firebase-perf/api.txt +++ b/firebase-perf/api.txt @@ -2,11 +2,15 @@ package com.google.firebase.perf { @javax.inject.Singleton public class FirebasePerformance { + method public String? getAttribute(String); + method public java.util.Map getAttributes(); method public static com.google.firebase.perf.FirebasePerformance getInstance(); method public boolean isPerformanceCollectionEnabled(); method public com.google.firebase.perf.metrics.HttpMetric newHttpMetric(String, @com.google.firebase.perf.FirebasePerformance.HttpMethod String); method public com.google.firebase.perf.metrics.HttpMetric newHttpMetric(java.net.URL, @com.google.firebase.perf.FirebasePerformance.HttpMethod String); method public com.google.firebase.perf.metrics.Trace newTrace(String); + method public void putAttribute(String, String); + method public void removeAttribute(String); method public void setPerformanceCollectionEnabled(boolean); method public static com.google.firebase.perf.metrics.Trace startTrace(String); field public static final int MAX_ATTRIBUTE_KEY_LENGTH = 40; // 0x28 diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerformance.java b/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerformance.java index 40468566225..4dcbdb922ac 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerformance.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/FirebasePerformance.java @@ -71,15 +71,15 @@ public class FirebasePerformance implements FirebasePerformanceAttributable { /** Maximum allowed number of attributes allowed in a trace. */ @SuppressWarnings("unused") // Used in Javadoc. - private static final int MAX_TRACE_CUSTOM_ATTRIBUTES = Constants.MAX_TRACE_CUSTOM_ATTRIBUTES; + public static final int MAX_TRACE_CUSTOM_ATTRIBUTES = Constants.MAX_TRACE_CUSTOM_ATTRIBUTES; /** Maximum allowed length of the Key of the {@link Trace} attribute */ @SuppressWarnings("unused") // Used in Javadoc. - private static final int MAX_ATTRIBUTE_KEY_LENGTH = Constants.MAX_ATTRIBUTE_KEY_LENGTH; + public static final int MAX_ATTRIBUTE_KEY_LENGTH = Constants.MAX_ATTRIBUTE_KEY_LENGTH; /** Maximum allowed length of the Value of the {@link Trace} attribute */ @SuppressWarnings("unused") // Used in Javadoc. - private static final int MAX_ATTRIBUTE_VALUE_LENGTH = Constants.MAX_ATTRIBUTE_VALUE_LENGTH; + public static final int MAX_ATTRIBUTE_VALUE_LENGTH = Constants.MAX_ATTRIBUTE_VALUE_LENGTH; /** Maximum allowed length of the name of the {@link Trace} */ @SuppressWarnings("unused") // Used in Javadoc. @@ -332,7 +332,6 @@ public boolean isPerformanceCollectionEnabled() { * length is limited to {@link #MAX_ATTRIBUTE_KEY_LENGTH} * @param value value of the attribute. The max length is limited to {@link * #MAX_ATTRIBUTE_VALUE_LENGTH} - * @hide */ @Override public void putAttribute(@NonNull String attribute, @NonNull String value) { @@ -371,7 +370,6 @@ private void checkAttribute(@Nullable String key, @Nullable String value) { * Removes the attribute from the global list of attributes. * * @param attribute name of the attribute to be removed from the global pool. - * @hide */ @Override public void removeAttribute(@NonNull String attribute) { @@ -383,7 +381,6 @@ public void removeAttribute(@NonNull String attribute) { * * @param attribute name of the attribute to fetch the value for * @return the value of the attribute if it exists or null otherwise. - * @hide */ @Override @Nullable @@ -395,7 +392,6 @@ public String getAttribute(@NonNull String attribute) { * Returns the map of all the attributes currently added in the global pool. * * @return map of attributes and its values currently added to the running Traces - * @hide */ @Override @NonNull diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/application/AppStateMonitor.java b/firebase-perf/src/main/java/com/google/firebase/perf/application/AppStateMonitor.java index b014d82bb83..dd6e04ff084 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/application/AppStateMonitor.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/application/AppStateMonitor.java @@ -22,6 +22,7 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.FragmentActivity; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.config.ConfigResolver; import com.google.firebase.perf.logging.AndroidLogger; import com.google.firebase.perf.metrics.FrameMetricsCalculator.PerfFrameMetrics; @@ -391,6 +392,12 @@ private void sendSessionLog(String name, Timer startTime, Timer endTime) { // reset metrics. metricToCountMap.clear(); } + try { + metric.putAllCustomAttributes(FirebasePerformance.getInstance().getAttributes()); + } catch (IllegalStateException e) { + // FirebaseApp not initialized yet, skip global attributes + } + // The Foreground and Background trace marks the transition between the two states, // so we always specify the state to be ApplicationProcessState.FOREGROUND_BACKGROUND. transportManager.log(metric.build(), ApplicationProcessState.FOREGROUND_BACKGROUND); diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java index 813c8988383..212546c78c6 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java @@ -35,6 +35,7 @@ import androidx.lifecycle.ProcessLifecycleOwner; import com.google.firebase.FirebaseApp; import com.google.firebase.StartupTime; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.config.ConfigResolver; import com.google.firebase.perf.logging.AndroidLogger; import com.google.firebase.perf.session.PerfSession; @@ -478,6 +479,12 @@ private void logAppStartTrace() { metric.addAllSubtraces(subtraces).addPerfSessions(this.startSession.build()); + try { + metric.putAllCustomAttributes(FirebasePerformance.getInstance().getAttributes()); + } catch (IllegalStateException e) { + // FirebaseApp not initialized yet, skip global attributes + } + transportManager.log(metric.build(), ApplicationProcessState.FOREGROUND_BACKGROUND); } diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilder.java b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilder.java index 1e04744d1b2..9c442b45010 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilder.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilder.java @@ -18,6 +18,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.application.AppStateMonitor; import com.google.firebase.perf.application.AppStateUpdateHandler; import com.google.firebase.perf.logging.AndroidLogger; @@ -37,6 +38,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -213,7 +215,14 @@ public NetworkRequestMetricBuilder setRequestPayloadBytes(long bytes) { /** Sets the customAttributes for the current {@link NetworkRequestMetric}. */ public NetworkRequestMetricBuilder setCustomAttributes(Map attributes) { - builder.clearCustomAttributes().putAllCustomAttributes(attributes); + Map merged = new HashMap<>(); + try { + merged.putAll(FirebasePerformance.getInstance().getAttributes()); + } catch (IllegalStateException e) { + // FirebaseApp not initialized yet, skip global attributes + } + merged.putAll(attributes); + builder.clearCustomAttributes().putAllCustomAttributes(merged); return this; } diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/TraceMetricBuilder.java b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/TraceMetricBuilder.java index 424ef2c5d45..ceb75740829 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/TraceMetricBuilder.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/TraceMetricBuilder.java @@ -15,9 +15,11 @@ package com.google.firebase.perf.metrics; import androidx.annotation.NonNull; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.session.PerfSession; import com.google.firebase.perf.v1.TraceMetric; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,7 +55,14 @@ TraceMetric build() { } } - traceMetric.putAllCustomAttributes(trace.getAttributes()); + Map mergedAttributes = new HashMap<>(); + try { + mergedAttributes.putAll(FirebasePerformance.getInstance().getAttributes()); + } catch (IllegalStateException e) { + // FirebaseApp not initialized yet, skip global attributes + } + mergedAttributes.putAll(trace.getAttributes()); + traceMetric.putAllCustomAttributes(mergedAttributes); com.google.firebase.perf.v1.PerfSession[] perfSessions = PerfSession.buildAndSort(trace.getSessions()); diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/application/AppStateMonitorTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/application/AppStateMonitorTest.java index 0b7d4bbfc17..5ed3d509dfb 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/application/AppStateMonitorTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/application/AppStateMonitorTest.java @@ -33,6 +33,7 @@ import android.content.Context; import android.os.Bundle; import android.view.WindowManager.LayoutParams; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.FirebasePerformanceInitializer; import com.google.firebase.perf.FirebasePerformanceTestBase; import com.google.firebase.perf.config.ConfigResolver; @@ -771,6 +772,66 @@ public void appColdStart_singleSubscriberRegistersForMultipleTimes_oneCallbackIs verify(mockInitializer1, times(1)).onAppColdStart(); } + @Test + public void screenTrace_globalAttributesIncluded() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + AppStateMonitor monitor = new AppStateMonitor(transportManager, clock); + currentTime = 1; + monitor.onActivityStarted(activity1); + currentTime = 2; + monitor.onActivityStopped(activity1); + + verify(transportManager, times(1)) + .log(argTraceMetric.capture(), any(ApplicationProcessState.class)); + TraceMetric metric = argTraceMetric.getValue(); + assertThat(metric.getName()).startsWith(Constants.SCREEN_TRACE_PREFIX); + assertThat(metric.getCustomAttributesMap()).containsEntry("globalKey", "globalValue"); + + firebasePerformance.removeAttribute("globalKey"); + } + + @Test + public void foregroundTrace_globalAttributesIncluded() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + AppStateMonitor monitor = new AppStateMonitor(transportManager, clock); + currentTime = 1; + monitor.onActivityResumed(activity1); + currentTime = 2; + monitor.onActivityStopped(activity1); + + verify(transportManager, times(1)).log(argTraceMetric.capture(), eq(FOREGROUND_BACKGROUND)); + TraceMetric metric = argTraceMetric.getValue(); + Assert.assertEquals(Constants.TraceNames.FOREGROUND_TRACE_NAME.toString(), metric.getName()); + Assert.assertEquals("globalValue", metric.getCustomAttributesMap().get("globalKey")); + + firebasePerformance.removeAttribute("globalKey"); + } + + @Test + public void backgroundTrace_globalAttributesIncluded() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + AppStateMonitor monitor = new AppStateMonitor(transportManager, clock); + currentTime = 1; + monitor.onActivityResumed(activity1); + currentTime = 2; + monitor.onActivityStopped(activity1); + currentTime = 3; + monitor.onActivityResumed(activity1); + + verify(transportManager, times(2)).log(argTraceMetric.capture(), eq(FOREGROUND_BACKGROUND)); + TraceMetric metric = argTraceMetric.getValue(); + Assert.assertEquals(Constants.TraceNames.BACKGROUND_TRACE_NAME.toString(), metric.getName()); + Assert.assertEquals("globalValue", metric.getCustomAttributesMap().get("globalKey")); + + firebasePerformance.removeAttribute("globalKey"); + } + private static Activity createFakeActivity(boolean isHardwareAccelerated) { ActivityController fakeActivityController = Robolectric.buildActivity(Activity.class); diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java index daa80ad29a2..b34f9925bde 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/AppStartTraceTest.java @@ -33,6 +33,7 @@ import android.os.SystemClock; import android.view.View; import androidx.test.core.app.ApplicationProvider; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.FirebasePerformanceTestBase; import com.google.firebase.perf.config.ConfigResolver; import com.google.firebase.perf.session.PerfSession; @@ -341,4 +342,32 @@ public void timeToInitialDisplay_isLogged() { assertThat(ttid.getDurationUs()).isEqualTo(drawTime - appStartTime); assertThat(ttid.getSubtracesCount()).isEqualTo(3); } + + @Test + public void testAppStartTrace_globalAttributesIncluded() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService(); + AppStartTrace trace = + new AppStartTrace(transportManager, clock, configResolver, fakeExecutorService); + trace.registerActivityLifecycleCallbacks(appContext); + currentTime = 1; + trace.onActivityCreated(activity1, bundle); + currentTime = 2; + trace.onActivityStarted(activity1); + currentTime = 3; + trace.onActivityResumed(activity1); + fakeExecutorService.runAll(); + + verify(transportManager, times(1)) + .log( + traceArgumentCaptor.capture(), + ArgumentMatchers.nullable(ApplicationProcessState.class)); + TraceMetric metric = traceArgumentCaptor.getValue(); + Assert.assertEquals(Constants.TraceNames.APP_START_TRACE_NAME.toString(), metric.getName()); + Assert.assertEquals("globalValue", metric.getCustomAttributesMap().get("globalKey")); + + firebasePerformance.removeAttribute("globalKey"); + } } diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilderTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilderTest.java index 61b3823741d..d0656d95af9 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilderTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/NetworkRequestMetricBuilderTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.FirebasePerformanceTestBase; import com.google.firebase.perf.application.AppStateMonitor; import com.google.firebase.perf.session.PerfSession; @@ -323,6 +324,34 @@ public void testSettingNullForContentTypeClearsIt() { assertThat(networkMetricBuilder.build().hasResponseContentType()).isFalse(); } + @Test + public void testGlobalAttributesIncludedInNetworkRequestMetric() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + networkMetricBuilder.setCustomAttributes(java.util.Collections.emptyMap()); + + NetworkRequestMetric metric = networkMetricBuilder.build(); + assertThat(metric.getCustomAttributesMap()).containsEntry("globalKey", "globalValue"); + + firebasePerformance.removeAttribute("globalKey"); + } + + @Test + public void testPerRequestAttributeOverridesGlobalAttributeInNetworkRequestMetric() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("sharedKey", "globalValue"); + + networkMetricBuilder.setCustomAttributes( + java.util.Collections.singletonMap("sharedKey", "requestValue")); + + NetworkRequestMetric metric = networkMetricBuilder.build(); + assertThat(metric.getCustomAttributesMap()).containsEntry("sharedKey", "requestValue"); + assertThat(metric.getCustomAttributesCount()).isEqualTo(1); + + firebasePerformance.removeAttribute("sharedKey"); + } + @Test public void testUpdateSessionWithValidSessionIsAdded() { networkMetricBuilder.setRequestStartTimeMicros(/* time= */ 2000); diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/TraceMetricBuilderTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/TraceMetricBuilderTest.java index fc019c51ce0..757414dddfc 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/metrics/TraceMetricBuilderTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/metrics/TraceMetricBuilderTest.java @@ -17,6 +17,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.MockitoAnnotations.initMocks; +import com.google.firebase.perf.FirebasePerformance; import com.google.firebase.perf.FirebasePerformanceTestBase; import com.google.firebase.perf.application.AppStateMonitor; import com.google.firebase.perf.transport.TransportManager; @@ -331,4 +332,61 @@ public void testUpdatingCustomAttributes() { Assert.assertEquals(TRACE_1, traceMetric.getName()); Assert.assertEquals(1, traceMetric.getCustomAttributesCount()); } + + @Test + public void testGlobalAttributesIncludedInTraceMetric() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + Trace trace = new Trace(TRACE_1, transportManager, clock, appStateMonitor); + currentTime = 1; + trace.start(); + currentTime = 2; + trace.stop(); + TraceMetric traceMetric = new TraceMetricBuilder(trace).build(); + + Assert.assertEquals(1, traceMetric.getCustomAttributesCount()); + Assert.assertEquals("globalValue", traceMetric.getCustomAttributesMap().get("globalKey")); + + firebasePerformance.removeAttribute("globalKey"); + } + + @Test + public void testTraceAttributeOverridesGlobalAttribute() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("sharedKey", "globalValue"); + + Trace trace = new Trace(TRACE_1, transportManager, clock, appStateMonitor); + currentTime = 1; + trace.start(); + trace.putAttribute("sharedKey", "traceValue"); + currentTime = 2; + trace.stop(); + TraceMetric traceMetric = new TraceMetricBuilder(trace).build(); + + Assert.assertEquals(1, traceMetric.getCustomAttributesCount()); + Assert.assertEquals("traceValue", traceMetric.getCustomAttributesMap().get("sharedKey")); + + firebasePerformance.removeAttribute("sharedKey"); + } + + @Test + public void testGlobalAndTraceAttributesMerged() { + FirebasePerformance firebasePerformance = FirebasePerformance.getInstance(); + firebasePerformance.putAttribute("globalKey", "globalValue"); + + Trace trace = new Trace(TRACE_1, transportManager, clock, appStateMonitor); + currentTime = 1; + trace.start(); + trace.putAttribute("traceKey", "traceValue"); + currentTime = 2; + trace.stop(); + TraceMetric traceMetric = new TraceMetricBuilder(trace).build(); + + Assert.assertEquals(2, traceMetric.getCustomAttributesCount()); + Assert.assertEquals("globalValue", traceMetric.getCustomAttributesMap().get("globalKey")); + Assert.assertEquals("traceValue", traceMetric.getCustomAttributesMap().get("traceKey")); + + firebasePerformance.removeAttribute("globalKey"); + } } diff --git a/firebase-perf/src/test/java/com/google/firebase/perf/transport/TransportManagerTest.java b/firebase-perf/src/test/java/com/google/firebase/perf/transport/TransportManagerTest.java index 5376265aa0e..318f14bdcfc 100644 --- a/firebase-perf/src/test/java/com/google/firebase/perf/transport/TransportManagerTest.java +++ b/firebase-perf/src/test/java/com/google/firebase/perf/transport/TransportManagerTest.java @@ -1102,6 +1102,48 @@ public void syncLogForGaugeMetric_performanceDisabled_noInteractionWithFirebaseI // region Global Custom Attributes Behaviour + @Test + public void logBuiltInTraces_globalCustomAttributesAreAdded() { + FirebasePerformance.getInstance().removeAttribute("experiment_id"); + FirebasePerformance.getInstance().removeAttribute("user_tier"); + FirebasePerformance.getInstance().putAttribute("experiment_id", "exp_123"); + FirebasePerformance.getInstance().putAttribute("user_tier", "gold"); + + // 1. App Start Trace (_as) + TraceMetric appStartTrace = createValidTraceMetric().toBuilder().setName("_as").build(); + testTransportManager.log(appStartTrace); + fakeExecutorService.runAll(); + PerfMetric loggedAppStart = getLastLoggedEvent(times(1)); + assertThat(loggedAppStart.getApplicationInfo().getCustomAttributesMap()) + .containsEntry("experiment_id", "exp_123"); + clearLastLoggedEvents(); + + // 2. Screen Trace (_st_MainActivity) + TraceMetric screenTrace = + createValidTraceMetric().toBuilder() + .setName("_st_MainActivity") + .putCounters(Constants.CounterNames.FRAMES_TOTAL.toString(), 100L) + .build(); + testTransportManager.log(screenTrace); + fakeExecutorService.runAll(); + PerfMetric loggedScreenTrace = getLastLoggedEvent(times(1)); + assertThat(loggedScreenTrace.getApplicationInfo().getCustomAttributesMap()) + .containsEntry("user_tier", "gold"); + clearLastLoggedEvents(); + + // 3. Network Request + NetworkRequestMetric networkMetric = createValidNetworkRequestMetric(); + testTransportManager.log(networkMetric); + fakeExecutorService.runAll(); + PerfMetric loggedNetworkMetric = getLastLoggedEvent(times(1)); + assertThat(loggedNetworkMetric.getApplicationInfo().getCustomAttributesMap()) + .containsEntry("experiment_id", "exp_123"); + + // Cleanup + FirebasePerformance.getInstance().removeAttribute("experiment_id"); + FirebasePerformance.getInstance().removeAttribute("user_tier"); + } + @Test public void logTraceMetric_globalCustomAttributesAreAdded() { FirebasePerformance.getInstance().putAttribute("test_key1", "test_value1");