debug.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Licensed Materials - Property of IBM
  2. //
  3. // IBM Cognos Products: pps
  4. //
  5. // (C) Copyright IBM Corp. 2005, 2017
  6. //
  7. // US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  8. // JS Debug Library (optional)
  9. // The inclusion of debug.js is done based on options in the PPSRoot.cfx file. There are also a few configuration options which are activated by adding settings appropriately. In order to enable the debugger, simply add a sub-tree to the PWQ section of the PPSRoot.cfx.
  10. //
  11. // <JavaScript Debugging="IN,,1" DebugFontSize="IN,,3" DebugAppendOutput="IN,Y,0"/>
  12. //
  13. // Debugging: Boolean value which enables/disables the debugger.
  14. // DebugFontSize: Integer value which controls the size of the font in the debugger window.
  15. // DebugAppendOutput: Boolean value which allows the output of each "run" to be appended to the end of the window.
  16. //
  17. // Available functions
  18. // The debugger is a singleton object represented by the pdb variable. In init.js, there is a function named initDebug() which creates a new Debugger object, if it is available. This function is also a good place to setup function and object traces.
  19. //
  20. // pdb.traceFunction(context, functionName);
  21. // pdb.traceObject(context, objectName);
  22. // where context is the execution context of the function/object (for global functions, the execution context is "window")
  23. // functionName/objectName is the name of the function/object
  24. //
  25. // These two functions will mark the beginning and end of a function (all member functions for an object), the return value of the function and the time (in ms) it took for the function to execute. These functions should be called within the initDebug() function in order to setup the traces at the beginning of an execution run.
  26. //
  27. // pdb.dumpArguments(arguments);
  28. // pdb.dumpObject(obj);
  29. // pdb.out("string");
  30. //
  31. // The first two methods dump either the arguments of a function (identified by the keyword arguments), or the member variables of an object. The third is the equivalent of a printf, simply dumping the string to the output window.
  32. function Debugger () {
  33. //Member assignment...
  34. this.debugWindowString = 'open("", "debugWindow", "height=400,left=10,top=10,width=600,location=no,menubar=no,scrollbars=yes,resizable=yes,status=no,toolbar=no")';
  35. this.debugWin = eval(this.debugWindowString);
  36. this.maxDebugLength = 100;
  37. this.startTime = new Date();
  38. this.stack = new Array();
  39. this.execprofile = new Array();
  40. this.action = "";
  41. this.lastCaller = "";
  42. this.dumpObjects = true;
  43. this.appendOutput = false;
  44. var dbgAppend = topparent.getGlobal("jsDebugAppendOutput");
  45. if (typeof dbgAppend != "undefined")
  46. this.appendOutput = dbgAppend;
  47. this.fontSize = 1;
  48. var dbgFont = topparent.getGlobal("jsDebugFontSize");
  49. if (typeof dbgFont != "undefined")
  50. this.fontSize = dbgFont;
  51. if (!this.appendOutput)
  52. {
  53. this.debugWin.document.close();
  54. this.debugWin.document.open();
  55. }
  56. if (!this.debugWin.document.title || this.debugWin.document.closed)
  57. {
  58. this.debugWin.document.write("<HTML><HEAD><TITLE>PPWeb Debug</TITLE></HEAD><BODY>");
  59. this.debugWin.document.write("<FONT SIZE=" + this.fontSize + "><B>*** Start ***</B><BR>");
  60. }
  61. else
  62. {
  63. this.debugWin.document.write("<BR><B>*** Start ***</B><BR>");
  64. }
  65. }
  66. Debugger.prototype.out = function () {
  67. // this is a variable argument function used to write to the debug window
  68. // suitable calls:
  69. //
  70. // pdb.out("This is a message") >> simply prints the message...
  71. // pdb.out("Test", action /*push, pop*/) >> prints the message and verifies stack for indentation
  72. var msg = "";
  73. var numArgs = arguments.length;
  74. if (numArgs <= 0) {
  75. return;
  76. }
  77. if (arguments.length == 2)
  78. {
  79. //must be from a callback function wrapper...
  80. //if it's not nested, then print it on the same line...
  81. var caller = arguments[1];
  82. var action = this.action;
  83. if (action == "push")
  84. msg += "<br>";
  85. else if (action == "pop" && caller != this.lastCaller)
  86. msg += "<br>";
  87. this.lastCaller = caller;
  88. }
  89. else
  90. {
  91. //not from a function/object wrapper...simply a message dump
  92. msg += "<br>";
  93. this.lastCaller = "";
  94. this.action = "msg";
  95. }
  96. if (msg.indexOf("<br>") == 0)
  97. {
  98. for (var j = 0; j < this.stack.length; j++)
  99. msg += "&nbsp;&nbsp;&nbsp;";
  100. }
  101. msg += arguments[0];
  102. if (msg) {
  103. this.debugWin.document.write(msg);
  104. }
  105. }
  106. Debugger.prototype.dumpArguments = function (obj) {
  107. this.out(this.dumpArgs(obj));
  108. }
  109. Debugger.prototype.dumpArgs = function (args) {
  110. var result = "";
  111. for (var i = 0; i < args.length; i++)
  112. {
  113. var arg = args[i];
  114. var argType = typeof arg;
  115. if (argType == "string" || argType == "number")
  116. {
  117. result += arg;
  118. }
  119. else if (argType == "object")
  120. {
  121. if (this.dumpObjects)
  122. {
  123. result += this.dumpObj(arg);
  124. }
  125. else
  126. result += arg;
  127. }
  128. else
  129. {
  130. result += "<unknown function parameter>";
  131. }
  132. if (i+1 < args.length)
  133. result += ", ";
  134. }
  135. return result;
  136. }
  137. Debugger.prototype.dumpObject = function (obj) {
  138. this.out(this.dumpObj(obj));
  139. }
  140. Debugger.prototype.dumpObj = function (obj) {
  141. var result = this.getObjectName( obj ) + "<br> { <br>";
  142. for (var prop in obj)
  143. {
  144. if (typeof prop != "function")
  145. result += prop + "=" + obj[prop] + "<br>";
  146. }
  147. result += " }; <br>";
  148. return result;
  149. }
  150. Debugger.prototype.getObjectName = function (obj) {
  151. if (typeof obj.constructor == "undefined")
  152. return "Object";
  153. return this.getFunctionName( obj.constructor );
  154. }
  155. Debugger.prototype.getFunctionName = function (funcref) {
  156. if (!funcref)
  157. return '';
  158. if (funcref.name)
  159. return funcref.name;
  160. var name = funcref + '';
  161. name = name.substring(name.indexOf(' ') + 1, name.indexOf('('));
  162. funcref.name = name;
  163. return name;
  164. }
  165. Debugger.prototype.createFunctionWrapper = function (scopename, funcname, precall, postcall)
  166. {
  167. var wrappedfunc;
  168. var scopeobject = eval(scopename);
  169. var funcref = scopeobject[funcname];
  170. scopeobject['xbDebug_orig_' + funcname] = funcref;
  171. wrappedfunc = function ()
  172. {
  173. var rv;
  174. precall(scopename, funcname, arguments);
  175. rv = funcref.apply(scopeobject, arguments);
  176. postcall(scopename, funcname, arguments, rv);
  177. return rv;
  178. };
  179. if (typeof(funcref.constructor) != 'undefined')
  180. wrappedfunc.constructor = funcref.constuctor;
  181. if (typeof(funcref.prototype) != 'undefined')
  182. wrappedfunc.prototype = funcref.prototype;
  183. scopeobject[funcname] = wrappedfunc;
  184. }
  185. Debugger.prototype.createMethodWrapper = function (contextname, classname, methodname, precall, postcall)
  186. {
  187. var context = eval(contextname);
  188. var methodref = context[classname].prototype[methodname];
  189. context[classname].prototype['xbDebug_orig_' + methodname] = methodref;
  190. var wrappedmethod = function ()
  191. {
  192. var rv;
  193. // eval 'this' at method run time to pick up reference to the object's instance
  194. var thisref = eval('this');
  195. // eval 'arguments' at method run time to pick up method's arguments
  196. var argsref = arguments;
  197. precall(contextname + '.' + classname, methodname, argsref);
  198. rv = methodref.apply(thisref, argsref);
  199. postcall(contextname + '.' + classname, methodname, argsref, rv);
  200. return rv;
  201. };
  202. return wrappedmethod;
  203. }
  204. Debugger.prototype.traceBefore = function (scopename, funcname, funcarguments)
  205. {
  206. var i;
  207. var s = '';
  208. var name = scopename + '.' + funcname;
  209. var profile = pdb.execprofile[name];
  210. if (!profile)
  211. profile = pdb.execprofile[name] = { started: 0, time: 0, count: 0 };
  212. var s = name + '(' + pdb.storeAsString(funcarguments) + ')';
  213. pdb.action = "push";
  214. pdb.out(s, name);
  215. pdb.stack.push(name);
  216. profile.started = (new Date()).getTime();
  217. }
  218. Debugger.prototype.traceAfter = function (scopename, funcname, funcarguments, rv)
  219. {
  220. var i;
  221. var s = '';
  222. var name = scopename + '.' + funcname;
  223. var execprofile = pdb.execprofile[name];
  224. if (!execprofile)
  225. pdb.out('TraceAfter: execprofile not created for ' + name);
  226. else if (execprofile.started == 0)
  227. pdb.out('TraceAfter: execprofile.started == 0 for ' + name);
  228. else
  229. {
  230. execprofile.time = (new Date()).getTime() - execprofile.started;
  231. execprofile.count++;
  232. execprofile.started = 0;
  233. }
  234. pdb.stack.pop();
  235. pdb.action = "pop";
  236. var s = " returned: " + rv + ", execution time: " + execprofile.time;
  237. pdb.out(s, name);
  238. }
  239. Debugger.prototype.traceFunction = function (scopename, funcname)
  240. {
  241. this.createFunctionWrapper(scopename, funcname, this.traceBefore, this.traceAfter);
  242. }
  243. Debugger.prototype.traceObject = function (contextname, classname)
  244. {
  245. var classref = eval(contextname + '.' + classname);
  246. var p;
  247. var sp;
  248. if (!classref || !classref.prototype)
  249. return;
  250. for (p in classref.prototype)
  251. {
  252. sp = p;
  253. if (typeof(classref.prototype[sp]) == 'function' && (sp).indexOf('xbDebug_orig') == -1)
  254. {
  255. classref.prototype[sp] = this.createMethodWrapper(contextname, classname, sp, this.traceBefore, this.traceAfter);
  256. }
  257. }
  258. }
  259. Debugger.prototype.dumpProfile = function ()
  260. {
  261. var p;
  262. var execprofile;
  263. var avg;
  264. for (p in this.execprofile)
  265. {
  266. execprofile = this.execprofile[p];
  267. avg = Math.round ( 100 * execprofile.time/execprofile.count) /100;
  268. this.out('Execution profile ' + p + ' called ' + execprofile.count + ' times. Total time=' + execprofile.time + 'ms. Avg Time=' + avg + 'ms.');
  269. }
  270. }
  271. Debugger.prototype.storeAsString = function (obj)
  272. {
  273. var argType = typeof obj;
  274. var msg = "";
  275. if (argType == "string")
  276. {
  277. msg = obj;
  278. }
  279. else if (argType == "object")
  280. {
  281. if (obj.constructor == "Array" || typeof obj.length != undefined)
  282. {
  283. for (var i = 0; i < obj.length; i++)
  284. {
  285. msg += obj[i]
  286. if (i+1 < obj.length)
  287. msg += ", ";
  288. }
  289. }
  290. else
  291. {
  292. msg = pdb.dumpObj(obj);
  293. }
  294. }
  295. return msg;
  296. }