Skip to content

Commit eaf1cea

Browse files
committed
promote network facts and metadata onto live frames
1 parent b57b8be commit eaf1cea

2 files changed

Lines changed: 71 additions & 0 deletions

File tree

‎lib/src/live/live_session_client.dart‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ class LiveSessionClient extends ChangeNotifier {
248248
/// a JSON string because it is on its way into a database, neither of which
249249
/// means anything to a browser rendering one row.
250250
Map<String, dynamic> _wireLog(LogEntry entry) {
251+
final metadata = entry.metadata;
251252
return {
252253
'level': entry.level.name,
253254
'message': entry.message,
@@ -256,6 +257,18 @@ class LiveSessionClient extends ChangeNotifier {
256257
if (entry.isNetworkCall) 'is_network_call': true,
257258
if (entry.requestId != null) 'request_id': entry.requestId,
258259
if (entry.callPhase != null) 'call_phase': entry.callPhase!.name,
260+
// The same promotion ingest does server-side, done here because a live
261+
// frame never passes through ingest. Without these the dashboard's
262+
// network rows have a phase and no verb, path or status to show.
263+
if (entry.isNetworkCall && metadata?['method'] != null) 'method': '${metadata!['method']}',
264+
if (entry.isNetworkCall && metadata?['url'] != null) 'url': '${metadata!['url']}',
265+
if (entry.isNetworkCall && metadata?['status_code'] is int)
266+
'status_code': metadata!['status_code'],
267+
// The whole metadata rides along on network calls only, for the live
268+
// inspector's headers and bodies. It was redacted at capture, so what is
269+
// in it is what the app agreed to send — and log rows do not carry it
270+
// because nothing on the logs pane reads it.
271+
if (entry.isNetworkCall && metadata != null) 'metadata': metadata,
259272
};
260273
}
261274

‎test/live_session_test.dart‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,64 @@ void main() {
215215
expect(DateTime.tryParse(logs.first['timestamp'] as String), isNotNull);
216216
});
217217

218+
test('a network call carries what the live inspector renders', () async {
219+
// Live frames never pass through ingest, so the promotion ingest does —
220+
// method, url, status_code out of the metadata — has to happen at the
221+
// socket. Without it every network row on the live screen has a phase
222+
// and nothing else to show.
223+
expect(await start('4K7Q2P'), isTrue);
224+
225+
LiveSessionClient.i.publish(LogEntry(
226+
level: LogLevel.debug,
227+
message: 'Network Response',
228+
sessionID: 'launch-1',
229+
isNetworkCall: true,
230+
requestId: 'req-1',
231+
callPhase: NetworkCallPhase.response,
232+
metadata: {
233+
'method': 'POST',
234+
'url': 'https://api.shop.dev/v2/pay',
235+
'status_code': 402,
236+
'body': {'error': 'card_declined'},
237+
},
238+
));
239+
240+
await _until(() => frames.any((f) => (f['logs'] as List?)?.isNotEmpty ?? false));
241+
final log = frames
242+
.expand((f) => (f['logs'] as List? ?? const []).cast<Map<String, dynamic>>())
243+
.single;
244+
245+
expect(log['is_network_call'], isTrue);
246+
expect(log['request_id'], 'req-1');
247+
expect(log['call_phase'], 'response');
248+
expect(log['method'], 'POST');
249+
expect(log['url'], 'https://api.shop.dev/v2/pay');
250+
expect(log['status_code'], 402);
251+
// The whole metadata rides along for the inspector's bodies and headers.
252+
expect((log['metadata'] as Map)['body'], {'error': 'card_declined'});
253+
});
254+
255+
test('an ordinary log does not drag its metadata onto the wire', () async {
256+
expect(await start('4K7Q2P'), isTrue);
257+
258+
LiveSessionClient.i.publish(LogEntry(
259+
level: LogLevel.info,
260+
message: 'cart viewed',
261+
sessionID: 'launch-1',
262+
metadata: {'items': 3},
263+
));
264+
265+
await _until(() => frames.any((f) => (f['logs'] as List?)?.isNotEmpty ?? false));
266+
final log = frames
267+
.expand((f) => (f['logs'] as List? ?? const []).cast<Map<String, dynamic>>())
268+
.single;
269+
270+
// Nothing on the logs pane reads it, and a chatty app's metadata would
271+
// be pure frame weight on every single row.
272+
expect(log.containsKey('metadata'), isFalse);
273+
expect(log.containsKey('method'), isFalse);
274+
});
275+
218276
test('nothing is sent once the session is stopped', () async {
219277
expect(await start('4K7Q2P'), isTrue);
220278
await LiveSessionClient.i.stop();

0 commit comments

Comments
 (0)