Skip to content

Commit 903abce

Browse files
authored
Performance Monitoring transport format upgrade from proto2 to proto3 (#2525)
* Update the Fireperf's log fromat from proto2 to proto3. * Add CHANGELOG for Fireperf transport update from proto2 to proto3 (#2492) * Add unit tests with the new proto format change. (#2516)
1 parent 6ef51fe commit 903abce

File tree

5 files changed

+156
-31
lines changed

5 files changed

+156
-31
lines changed

packages/performance/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Unreleased
2+
- [changed] Internal transport protocol update from proto2 to proto3.

packages/performance/src/resources/trace.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ describe('Firebase Performance > trace', () => {
138138

139139
it('throws error if metric doesnt exist and has invalid name', () => {
140140
expect(() => trace.putMetric('_invalidMetric', 1)).to.throw();
141+
expect(() => trace.putMetric('_fid', 1)).to.throw();
141142
});
142143
});
143144

packages/performance/src/services/perf_logger.test.ts

Lines changed: 146 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ describe('Performance Monitoring > perf_logger', () => {
4040
const TRACE_NAME = 'testTrace';
4141
const START_TIME = 12345;
4242
const DURATION = 321;
43+
// Perf event header which is constant across tests in this file.
44+
const WEBAPP_INFO = `"application_info":{"google_app_id":"${APP_ID}",\
45+
"app_instance_id":"${IID}","web_app_info":{"sdk_version":"${SDK_VERSION}",\
46+
"page_url":"${PAGE_URL}","service_worker_status":${SERVICE_WORKER_STATUS},\
47+
"visibility_state":${VISIBILITY_STATE},"effective_connection_type":${EFFECTIVE_CONNECTION_TYPE}},\
48+
"application_process_state":0}`;
4349

4450
let addToQueueStub: SinonStub<
4551
Array<{ message: string; eventTime: number }>,
@@ -69,7 +75,6 @@ describe('Performance Monitoring > perf_logger', () => {
6975
stub(Api.prototype, 'getUrl').returns(PAGE_URL);
7076
stub(Api.prototype, 'getTimeOrigin').returns(TIME_ORIGIN);
7177
stub(initializationService, 'isPerfInitialized').returns(true);
72-
stub(attributeUtils, 'getVisibilityState').returns(VISIBILITY_STATE);
7378
stub(attributeUtils, 'getEffectiveConnectionType').returns(
7479
EFFECTIVE_CONNECTION_TYPE
7580
);
@@ -83,17 +88,20 @@ describe('Performance Monitoring > perf_logger', () => {
8388
});
8489

8590
describe('logTrace', () => {
86-
it('creates, serializes and sends a trace to cc service', () => {
87-
const EXPECTED_TRACE_MESSAGE = `{"application_info":{"google_app_id":"${APP_ID}",\
88-
"app_instance_id":"${IID}","web_app_info":{"sdk_version":"${SDK_VERSION}",\
89-
"page_url":"${PAGE_URL}","service_worker_status":${SERVICE_WORKER_STATUS},\
90-
"visibility_state":${VISIBILITY_STATE},"effective_connection_type":${EFFECTIVE_CONNECTION_TYPE}},\
91-
"application_process_state":0},"trace_metric":{"name":"${TRACE_NAME}","is_auto":false,\
92-
"client_start_time_us":${START_TIME * 1000},"duration_us":${DURATION * 1000}}}`;
91+
it('creates, serializes and sends a trace to transport service', () => {
92+
const EXPECTED_TRACE_MESSAGE =
93+
`{` +
94+
WEBAPP_INFO +
95+
`,"trace_metric":{"name":"${TRACE_NAME}","is_auto":false,\
96+
"client_start_time_us":${START_TIME * 1000},"duration_us":${DURATION * 1000},\
97+
"counters":{"counter1":3},"custom_attributes":{"attr":"val"}}}`;
9398
getIidStub.returns(IID);
99+
stub(attributeUtils, 'getVisibilityState').returns(VISIBILITY_STATE);
94100
SettingsService.getInstance().loggingEnabled = true;
95101
SettingsService.getInstance().logTraceAfterSampling = true;
96102
const trace = new Trace(TRACE_NAME);
103+
trace.putAttribute('attr', 'val');
104+
trace.putMetric('counter1', 3);
97105
trace.record(START_TIME, DURATION);
98106
clock.tick(1);
99107

@@ -105,16 +113,140 @@ describe('Performance Monitoring > perf_logger', () => {
105113

106114
it('does not log an event if cookies are disabled in the browser', () => {
107115
stub(Api.prototype, 'requiredApisAvailable').returns(false);
116+
stub(attributeUtils, 'getVisibilityState').returns(VISIBILITY_STATE);
108117
const trace = new Trace(TRACE_NAME);
109118
trace.record(START_TIME, DURATION);
110119
clock.tick(1);
111120

112121
expect(addToQueueStub).not.to.be.called;
113122
});
123+
124+
it('ascertains that the max number of customMetric allowed is 32', () => {
125+
const EXPECTED_TRACE_MESSAGE =
126+
`{` +
127+
WEBAPP_INFO +
128+
`,"trace_metric":{"name":"${TRACE_NAME}","is_auto":false,\
129+
"client_start_time_us":${START_TIME * 1000},"duration_us":${DURATION * 1000},\
130+
"counters":{"counter1":1,"counter2":2,"counter3":3,"counter4":4,"counter5":5,"counter6":6,\
131+
"counter7":7,"counter8":8,"counter9":9,"counter10":10,"counter11":11,"counter12":12,\
132+
"counter13":13,"counter14":14,"counter15":15,"counter16":16,"counter17":17,"counter18":18,\
133+
"counter19":19,"counter20":20,"counter21":21,"counter22":22,"counter23":23,"counter24":24,\
134+
"counter25":25,"counter26":26,"counter27":27,"counter28":28,"counter29":29,"counter30":30,\
135+
"counter31":31,"counter32":32}}}`;
136+
getIidStub.returns(IID);
137+
stub(attributeUtils, 'getVisibilityState').returns(VISIBILITY_STATE);
138+
SettingsService.getInstance().loggingEnabled = true;
139+
SettingsService.getInstance().logTraceAfterSampling = true;
140+
const trace = new Trace(TRACE_NAME);
141+
for (let i = 1; i <= 32; i++) {
142+
trace.putMetric('counter' + i, i);
143+
}
144+
trace.record(START_TIME, DURATION);
145+
clock.tick(1);
146+
147+
expect(addToQueueStub).to.be.called;
148+
expect(addToQueueStub.getCall(0).args[0].message).to.be.equal(
149+
EXPECTED_TRACE_MESSAGE
150+
);
151+
});
152+
153+
it('ascertains that the max number of custom attributes allowed is 5', () => {
154+
const EXPECTED_TRACE_MESSAGE =
155+
`{` +
156+
WEBAPP_INFO +
157+
`,"trace_metric":{"name":"${TRACE_NAME}","is_auto":false,\
158+
"client_start_time_us":${START_TIME * 1000},"duration_us":${DURATION * 1000},\
159+
"custom_attributes":{"attr1":"val1","attr2":"val2","attr3":"val3","attr4":"val4","attr5":"val5"}}}`;
160+
getIidStub.returns(IID);
161+
stub(attributeUtils, 'getVisibilityState').returns(VISIBILITY_STATE);
162+
SettingsService.getInstance().loggingEnabled = true;
163+
SettingsService.getInstance().logTraceAfterSampling = true;
164+
const trace = new Trace(TRACE_NAME);
165+
for (let i = 1; i <= 5; i++) {
166+
trace.putAttribute('attr' + i, 'val' + i);
167+
}
168+
trace.record(START_TIME, DURATION);
169+
clock.tick(1);
170+
171+
expect(addToQueueStub).to.be.called;
172+
expect(addToQueueStub.getCall(0).args[0].message).to.be.equal(
173+
EXPECTED_TRACE_MESSAGE
174+
);
175+
});
176+
});
177+
178+
describe('logPageLoadTrace', () => {
179+
it('creates, serializes and sends a page load trace to cc service', () => {
180+
const flooredStartTime = Math.floor(TIME_ORIGIN * 1000);
181+
const EXPECTED_TRACE_MESSAGE = `{"application_info":{"google_app_id":"${APP_ID}",\
182+
"app_instance_id":"${IID}","web_app_info":{"sdk_version":"${SDK_VERSION}",\
183+
"page_url":"${PAGE_URL}","service_worker_status":${SERVICE_WORKER_STATUS},\
184+
"visibility_state":${
185+
attributeUtils.VisibilityState.VISIBLE
186+
},"effective_connection_type":${EFFECTIVE_CONNECTION_TYPE}},\
187+
"application_process_state":0},"trace_metric":{"name":"_wt_${PAGE_URL}","is_auto":true,\
188+
"client_start_time_us":${flooredStartTime},"duration_us":${DURATION * 1000},\
189+
"counters":{"domInteractive":10000,"domContentLoadedEventEnd":20000,"loadEventEnd":10000,\
190+
"_fp":40000,"_fcp":50000,"_fid":90000}}}`;
191+
getIidStub.returns(IID);
192+
SettingsService.getInstance().loggingEnabled = true;
193+
SettingsService.getInstance().logTraceAfterSampling = true;
194+
195+
stub(attributeUtils, 'getVisibilityState').returns(
196+
attributeUtils.VisibilityState.VISIBLE
197+
);
198+
199+
const navigationTiming: PerformanceNavigationTiming = {
200+
domComplete: 100,
201+
domContentLoadedEventEnd: 20,
202+
domContentLoadedEventStart: 10,
203+
domInteractive: 10,
204+
loadEventEnd: 10,
205+
loadEventStart: 10,
206+
redirectCount: 10,
207+
type: 'navigate',
208+
unloadEventEnd: 10,
209+
unloadEventStart: 10,
210+
duration: DURATION
211+
} as PerformanceNavigationTiming;
212+
213+
const navigationTimings: PerformanceNavigationTiming[] = [
214+
navigationTiming
215+
];
216+
217+
const firstPaint: PerformanceEntry = {
218+
name: 'first-paint',
219+
startTime: 40,
220+
duration: 100,
221+
entryType: 'url',
222+
toJSON() {}
223+
};
224+
225+
const firstContentfulPaint: PerformanceEntry = {
226+
name: 'first-contentful-paint',
227+
startTime: 50,
228+
duration: 100,
229+
entryType: 'url',
230+
toJSON() {}
231+
};
232+
233+
const paintTimings: PerformanceEntry[] = [
234+
firstPaint,
235+
firstContentfulPaint
236+
];
237+
238+
Trace.createOobTrace(navigationTimings, paintTimings, 90);
239+
clock.tick(1);
240+
241+
expect(addToQueueStub).to.be.called;
242+
expect(addToQueueStub.getCall(0).args[0].message).to.be.equal(
243+
EXPECTED_TRACE_MESSAGE
244+
);
245+
});
114246
});
115247

116248
describe('logNetworkRequest', () => {
117-
it('creates, serializes and sends a network request to cc service', () => {
249+
it('creates, serializes and sends a network request to transport service', () => {
118250
const RESOURCE_PERFORMANCE_ENTRY: PerformanceResourceTiming = {
119251
connectEnd: 0,
120252
connectStart: 0,
@@ -147,17 +279,17 @@ describe('Performance Monitoring > perf_logger', () => {
147279
RESOURCE_PERFORMANCE_ENTRY.startTime) *
148280
1000
149281
);
150-
const EXPECTED_NETWORK_MESSAGE = `{"application_info":{"google_app_id":"${APP_ID}",\
151-
"app_instance_id":"${IID}","web_app_info":{"sdk_version":"${SDK_VERSION}",\
152-
"page_url":"${PAGE_URL}","service_worker_status":${SERVICE_WORKER_STATUS},\
153-
"visibility_state":${VISIBILITY_STATE},"effective_connection_type":${EFFECTIVE_CONNECTION_TYPE}},\
154-
"application_process_state":0},\
282+
const EXPECTED_NETWORK_MESSAGE =
283+
`{` +
284+
WEBAPP_INFO +
285+
`,\
155286
"network_request_metric":{"url":"${RESOURCE_PERFORMANCE_ENTRY.name}",\
156287
"http_method":0,"http_response_code":200,\
157288
"response_payload_bytes":${RESOURCE_PERFORMANCE_ENTRY.transferSize},\
158289
"client_start_time_us":${START_TIME},\
159290
"time_to_response_completed_us":${TIME_TO_RESPONSE_COMPLETED}}}`;
160291
getIidStub.returns(IID);
292+
stub(attributeUtils, 'getVisibilityState').returns(VISIBILITY_STATE);
161293
SettingsService.getInstance().loggingEnabled = true;
162294
SettingsService.getInstance().logNetworkAfterSampling = true;
163295
// Calls logNetworkRequest under the hood.

packages/performance/src/services/perf_logger.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ interface TraceMetric {
7979
is_auto: boolean;
8080
client_start_time_us: number;
8181
duration_us: number;
82-
counters?: Array<{ key: string; value: number }>;
83-
custom_attributes?: Array<{ key: string; value: string }>;
82+
counters?: { [key: string]: number };
83+
custom_attributes?: { [key: string]: string };
8484
}
8585

8686
/* eslint-enble camelcase */
@@ -201,11 +201,11 @@ function serializeTrace(trace: Trace): string {
201201
};
202202

203203
if (Object.keys(trace.counters).length !== 0) {
204-
traceMetric.counters = convertToKeyValueArray(trace.counters);
204+
traceMetric.counters = trace.counters;
205205
}
206206
const customAttributes = trace.getAttributes();
207207
if (Object.keys(customAttributes).length !== 0) {
208-
traceMetric.custom_attributes = convertToKeyValueArray(customAttributes);
208+
traceMetric.custom_attributes = customAttributes;
209209
}
210210

211211
const perfMetric: PerfTraceLog = {
@@ -229,13 +229,3 @@ function getApplicationInfo(): ApplicationInfo {
229229
application_process_state: 0
230230
};
231231
}
232-
233-
function convertToKeyValueArray<T>(obj: {
234-
[key: string]: T;
235-
}): Array<{
236-
key: string;
237-
value: T;
238-
}> {
239-
const keys = Object.keys(obj);
240-
return keys.map(key => ({ key, value: obj[key] }));
241-
}

packages/performance/src/services/transport_service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ interface ClientInfo {
4545
}
4646

4747
interface Log {
48-
source_extension_json: string;
48+
source_extension_json_proto3: string;
4949
event_time_ms: string;
5050
}
5151
/* eslint-enable camelcase */
@@ -79,8 +79,8 @@ function processQueue(timeOffset: number): void {
7979

8080
/* eslint-disable camelcase */
8181
// We will pass the JSON serialized event to the backend.
82-
const log_event = staged.map(evt => ({
83-
source_extension_json: evt.message,
82+
const log_event: Log[] = staged.map(evt => ({
83+
source_extension_json_proto3: evt.message,
8484
event_time_ms: String(evt.eventTime)
8585
}));
8686

0 commit comments

Comments
 (0)