基础库
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 

370 řádky
9.0 KiB

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