[FR] Allow custom attributes on built-in traces via global attribute API#8031
[FR] Allow custom attributes on built-in traces via global attribute API#8031jrodiz wants to merge 2 commits into
Conversation
Resolves firebase#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
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
… full attribute scope Global attributes apply to all traces (built-in and custom) via TraceMetricBuilder, not only the built-in traces listed in the original changelog entry. Updated the entry to accurately describe the full scope and mention that the attribute methods and constants were made public.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request makes global attribute methods and constants public in FirebasePerformance and ensures these attributes are merged into all traces (built-in and custom) and network requests. Feedback suggests enforcing the MAX_TRACE_CUSTOM_ATTRIBUTES limit during the merge process to prevent events from being dropped by the backend and optimizing map allocations by utilizing the defensive copy returned by getAttributes().
| 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); |
There was a problem hiding this comment.
The merging logic can result in a network request having more than MAX_TRACE_CUSTOM_ATTRIBUTES (5) attributes if both global and local attributes are set. Since the backend typically enforces a limit of 5 custom attributes per event, this could lead to events being dropped or truncated. Consider enforcing the limit during the merge, giving priority to local attributes.
| 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); |
There was a problem hiding this comment.
The merging logic can result in a trace having more than MAX_TRACE_CUSTOM_ATTRIBUTES (5) attributes if both global and local attributes are set. Since the backend typically enforces a limit of 5 custom attributes per event, this could lead to events being dropped or truncated. Consider enforcing the limit during the merge, giving priority to local 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); |
There was a problem hiding this comment.
The current implementation creates a new HashMap and then copies the global attributes into it. Since FirebasePerformance.getAttributes() already returns a defensive copy (a new HashMap), you can use it directly to avoid an extra map allocation and redundant copies.
| 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); | |
| Map<String, String> merged; | |
| try { | |
| merged = FirebasePerformance.getInstance().getAttributes(); | |
| } catch (IllegalStateException e) { | |
| // FirebaseApp not initialized yet, skip global attributes | |
| merged = new HashMap<>(); | |
| } | |
| merged.putAll(attributes); | |
| builder.clearCustomAttributes().putAllCustomAttributes(merged); |
| 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); |
There was a problem hiding this comment.
The current implementation creates a new HashMap and then copies the global attributes into it. Since FirebasePerformance.getAttributes() already returns a defensive copy (a new HashMap), you can use it directly to avoid an extra map allocation and redundant copies.
| 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); | |
| Map<String, String> mergedAttributes; | |
| try { | |
| mergedAttributes = FirebasePerformance.getInstance().getAttributes(); | |
| } catch (IllegalStateException e) { | |
| // FirebaseApp not initialized yet, skip global attributes | |
| mergedAttributes = new HashMap<>(); | |
| } | |
| mergedAttributes.putAll(trace.getAttributes()); | |
| traceMetric.putAllCustomAttributes(mergedAttributes); |
[FR] Allow custom attributes on built-in traces (#6664)
Summary
Resolves #6664
Firebase Performance already had
putAttribute/getAttribute/removeAttribute/getAttributesonFirebasePerformancebacked by aConcurrentHashMap, but these were@hideand not wired into built-in trace serialization. This change makes them public and ensures global attributes are included on all traces and network requests — built-in and custom alike.Changes
FirebasePerformance.java— Made 4 global attribute methods (putAttribute,removeAttribute,getAttribute,getAttributes) and 3 constants (MAX_TRACE_CUSTOM_ATTRIBUTES,MAX_ATTRIBUTE_KEY_LENGTH,MAX_ATTRIBUTE_VALUE_LENGTH) publicapi.txt— Added the 4 methods to the publicFirebasePerformanceAPI surfaceTraceMetricBuilder.java— Merges global attributes into allTrace-based metrics (screen traces, custom traces); trace-level attributes override global on key conflictAppStartTrace.java— Applies global attributes to the_app_starttrace metricAppStateMonitor.java— Applies global attributes to foreground (_fs) and background (_bs) session tracesNetworkRequestMetricBuilder.java— Merges global attributes into all network request metrics (auto-instrumented OkHttp and manualHttpMetric); per-request attributes override global on key conflictUsage
These attributes will appear on
_app_start,_app_in_foreground,_app_in_background, screen traces (_st_*), network requests, and all custom traces automatically.Design Notes
checkAttribute()logicmCustomAttributesis aConcurrentHashMap;getAttributes()returns a defensive copy_app_start: global attributes must be set before the first activity resumes (e.g., inApplication.onCreate())Test Coverage
_app_start—AppStartTraceTest_app_in_foreground(_fs) —AppStateMonitorTest_app_in_background(_bs) —AppStateMonitorTest_st_*) —AppStateMonitorTestNetworkRequestMetricBuilderTestApplicationInfo—TransportManagerTest