Tracing.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. var Class = require('./Class');
  2. var Trace = require('./Trace');
  3. var perfNow = require('./perfNow');
  4. var extend = require('./extend');
  5. var isNode = require('./isNode');
  6. var Stack = require('./Stack');
  7. var map = require('./map');
  8. var trim = require('./trim');
  9. var isEmpty = require('./isEmpty');
  10. var intersect = require('./intersect');
  11. var convertBase = require('./convertBase');
  12. var defPid = 0;
  13. var defTid = 0;
  14. var id = 0;
  15. if (isNode) {
  16. defPid = process.pid;
  17. try {
  18. defTid = eval('require')('worker_threads').threadId;
  19. } catch (e) {}
  20. }
  21. exports = Class({
  22. initialize: function Tracing() {
  23. var _ref =
  24. arguments.length > 0 && arguments[0] !== undefined
  25. ? arguments[0]
  26. : {},
  27. _ref$pid = _ref.pid,
  28. pid = _ref$pid === void 0 ? defPid : _ref$pid,
  29. _ref$tid = _ref.tid,
  30. tid = _ref$tid === void 0 ? defTid : _ref$tid,
  31. _ref$processName = _ref.processName,
  32. processName =
  33. _ref$processName === void 0 ? 'Process' : _ref$processName,
  34. _ref$threadName = _ref.threadName,
  35. threadName =
  36. _ref$threadName === void 0 ? 'Thread' : _ref$threadName;
  37. this._pid = pid;
  38. this._tid = tid;
  39. this._processName = processName;
  40. this._threadName = threadName;
  41. },
  42. start: function() {
  43. var cat =
  44. arguments.length > 0 && arguments[0] !== undefined
  45. ? arguments[0]
  46. : '';
  47. this._targetCat = processCat(cat);
  48. if (!isEmpty(this._targetCat)) {
  49. this._targetCat.push('__metadata');
  50. }
  51. this._traceEventStack = new Stack();
  52. this._asyncEventMap = {};
  53. this._trace = new Trace();
  54. this.metadata(
  55. 'process_name',
  56. {
  57. name: this._processName
  58. },
  59. {
  60. tid: 0,
  61. ts: 0
  62. }
  63. );
  64. this.metadata(
  65. 'thread_name',
  66. {
  67. name: this._threadName
  68. },
  69. {
  70. ts: 0
  71. }
  72. );
  73. },
  74. stop: function() {
  75. var trace = this._trace;
  76. if (!trace) {
  77. throw Error('Need to call start first');
  78. }
  79. delete this._targetCat;
  80. delete this._traceEventStack;
  81. delete this._asyncEventMap;
  82. delete this._trace;
  83. return trace.toJSON();
  84. },
  85. metadata: function(name, args, extra) {
  86. this._addEvent('__metadata', name, Phase.Metadata, args, extra);
  87. },
  88. begin: function(cat, name) {
  89. var args =
  90. arguments.length > 2 && arguments[2] !== undefined
  91. ? arguments[2]
  92. : {};
  93. if (!this._traceEventStack) {
  94. return;
  95. }
  96. this._traceEventStack.push({
  97. cat: cat,
  98. name: name,
  99. args: args,
  100. ts: this._getCurTs()
  101. });
  102. },
  103. end: function(args) {
  104. if (!this._traceEventStack) {
  105. return;
  106. }
  107. var beginEvent = this._traceEventStack.pop();
  108. if (!beginEvent) {
  109. throw Error('Need to call begin first');
  110. }
  111. var cat = beginEvent.cat,
  112. name = beginEvent.name,
  113. ts = beginEvent.ts;
  114. args = extend(beginEvent.args, args);
  115. this._addEvent(cat, name, Phase.Complete, args, {
  116. dur: this._getCurTs() - ts,
  117. ts: ts
  118. });
  119. },
  120. asyncBegin: function(cat, name) {
  121. var id =
  122. arguments.length > 2 && arguments[2] !== undefined
  123. ? arguments[2]
  124. : this.id();
  125. var args =
  126. arguments.length > 3 && arguments[3] !== undefined
  127. ? arguments[3]
  128. : {};
  129. if (!this._asyncEventMap) {
  130. return id;
  131. }
  132. this._asyncEventMap[id] = {
  133. cat: cat,
  134. name: name
  135. };
  136. this._addEvent(cat, name, Phase.NestableAsyncBegin, args, {
  137. id: id
  138. });
  139. return id;
  140. },
  141. asyncEnd: function(id) {
  142. var args =
  143. arguments.length > 1 && arguments[1] !== undefined
  144. ? arguments[1]
  145. : {};
  146. if (!this._asyncEventMap) {
  147. return;
  148. }
  149. var asyncBeginEvent = this._asyncEventMap[id];
  150. if (!asyncBeginEvent) {
  151. throw Error('Need to call async begin first');
  152. }
  153. var cat = asyncBeginEvent.cat,
  154. name = asyncBeginEvent.name;
  155. delete this._asyncEventMap[id];
  156. this._addEvent(cat, name, Phase.NestableAsyncEnd, args, {
  157. id: id
  158. });
  159. },
  160. instant: function(cat, name) {
  161. var scope =
  162. arguments.length > 2 && arguments[2] !== undefined
  163. ? arguments[2]
  164. : 't';
  165. var args = arguments.length > 3 ? arguments[3] : undefined;
  166. this._addEvent(cat, name, Phase.Instant, args, {
  167. s: scope
  168. });
  169. },
  170. id: function() {
  171. return '0x' + convertBase(id++, 10, 16);
  172. },
  173. _addEvent: function(cat, name, ph) {
  174. var args =
  175. arguments.length > 3 && arguments[3] !== undefined
  176. ? arguments[3]
  177. : {};
  178. var extra =
  179. arguments.length > 4 && arguments[4] !== undefined
  180. ? arguments[4]
  181. : {};
  182. if (!this._trace) {
  183. return;
  184. }
  185. var targetCat = this._targetCat;
  186. if (!isEmpty(targetCat)) {
  187. var catArr = processCat(cat);
  188. if (isEmpty(intersect(catArr, targetCat))) {
  189. return;
  190. }
  191. }
  192. var event = extend(
  193. {
  194. name: name,
  195. cat: cat,
  196. ph: ph,
  197. ts: this._getCurTs(),
  198. pid: this._pid,
  199. tid: this._tid,
  200. args: args
  201. },
  202. extra
  203. );
  204. this._trace.addEvent(event);
  205. },
  206. _getCurTs: function() {
  207. return Math.round(perfNow() * 1000);
  208. }
  209. });
  210. var Phase = {
  211. Begin: 'B',
  212. End: 'E',
  213. Complete: 'X',
  214. Instant: 'I',
  215. NestableAsyncBegin: 'b',
  216. NestableAsyncEnd: 'e',
  217. Metadata: 'M'
  218. };
  219. function processCat(cat) {
  220. cat = trim(cat);
  221. if (cat === '') {
  222. return [];
  223. }
  224. return map(cat.split(','), trim);
  225. }
  226. module.exports = exports;