Skip to content

Commit c83eeac

Browse files
nshahancommit-bot@chromium.org
authored andcommitted
[ddc] Avoid sending messages to console.debug
Calling `postEvent()` or `registerExtension()` from the dart:developer library now sends messages via global functions that can be set by the development infrastructure. For example, these hooks are set by package:dwds. When there is no debugger attached to the app, calling `postEvent()` or `registerExtension()` will produce a warning once each to avoid spamming the debug log with messages that do nothing. For backwards compatibility, when a debugger is attached but the hooks have not defined continue to write the events to the console.debug log. This support will be removed when package:dwds no longer reads from the log. dart-lang/webdev#1342 Change-Id: I126446666b5a85c68424546b8b1198d1582bba74 Issue: flutter/flutter#75225 Fixes: #36143 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202540 Commit-Queue: Nicholas Shahan <[email protected]> Reviewed-by: Gary Roumanis <[email protected]> Reviewed-by: Mark Zhou <[email protected]> Reviewed-by: Sigmund Cherem <[email protected]>
1 parent b5e7656 commit c83eeac

File tree

3 files changed

+511
-1
lines changed

3 files changed

+511
-1
lines changed

sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ import 'dart:async';
1111
import 'dart:convert' show json;
1212
import 'dart:isolate';
1313

