基础库
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

363 linhas
8.8 KiB

  1. library let_log;
  2. import 'dart:convert';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. part 'log_widget.dart';
  6. part 'net_widget.dart';
  7. enum _Type { log, debug, warn, error }
  8. List<String> _printNames = ["😄", "🐛", "❗", "❌", "⬆️", "⬇️"];
  9. List<String> _tabNames = ["[Log]", "[Debug]", "[Warn]", "[Error]"];
  10. final RegExp _tabReg = RegExp(r"\[|\]");
  11. String _getTabName(int index) {
  12. return _tabNames[index].replaceAll(_tabReg, "");
  13. }
  14. class _Config {
  15. /// Whether to display the log in reverse order
  16. bool reverse = false;
  17. /// Whether or not to print logs in the ide
  18. bool printNet = true;
  19. /// Whether or not to print net logs in the ide
  20. bool printLog = true;
  21. /// Maximum number of logs, larger than this number, will be cleaned up, default value 500
  22. int maxLimit = 500;
  23. /// Set the names in ide print.
  24. void setPrintNames({
  25. String log,
  26. String debug,
  27. String warn,
  28. String error,
  29. String request,
  30. String response,
  31. }) {
  32. _printNames = [
  33. log ?? "[Log]",
  34. debug ?? "[Debug]",
  35. warn ?? "[Warn]",
  36. error ?? "[Error]",
  37. request ?? "[Req]",
  38. response ?? "[Res]",
  39. ];
  40. }
  41. /// Set the names in the app.
  42. void setTabNames({
  43. String log,
  44. String debug,
  45. String warn,
  46. String error,
  47. String request,
  48. String response,
  49. }) {
  50. _tabNames = [
  51. log ?? "[Log]",
  52. debug ?? "[Debug]",
  53. warn ?? "[Warn]",
  54. error ?? "[Error]",
  55. ];
  56. }
  57. }
  58. class Logger extends StatelessWidget {
  59. @override
  60. Widget build(BuildContext context) {
  61. return DefaultTabController(
  62. length: 2,
  63. child: Scaffold(
  64. appBar: AppBar(
  65. title: const TabBar(
  66. tabs: [
  67. Tab(child: Text("Log")),
  68. Tab(child: Text("Net")),
  69. ],
  70. ),
  71. elevation: 0,
  72. ),
  73. body: const TabBarView(
  74. children: [
  75. LogWidget(),
  76. NetWidget(),
  77. ],
  78. ),
  79. ),
  80. );
  81. }
  82. static bool enabled = true;
  83. static _Config config = _Config();
  84. /// Logging
  85. static void log(Object message, [Object detail]) {
  86. if (enabled) _Log.add(_Type.log, message, detail);
  87. }
  88. /// Record debug information
  89. static void debug(Object message, [Object detail]) {
  90. if (enabled) _Log.add(_Type.debug, message, detail);
  91. }
  92. /// Record warnning information
  93. static void warn(Object message, [Object detail]) {
  94. if (enabled) _Log.add(_Type.warn, message, detail);
  95. }
  96. /// Record error information
  97. static void error(Object message, [Object detail]) {
  98. if (enabled) _Log.add(_Type.error, message, detail);
  99. }
  100. /// Start recording time
  101. static void time(Object key) {
  102. assert(key != null);
  103. if (enabled) _Log.time(key);
  104. }
  105. /// End of record time
  106. static void endTime(Object key) {
  107. assert(key != null);
  108. if (enabled) _Log.endTime(key);
  109. }
  110. /// Clearance log
  111. static void clear() {
  112. _Log.clear();
  113. }
  114. /// Recording network information
  115. static void net(String api,
  116. {String type = "请求接口", int status = 100, Object data}) {
  117. assert(api != null);
  118. if (enabled) _Net.request(api, type, status, data);
  119. }
  120. /// End of record network information, with statistics on duration and size.
  121. static void endNet(String api,
  122. {int status = 200, Object data, Object headers, String type}) {
  123. assert(api != null);
  124. if (enabled) _Net.response(api, status, data, headers, type);
  125. }
  126. }
  127. class _Log {
  128. static final List<_Log> list = [];
  129. static final ValueNotifier<int> length = ValueNotifier(0);
  130. static final Map<Object, Object> _map = {};
  131. final _Type type;
  132. final String message;
  133. final String detail;
  134. final DateTime start;
  135. const _Log({this.type, this.message, this.detail, this.start});
  136. String get typeName {
  137. return _printNames[type.index];
  138. }
  139. String get tabName {
  140. return _tabNames[type.index];
  141. }
  142. bool contains(String keyword) {
  143. if (keyword.isEmpty) return true;
  144. return message != null && message.contains(keyword) ||
  145. detail != null && detail.contains(keyword);
  146. }
  147. @override
  148. String toString() {
  149. final StringBuffer sb = StringBuffer();
  150. sb.writeln("Message: $message");
  151. sb.writeln("Time: $start");
  152. if (detail != null && detail.length > 100) {
  153. sb.writeln("Detail: ");
  154. sb.writeln(detail);
  155. } else {
  156. sb.writeln("Detail: $detail");
  157. }
  158. return sb.toString();
  159. }
  160. static void add(_Type type, Object value, Object detail) {
  161. final log = _Log(
  162. type: type,
  163. message: value?.toString(),
  164. detail: detail?.toString(),
  165. start: DateTime.now(),
  166. );
  167. list.add(log);
  168. _clearWhenTooMuch();
  169. length.value++;
  170. if (Logger.config.printLog) {
  171. debugPrint(
  172. "${log.typeName} ${log.message}${log.detail == null ? '' : '\n${log.detail}'}\n--------------------------------");
  173. }
  174. }
  175. static void _clearWhenTooMuch() {
  176. if (list.length > Logger.config.maxLimit) {
  177. list.removeRange(0, (Logger.config.maxLimit * 0.2).ceil());
  178. }
  179. }
  180. static void time(Object key) {
  181. _map[key] = DateTime.now();
  182. }
  183. static void endTime(Object key) {
  184. final data = _map[key];
  185. if (data != null) {
  186. _map.remove(key);
  187. final spend = DateTime.now().difference(data).inMilliseconds;
  188. _Log.add(_Type.log, '$key: $spend ms', null);
  189. }
  190. }
  191. static void clear() {
  192. list.clear();
  193. _map.clear();
  194. length.value = 0;
  195. }
  196. }
  197. class _Net extends ChangeNotifier {
  198. static const all = "All";
  199. static final List<_Net> list = [];
  200. static final ValueNotifier<int> length = ValueNotifier(0);
  201. static final Map<String, _Net> _map = {};
  202. static final List<String> types = [all];
  203. static final ValueNotifier<int> typeLength = ValueNotifier(1);
  204. final String api;
  205. final String req;
  206. final DateTime start;
  207. String type;
  208. int status = 100;
  209. int spend = 0;
  210. String res;
  211. String headers;
  212. bool showDetail = false;
  213. int _reqSize = -1;
  214. int _resSize = -1;
  215. _Net({
  216. this.api,
  217. this.type,
  218. this.req,
  219. this.headers,
  220. this.start,
  221. this.res,
  222. this.spend = 0,
  223. this.status = 100,
  224. });
  225. int getReqSize() {
  226. if (_reqSize > -1) return _reqSize;
  227. if (req != null && req.isNotEmpty) {
  228. try {
  229. return _reqSize = utf8.encode(req).length;
  230. } catch (e) {
  231. // print(e);
  232. }
  233. }
  234. return 0;
  235. }
  236. int getResSize() {
  237. if (_resSize > -1) return _resSize;
  238. if (res != null && res.isNotEmpty) {
  239. try {
  240. return _resSize = utf8.encode(res).length;
  241. } catch (e) {
  242. // print(e);
  243. }
  244. }
  245. return 0;
  246. }
  247. bool contains(String keyword) {
  248. if (keyword.isEmpty) return true;
  249. return api.contains(keyword) ||
  250. req != null && req.contains(keyword) ||
  251. res != null && res.contains(keyword);
  252. }
  253. @override
  254. String toString() {
  255. final StringBuffer sb = StringBuffer();
  256. sb.writeln("[$status] $api");
  257. sb.writeln("Start: $start");
  258. sb.writeln("Spend: $spend ms");
  259. sb.writeln("Headers: $headers");
  260. sb.writeln("Request: $req");
  261. sb.writeln("Response: $res");
  262. return sb.toString();
  263. }
  264. static void request(String api, String type, int status, Object data) {
  265. final net = _Net(
  266. api: api,
  267. type: type,
  268. status: status,
  269. req: data?.toString(),
  270. start: DateTime.now(),
  271. );
  272. list.add(net);
  273. _map[api] = net;
  274. if (type != null && type != "" && !types.contains(type)) {
  275. types.add(type);
  276. typeLength.value++;
  277. }
  278. _clearWhenTooMuch();
  279. length.value++;
  280. if (Logger.config.printNet) {
  281. debugPrint(
  282. "${_printNames[4]} ${type == null ? '' : '$type: '}${net.api}${net.req == null ? '' : '\n${_printNames[0]} 请求数据: ${net.req}'}\n--------------------------------");
  283. }
  284. }
  285. static void _clearWhenTooMuch() {
  286. if (list.length > Logger.config.maxLimit) {
  287. list.removeRange(0, (Logger.config.maxLimit * 0.2).ceil());
  288. }
  289. }
  290. static void response(
  291. String api, int status, Object data, Object headers, String type) {
  292. _Net net = _map[api];
  293. if (net != null) {
  294. _map.remove(net);
  295. net.spend = DateTime.now().difference(net.start).inMilliseconds;
  296. net.status = status;
  297. net.headers = headers?.toString();
  298. net.res = data?.toString();
  299. length.notifyListeners();
  300. } else {
  301. net = _Net(api: api, start: DateTime.now(), type: type);
  302. net.status = status;
  303. net.headers = headers?.toString();
  304. net.res = data?.toString();
  305. list.add(net);
  306. _clearWhenTooMuch();
  307. length.value++;
  308. }
  309. if (Logger.config.printNet) {
  310. debugPrint(
  311. "${_printNames[5]} ${net.type == null ? '' : '${net.type}: '}${net.api}${net.res == null ? '' : '\n${_printNames[0]} 响应数据: ${net.res}'}\nSpend: ${net.spend} ms\n--------------------------------");
  312. }
  313. }
  314. static void clear() {
  315. list.clear();
  316. _map.clear();
  317. length.value = 0;
  318. }
  319. }