debugout

主要用于日志检测脚本的调用

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/440535/1021754/debugout.js

  1. /*
  2.  
  3. debugout.js
  4. by @inorganik
  5. */
  6.  
  7. // save all the console.logs
  8. function debugout() {
  9. var self = this;
  10.  
  11. // OPTIONS
  12. self.realTimeLoggingOn = true; // log in real time (forwards to console.log)
  13. self.useTimestamps = false; // insert a timestamp in front of each log
  14. self.useLocalStorage = false; // store the output using window.localStorage() and continuously add to the same log each session
  15. self.recordLogs = true; // set to false after you're done debugging to avoid the log eating up memory
  16. self.autoTrim = true; // to avoid the log eating up potentially endless memory
  17. self.maxLines = 2500; // if autoTrim is true, this many most recent lines are saved
  18. self.tailNumLines = 100; // how many lines tail() will retrieve
  19. self.logFilename = 'debugout.txt'; // filename of log downloaded with downloadLog()
  20.  
  21. // vars
  22. self.depth = 0;
  23. self.parentSizes = [0];
  24. self.currentResult = '';
  25. self.startTime = new Date();
  26. self.output = '';
  27.  
  28. this.version = function() { return '0.5.0' }
  29.  
  30. /*
  31. USER METHODS
  32. */
  33. this.getLog = function() {
  34. var retrievalTime = new Date();
  35. // if recording is off, so dev knows why they don't have any logs
  36. if (!self.recordLogs) {
  37. self.log('[debugout.js] log recording is off.');
  38. }
  39. // if using local storage, get values
  40. if (self.useLocalStorage) {
  41. var saved = window.localStorage.getItem('debugout.js');
  42. if (saved) {
  43. saved = JSON.parse(saved);
  44. self.startTime = new Date(saved.startTime);
  45. self.output = saved.log;
  46. retrievalTime = new Date(saved.lastLog);
  47. }
  48. }
  49. return self.output
  50. + '\n---- Log retrieved: '+retrievalTime+' ----\n'
  51. + self.formatSessionDuration(self.startTime, retrievalTime);
  52. }
  53. // accepts optional number or uses the default for number of lines
  54. this.tail = function(numLines) {
  55. var numLines = numLines || self.tailLines;
  56. return self.trimLog(self.getLog(), numLines);
  57. }
  58. // accepts a string to search for
  59. this.search = function(string) {
  60. var lines = self.output.split('\n');
  61. var rgx = new RegExp(string);
  62. var matched = [];
  63. // can't use a simple Array.prototype.filter() here
  64. // because we need to add the line number
  65. for (var i = 0; i < lines.length; i++) {
  66. var addr = '['+i+'] ';
  67. if (lines[i].match(rgx)) {
  68. matched.push(addr + lines[i]);
  69. }
  70. }
  71. var result = matched.join('\n');
  72. if (result.length == 0) result = 'Nothing found for "'+string+'".';
  73. return result
  74. }
  75. // accepts the starting line and how many lines after the starting line you want
  76. this.getSlice = function(lineNumber, numLines) {
  77. var lines = self.output.split('\n');
  78. var segment = lines.slice(lineNumber, lineNumber + numLines);
  79. return segment.join('\n');
  80. }
  81. // immediately downloads the log - for desktop browser use
  82. this.downloadLog = function() {
  83. var file = "data:text/plain;charset=utf-8,";
  84. var logFile = self.getLog();
  85. var encoded = encodeURIComponent(logFile);
  86. file += encoded;
  87. var a = document.createElement('a');
  88. a.href = file;
  89. a.target = '_blank';
  90. a.download = self.logFilename;
  91. document.body.appendChild(a);
  92. a.click();
  93. a.remove();
  94. }
  95. // clears the log
  96. this.clear = function() {
  97. var clearTime = new Date();
  98. self.output = '---- Log cleared: '+clearTime+' ----\n';
  99. if (self.useLocalStorage) {
  100. // local storage
  101. var saveObject = {
  102. startTime: self.startTime,
  103. log: self.output,
  104. lastLog: clearTime
  105. }
  106. saveObject = JSON.stringify(saveObject);
  107. window.localStorage.setItem('debugout.js', saveObject);
  108. }
  109. if (self.realTimeLoggingOn) console.log('[debugout.js] clear()');
  110. }
  111. // records a log
  112. this.log = function(obj) {
  113. // log in real time
  114. if (self.realTimeLoggingOn) console.log(obj);
  115. // record log
  116. var type = self.determineType(obj);
  117. if (type != null && self.recordLogs) {
  118. var addition = self.formatType(type, obj);
  119. // timestamp, formatted for brevity
  120. if (self.useTimestamps) {
  121. var logTime = new Date();
  122. self.output += self.formatTimestamp(logTime);
  123. }
  124. self.output += addition+'\n';
  125. if (self.autoTrim) self.output = self.trimLog(self.output, self.maxLines);
  126. // local storage
  127. if (self.useLocalStorage) {
  128. var last = new Date();
  129. var saveObject = {
  130. startTime: self.startTime,
  131. log: self.output,
  132. lastLog: last
  133. }
  134. saveObject = JSON.stringify(saveObject);
  135. window.localStorage.setItem('debugout.js', saveObject);
  136. }
  137. }
  138. self.depth = 0;
  139. self.parentSizes = [0];
  140. self.currentResult = '';
  141. }
  142. /*
  143. METHODS FOR CONSTRUCTING THE LOG
  144. */
  145.  
  146. // like typeof but classifies objects of type 'object'
  147. // kept separate from formatType() so you can use at your convenience!
  148. this.determineType = function(object) {
  149. if (object != null) {
  150. var typeResult;
  151. var type = typeof object;
  152. if (type == 'object') {
  153. var len = object.length;
  154. if (len == null) {
  155. if (typeof object.getTime == 'function') {
  156. typeResult = 'Date';
  157. }
  158. else if (typeof object.test == 'function') {
  159. typeResult = 'RegExp';
  160. }
  161. else {
  162. typeResult = 'Object';
  163. }
  164. } else {
  165. typeResult = 'Array';
  166. }
  167. } else {
  168. typeResult = type;
  169. }
  170. return typeResult;
  171. } else {
  172. return null;
  173. }
  174. }
  175. // format type accordingly, recursively if necessary
  176. this.formatType = function(type, obj) {
  177. switch(type) {
  178. case 'Object' :
  179. self.currentResult += '{\n';
  180. self.depth++;
  181. self.parentSizes.push(self.objectSize(obj));
  182. var i = 0;
  183. for (var prop in obj) {
  184. self.currentResult += self.indentsForDepth(self.depth);
  185. self.currentResult += prop + ': ';
  186. var subtype = self.determineType(obj[prop]);
  187. var subresult = self.formatType(subtype, obj[prop]);
  188. if (subresult) {
  189. self.currentResult += subresult;
  190. if (i != self.parentSizes[self.depth]-1) self.currentResult += ',';
  191. self.currentResult += '\n';
  192. } else {
  193. if (i != self.parentSizes[self.depth]-1) self.currentResult += ',';
  194. self.currentResult += '\n';
  195. }
  196. i++;
  197. }
  198. self.depth--;
  199. self.parentSizes.pop();
  200. self.currentResult += self.indentsForDepth(self.depth);
  201. self.currentResult += '}';
  202. if (self.depth == 0) return self.currentResult;
  203. break;
  204. case 'Array' :
  205. self.currentResult += '[';
  206. self.depth++;
  207. self.parentSizes.push(obj.length);
  208. for (var i = 0; i < obj.length; i++) {
  209. var subtype = self.determineType(obj[i]);
  210. if (subtype == 'Object' || subtype == 'Array') self.currentResult += '\n' + self.indentsForDepth(self.depth);
  211. var subresult = self.formatType(subtype, obj[i]);
  212. if (subresult) {
  213. self.currentResult += subresult;
  214. if (i != self.parentSizes[self.depth]-1) self.currentResult += ', ';
  215. if (subtype == 'Array') self.currentResult += '\n';
  216. } else {
  217. if (i != self.parentSizes[self.depth]-1) self.currentResult += ', ';
  218. if (subtype != 'Object') self.currentResult += '\n';
  219. else if (i == self.parentSizes[self.depth]-1) self.currentResult += '\n';
  220. }
  221. }
  222. self.depth--;
  223. self.parentSizes.pop();
  224. self.currentResult += ']';
  225. if (self.depth == 0) return self.currentResult;
  226. break;
  227. case 'function' :
  228. obj += '';
  229. var lines = obj.split('\n');
  230. for (var i = 0; i < lines.length; i++) {
  231. if (lines[i].match(/\}/)) self.depth--;
  232. self.currentResult += self.indentsForDepth(self.depth);
  233. if (lines[i].match(/\{/)) self.depth++;
  234. self.currentResult += lines[i] + '\n';
  235. }
  236. return self.currentResult;
  237. break;
  238. case 'RegExp' :
  239. return '/'+obj.source+'/';
  240. break;
  241. case 'Date' :
  242. case 'string' :
  243. if (self.depth > 0 || obj.length == 0) {
  244. return '"'+obj+'"';
  245. } else {
  246. return obj;
  247. }
  248. case 'boolean' :
  249. if (obj) return 'true';
  250. else return 'false';
  251. case 'number' :
  252. return obj+'';
  253. break;
  254. }
  255. }
  256. this.indentsForDepth = function(depth) {
  257. var str = '';
  258. for (var i = 0; i < depth; i++) {
  259. str += '\t';
  260. }
  261. return str;
  262. }
  263. this.trimLog = function(log, maxLines) {
  264. var lines = log.split('\n');
  265. if (lines.length > maxLines) {
  266. lines = lines.slice(lines.length - maxLines);
  267. }
  268. return lines.join('\n');
  269. }
  270. this.lines = function() {
  271. return self.output.split('\n').length;
  272. }
  273. // calculate testing time
  274. this.formatSessionDuration = function(startTime, endTime) {
  275. var msec = endTime - startTime;
  276. var hh = Math.floor(msec / 1000 / 60 / 60);
  277. var hrs = ('0' + hh).slice(-2);
  278. msec -= hh * 1000 * 60 * 60;
  279. var mm = Math.floor(msec / 1000 / 60);
  280. var mins = ('0' + mm).slice(-2);
  281. msec -= mm * 1000 * 60;
  282. var ss = Math.floor(msec / 1000);
  283. var secs = ('0' + ss).slice(-2);
  284. msec -= ss * 1000;
  285. return '---- Session duration: '+hrs+':'+mins+':'+secs+' ----'
  286. }
  287. this.formatTimestamp = function(timestamp) {
  288. var year = timestamp.getFullYear();
  289. var date = timestamp.getDate();
  290. var month = ('0' + (timestamp.getMonth() +1)).slice(-2);
  291. var hrs = Number(timestamp.getHours());
  292. var mins = ('0' + timestamp.getMinutes()).slice(-2);
  293. var secs = ('0' + timestamp.getSeconds()).slice(-2);
  294. return '['+ year + '-' + month + '-' + date + ' ' + hrs + ':' + mins + ':'+secs + ']: ';
  295. }
  296. this.objectSize = function(obj) {
  297. var size = 0, key;
  298. for (key in obj) {
  299. if (obj.hasOwnProperty(key)) size++;
  300. }
  301. return size;
  302. }
  303.  
  304. /*
  305. START/RESUME LOG
  306. */
  307. if (self.useLocalStorage) {
  308. var saved = window.localStorage.getItem('debugout.js');
  309. if (saved) {
  310. saved = JSON.parse(saved);
  311. self.output = saved.log;
  312. var start = new Date(saved.startTime);
  313. var end = new Date(saved.lastLog);
  314. self.output += '\n---- Session end: '+saved.lastLog+' ----\n';
  315. self.output += self.formatSessionDuration(start, end);
  316. self.output += '\n\n';
  317. }
  318. }
  319. self.output += '---- Session started: '+self.startTime+' ----\n\n';
  320. }