Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions firebase-perf/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 4 additions & 0 deletions firebase-perf/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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<java.lang.String!,java.lang.String!> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -213,7 +215,14 @@ public NetworkRequestMetricBuilder setRequestPayloadBytes(long bytes) {

/** Sets the customAttributes for the current {@link NetworkRequestMetric}. */
public NetworkRequestMetricBuilder setCustomAttributes(Map<String, String> attributes) {
builder.clearCustomAttributes().putAllCustomAttributes(attributes);
Map<String, String> 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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -53,7 +55,14 @@ TraceMetric build() {
}
}

traceMetric.putAllCustomAttributes(trace.getAttributes());
Map<String, String> 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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Activity> fakeActivityController = Robolectric.buildActivity(Activity.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Loading