14+
var _issuedPostEventWarning = false;
15+
var _issuedRegisterExtensionWarning = false;
16+
final _developerSupportWarning = 'from dart:developer is only supported in '
17+
'build/run/test environments where the developer event method hooks have '
18+
'been set.';
19+
20+
/// Returns `true` if the debugger service has been attached to the app.
21+
// TODO(46377) Update this check when we have a documented API for DDC apps.
22+
bool get _debuggerAttached => JS<bool>('!', r'!!#.$dwdsVersion', dart.global_);
23+
1424
@patch
1525
@ForceInline()
1626
bool debugger({bool when = true, String? message}) {
@@ -59,7 +69,24 @@ ServiceExtensionHandler? _lookupExtension(String method) {
5969

6070
@patch
6171
_registerExtension(String method, ServiceExtensionHandler handler) {
62-
_extensions[method] = handler;
72+
if (!_debuggerAttached) {
73+
if (!_issuedRegisterExtensionWarning) {
74+
var message = 'registerExtension() $_developerSupportWarning';
75+
JS('', 'console.warn(#)', message);
76+
_issuedRegisterExtensionWarning = true;
77+
}
78+
return;
79+
}
80+
// TODO(46377) Update this check when we have a documented API for DDC apps.
81+
if (JS<bool>('!', r'!!#.$emitRegisterEvent', dart.global_)) {
82+
_extensions[method] = handler;
83+
// See hooks assigned by package:dwds:
84+
// https://github.com/dart-lang/webdev/blob/de05cf9fbbfe088be74bb61df4a138289a94d902/dwds/web/client.dart#L223
85+
JS('', r'#.$emitRegisterEvent(#)', dart.global_, method);
86+
return;
87+
}
88+
// TODO(nshahan) Remove use of debug log after package:dwds removes support.
89+
// https://github.com/dart-lang/webdev/issues/1342
6390
JS('', 'console.debug("dart.developer.registerExtension", #)', method);
6491
}
6592

@@ -92,6 +119,23 @@ _invokeExtension(String methodName, String encodedJson) {
92119

93120
@patch
94121
void _postEvent(String eventKind, String eventData) {
122+
if (!_debuggerAttached) {
123+
if (!_issuedPostEventWarning) {
124+
var message = 'postEvent() $_developerSupportWarning';
125+
JS('', 'console.warn(#)', message);
126+
_issuedPostEventWarning = true;
127+
}
128+
return;
129+
}
130+
// TODO(46377) Update this check when we have a documented API for DDC apps.
131+
if (JS<bool>('!', r'!!#.$emitDebugEvent', dart.global_)) {
132+
// See hooks assigned by package:dwds:
133+
// https://github.com/dart-lang/webdev/blob/de05cf9fbbfe088be74bb61df4a138289a94d902/dwds/web/client.dart#L220
134+
JS('', r'#.$emitDebugEvent(#, #)', dart.global_, eventKind, eventData);
135+
return;
136+
}
137+
// TODO(nshahan) Remove use of debug log after package:dwds removes support.
138+
// https://github.com/dart-lang/webdev/issues/1342
95139
JS('', 'console.debug("dart.developer.postEvent", #, #)', eventKind,
96140
eventData);
97141
}
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
@JS()
6+
library developer_events_test;
7+
8+
import 'dart:developer'
9+
show postEvent, registerExtension, ServiceExtensionResponse;
10+
import 'dart:convert';
11+
12+
import 'package:js/js.dart';
13+
import 'package:expect/minitest.dart';
14+
15+
@JS(r'$emitDebugEvent')
16+
external set emitDebugEvent(void Function(String, String)? func);
17+
18+
@JS(r'$emitDebugEvent')
19+
external void Function(String, String)? get emitDebugEvent;
20+
21+
@JS(r'$emitRegisterEvent')
22+
external set emitRegisterEvent(void Function(String)? func);
23+
24+
@JS(r'$emitRegisterEvent')
25+
external void Function(String)? get emitRegisterEvent;
26+
27+
@JS(r'console.warn')
28+
external set consoleWarn(void Function(String) func);
29+
30+
@JS(r'console.warn')
31+
external void Function(String) get consoleWarn;
32+
33+
@JS(r'console.debug')
34+
external set consoleDebug(void Function(String) func);
35+
36+
@JS(r'console.debug')
37+
external void Function(String) get consoleDebug;
38+
39+
@JS(r'$dwdsVersion')
40+
external set dwdsVersion(String? s);
41+
42+
@JS(r'$dwdsVersion')
43+
external String? get dwdsVersion;
44+
45+
class _TestDebugEvent {
46+
final String kind;
47+
final String eventData;
48+
_TestDebugEvent(this.kind, this.eventData);
49+
}
50+
51+
void main() {
52+
testBackwardsCompatibility();
53+
testWarningMessages();
54+
testPostEvent();
55+
testRegisterExtension();
56+
}
57+
58+
/// Verify backwards compatibility for sending messages on the console.debug log
59+
/// in the chrome browser when the hooks have not been set.
60+
// TODO(nshahan) Remove testing of debug log after package:dwds removes support.
61+
// https://github.com/dart-lang/webdev/issues/1342`
62+
void testBackwardsCompatibility() {
63+
var consoleDebugLog = <List>[];
64+
var savedConsoleDebug = consoleDebug;
65+
var savedDwdsVersion = dwdsVersion;
66+
67+
try {
68+
// Patch our own console.debug function for testing.
69+
consoleDebug = allowInterop((arg1, [arg2, arg3]) => consoleDebugLog.add([
70+
arg1,
71+
if (arg2 != null) arg2,
72+
if (arg3 != null) arg3,
73+
]));
74+
// Provide a version to signal there is an attached debugger.
75+
dwdsVersion = '1.0.0-for-test';
76+
77+
// All post and register events should go to the console debug log.
78+
var data0 = {'key0': 'value0'};
79+
postEvent('kind0', data0);
80+
81+
expect(consoleDebugLog.single[0], 'dart.developer.postEvent');
82+
expect(consoleDebugLog.single[1], 'kind0');
83+
expect(consoleDebugLog.single[2], jsonEncode(data0));
84+
85+
var testHandler = (String s, Map<String, String> m) async =>
86+
ServiceExtensionResponse.result('test result');
87+
88+
registerExtension('ext.method0', testHandler);
89+
expect(consoleDebugLog.length, 2);
90+
expect(consoleDebugLog[1].first, 'dart.developer.registerExtension');
91+
expect(consoleDebugLog[1].last, 'ext.method0');
92+
93+
var data1 = {'key1': 'value1'};
94+
postEvent('kind1', data1);
95+
96+
expect(consoleDebugLog.length, 3);
97+
expect(consoleDebugLog[2][0], 'dart.developer.postEvent');
98+
expect(consoleDebugLog[2][1], 'kind1');
99+
expect(consoleDebugLog[2][2], jsonEncode(data1));
100+
101+
registerExtension('ext.method1', testHandler);
102+
expect(consoleDebugLog.length, 4);
103+
expect(consoleDebugLog[3].first, 'dart.developer.registerExtension');
104+
expect(consoleDebugLog[3].last, 'ext.method1');
105+
} finally {
106+
// Restore actual console.debug function.
107+
consoleDebug = savedConsoleDebug;
108+
dwdsVersion = savedDwdsVersion;
109+
}
110+
}
111+
112+
/// Verify that warning messages are printed on the first call of postEvent()
113+
/// and registerExtension() when the hooks are undefined.
114+
void testWarningMessages() {
115+
final consoleWarnLog = <String>[];
116+
var savedConsoleWarn = consoleWarn;
117+
try {
118+
// Patch our own console.warn function for testing.
119+
consoleWarn = allowInterop((String s) => consoleWarnLog.add(s));
120+
expect(consoleWarnLog.isEmpty, true);
121+
122+
var data0 = {'key0': 'value0'};
123+
postEvent('kind0', data0);
124+
125+
// A warning message was issued about calling `postEvent()` from
126+
// dart:developer.
127+
expect(consoleWarnLog.single.contains('postEvent() from dart:developer'),
128+
true);
129+
130+
postEvent('kind0', data0);
131+
var data1 = {'key1': 'value1'};
132+
postEvent('kind1', data1);
133+
134+
// A warning is only issued on the first call of `postEvent()`.
135+
expect(consoleWarnLog.length, 1);
136+
137+
consoleWarnLog.clear();
138+
139+
var testHandler = (String s, Map<String, String> m) async =>
140+
ServiceExtensionResponse.result('test result');
141+
142+
expect(consoleWarnLog.isEmpty, true);
143+
144+
registerExtension('ext.method0', testHandler);
145+
146+
// A warning message was issued about calling `registerExtension()` from
147+
// dart:developer.
148+
expect(
149+
consoleWarnLog.single
150+
.contains('registerExtension() from dart:developer'),
151+
true);
152+
153+
registerExtension('ext.method1', testHandler);
154+
registerExtension('ext.method2', testHandler);
155+
156+
// A warning is only issued on the first call of `registerExtension()`.
157+
expect(consoleWarnLog.length, 1);
158+
} finally {
159+
// Restore actual console.warn function.
160+
consoleWarn = savedConsoleWarn;
161+
}
162+
}
163+
164+
void testPostEvent() {
165+
final debugEventLog = <_TestDebugEvent>[];
166+
var savedEmitDebugEvent = emitDebugEvent;
167+
var savedDwdsVersion = dwdsVersion;
168+
169+
try {
170+
// Provide a test version of the $emitDebugEvent hook.
171+
emitDebugEvent = allowInterop((String kind, String eventData) {
172+
debugEventLog.add(_TestDebugEvent(kind, eventData));
173+
});
174+
// Provide a version to signal there is an attached debugger.
175+
dwdsVersion = '1.0.0-for-test';
176+
expect(debugEventLog.isEmpty, true);
177+
178+
var data0 = {'key0': 'value0'};
179+
postEvent('kind0', data0);
180+
181+
expect(debugEventLog.single.kind, 'kind0');
182+
expect(debugEventLog.single.eventData, jsonEncode(data0));
183+
184+
var data1 = {'key1': 'value1'};
185+
var data2 = {'key2': 'value2'};
186+
postEvent('kind1', data1);
187+
postEvent('kind2', data2);
188+
189+
expect(debugEventLog.length, 3);
190+
expect(debugEventLog[0].kind, 'kind0');
191+
expect(debugEventLog[0].eventData, jsonEncode(data0));
192+
expect(debugEventLog[1].kind, 'kind1');
193+
expect(debugEventLog[1].eventData, jsonEncode(data1));
194+
expect(debugEventLog[2].kind, 'kind2');
195+
expect(debugEventLog[2].eventData, jsonEncode(data2));
196+
} finally {
197+
emitDebugEvent = savedEmitDebugEvent;
198+
dwdsVersion = savedDwdsVersion;
199+
}
200+
}
201+
202+
void testRegisterExtension() {
203+
final registerEventLog = <String>[];
204+
var savedEmitRegisterEvent = emitRegisterEvent;
205+
var savedDwdsVersion = dwdsVersion;
206+
207+
try {
208+
// Provide a test version of the $emitRegisterEvent hook.
209+
emitRegisterEvent = allowInterop((String eventData) {
210+
registerEventLog.add(eventData);
211+
});
212+
// Provide a version to signal there is an attached debugger.
213+
dwdsVersion = '1.0.0-for-test';
214+
expect(registerEventLog.isEmpty, true);
215+
216+
var testHandler = (String s, Map<String, String> m) async =>
217+
ServiceExtensionResponse.result('test result');
218+
registerExtension('ext.method0', testHandler);
219+
220+
expect(registerEventLog.single, 'ext.method0');
221+
222+
registerExtension('ext.method1', testHandler);
223+
registerExtension('ext.method2', testHandler);
224+
225+
expect(registerEventLog.length, 3);
226+
expect(registerEventLog[0], 'ext.method0');
227+
expect(registerEventLog[1], 'ext.method1');
228+
expect(registerEventLog[2], 'ext.method2');
229+
} finally {
230+
emitRegisterEvent = savedEmitRegisterEvent;
231+
dwdsVersion = savedDwdsVersion;
232+
}
233+
}

0 commit comments

Comments
 (0)