[Javascript] creating a better console log

rene7705 rene7705 at gmail.com
Mon May 13 23:01:43 CDT 2013


update:
- freezing fixed
- setTimeout() and setInterval() gap solved <grin>
- plugged in file:line:column details via stacktracejs.com

yet to solve:
- crossing event handlers (although i'm probably going to go with each DOM
event creating a new userAction and thus a new stacktrace in
tracer.traced[userActionIdx])
- crossing callbacks from jQuery (which is going to be a bitch, I recon,
but I'll ask on the jQuery forums).
- fix the indentCount jumping around (bug?)

i'll take a nap to think the jQuery problem over, after posting this on
their forums as well of course...

latest code:

String.prototype.times = function(count) {
    return count < 1 ? '' : new Array(count + 1).join(this);
}

// Enable the passage of the 'this' object through the JavaScript timers
// thanks to
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#Callback_arguments
var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval;
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1,
argumentToPass2, etc. */) {
  var
  oThis = this,
  aArgs = Array.prototype.slice.call(arguments, 2),
  ua = tracer.findUA(arguments);
  if (ua) aArgs.ua = ua;
  return __nativeST__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};
window.setInterval = function (vCallback, nDelay /*, argumentToPass1,
argumentToPass2, etc. */) {
  var
  oThis = this,
  aArgs = Array.prototype.slice.call(arguments, 2),
  ua = tracer.findUA(arguments);
  if (ua) aArgs.ua = ua;
  return __nativeSI__(vCallback instanceof Function ? function () {
    vCallback.apply(oThis, aArgs);
  } : vCallback, nDelay);
};

var tracer = {
/*  object last modified : 14 May 2013, 05:53 CEST

 original code by
http://javascriptweblog.wordpress.com/2010/06/01/a-tracer-utility-in-2kb/
 modified by rene7705 at gmail.com with (among other things):
 (1) http://stackoverflow.com/a/15582432/2379929
 augmented by rene7705 at gmail with:
 http://stacktracejs.com/
 this code is now used in and offered as part of the web-framework at
http://fancywebapps.com
 (component name : hipLog, to be released later)
 problems remaining:
{1} crossing event handlers (although i'm probably going to go with each
DOM event creating a new userAction and thus a new stacktrace in
tracer.traced[userActionIdx])
 {2} crossing callbacks from jQuery (which is going to be a bitch, I recon,
but I'll ask on the jQuery forums).
 {3} fix the indentCount jumping around (bug?)
*/

     nativeCodeEx: /\[native code\]/,
    tracing: [],
    traced : [],
 userActions : [],
 findUA : function (arg) {
var p = arg;
 if (p.ua) return p.ua;

var callee = arg.callee;
 var caller = callee.caller;

 var stack = [callee];

 while (caller) {
    if (stack.indexOf(caller) < 0) {
        stack.push(caller);
        args = caller.arguments;
        callee = args.callee;
        caller = callee.caller;
    } else break;
}

 while (p = stack.shift()) {
if (p.arguments && p.arguments.ua) return p.arguments.ua;
 };
 return false;
},

    traceMe: function(func, methodName, path) {
    var traceOn = function() {
var
 ua = tracer.findUA(arguments),
startTime = +new Date;

if (!ua) {
 var
uaIdx = tracer.userActions.length,
 ua = tracer.userActions[uaIdx] = {
uaIdx : uaIdx,
 startTime : startTime,
path : path,
 stackLevel : 0
};
 tracer.traced[uaIdx] = [];
} else {
 var uaIdx = ua.uaIdx;
ua.stackLevel += 1;
 }
 arguments.ua = ua;
 var idx = tracer.traced[uaIdx].length;
tracer.traced[uaIdx][idx] = {
 path : path,
arguments : arguments
 };
 var result = func.apply(this, arguments);

 tracer.traced[uaIdx][idx].stacktrace = printStackTrace()
 tracer.traced[uaIdx][idx].result = result;
tracer.traced[uaIdx][idx].timed = new Date - startTime;
 tracer.traced[uaIdx][idx].stackLevel = ua.stackLevel;

 return result;
        };
        traceOn.traceOff = func;
        for (var prop in func) {
            traceOn[prop] = func[prop];
        }
        //console.log("tracing " + path);
        return traceOn;
    },

    traceAll: function(root, path, recurse) {
 if ((root == window) || !((typeof root == 'object') || (typeof root ==
'function'))) {return;}
        for (var key in root) {
            if ((root.hasOwnProperty(key)) && (root[key] != root)) {
                var thisObj = root[key];
                if (typeof thisObj == 'function') {
                    if ((this != root) && !thisObj.traceOff &&
!this.nativeCodeEx.test(thisObj)) {
                        root[key] = this.traceMe(root[key], key,
path+'.'+key);
                        this.tracing.push({obj:root,methodName:key,
path:path+'.'+key});
                    }
                }
                recurse && this.traceAll(thisObj, path+'.'+key, true);
             }
        }
    },

    untraceAll: function() {
        for (var i=0; i<this.tracing.length; ++i) {
            var thisTracing = this.tracing[i];
            thisTracing.obj[thisTracing.methodName] =
                thisTracing.obj[thisTracing.methodName].traceOff;
        }
        //console.log("tracing disabled");
        tracer.tracing = [];
    }
}

the printStackTrace() function (provides file:line:column info) comes from
stacktracejs.com (free)


On Mon, May 13, 2013 at 7:59 PM, rene7705 <rene7705 at gmail.com> wrote:

> i have another problem related to the previous one;
>
> in the javascript framework that I wrote (http://fancywebapps.com), it's
> entirely possible to have multiple user clicks and background animations
> being processed at the same time.
>
> the original tracer object could not handle this, so I built an
> improvement, one that unfortunately freezes the browser for reasons I don't
> understand yet. A page with my framework where you can find the thing
> freezing the browser is up at http://freegemini.me/sites/fancywebapps.com
>
> I would greatly appreciate any tips you have to offer.
>
> Here's the new code:
>
> String.prototype.times = function(count) {
>     return count < 1 ? '' : new Array(count + 1).join(this);
> }
>
> var tracer = {
>     nativeCodeEx: /\[native code\]/,
>     indentCount: -4,
>     tracing: [],
>      traced : [],
> userActions : [],
>  findUA : function (arg) {
>  var p = arg;
> while (p) {
>  if (p.ua) return p.ua;
>  if (p.arguments && p.arguments.ua) return p.arguments.ua;
>  if (typeof p.callee=='function') {
> p = p.callee;
>  } else if (typeof p.caller=='function') {
> p = p.caller;
>  } else return false;
> }
>  },
>
>     traceMe: function(func, methodName, path) {
>       var userAction;
>      var traceOn = function() {
> var startTime = +new Date;
>  var indentString = " ".times(tracer.indentCount += 4);
>  debugger;
>  var ua = tracer.findUA(arguments);
>  if (!ua) {
> var uaIdx = tracer.userActions.length;
>  ua = tracer.userActions[uaIdx] = {
> uaIdx : uaIdx,
>  startTime : startTime,
> path : path
>  }
> tracer.traced[uaIdx] = [];
>  arguments.ua = ua;
>  } else {
>  var uaIdx = ua.uaIdx;
> }
>  var idx = tracer.traced[uaIdx].length;
> tracer.traced[uaIdx][idx] = {
>  path : path,
> arguments : arguments
>  };
>   console.info(indentString + path + '(' +
> Array.prototype.slice.call(arguments).join(', ') + ')');
>  var result = func.apply(this, arguments);
> tracer.traced[uaIdx][idx].result = result;
>  tracer.traced[uaIdx][idx].timed = new Date - startTime;
>  tracer.traced[uaIdx][idx].indentCount = tracer.indentCount;
>
>  console.info(indentString + path , '-> ', result, "(", new Date -
> startTime, 'ms', ")");
>  tracer.indentCount -= 4;
> return result;
>         };
>         traceOn.traceOff = func;
>          for (var prop in func) {
>             traceOn[prop] = func[prop];
>         }
>         //console.log("tracing " + path);
>          return traceOn;
>     },
>
>     traceAll: function(root, path, recurse) {
>  if ((root == window) || !((typeof root == 'object') || (typeof root ==
> 'function'))) {return;}
>         for (var key in root) {
>             if ((root.hasOwnProperty(key)) && (root[key] != root)) {
>                 var thisObj = root[key];
>                 if (typeof thisObj == 'function') {
>                     if ((this != root) && !thisObj.traceOff &&
> !this.nativeCodeEx.test(thisObj)) {
>                         root[key] = this.traceMe(root[key], key,
> path+'.'+key);
>                         this.tracing.push({obj:root,methodName:key,
> path:path+'.'+key});
>                     }
>                 }
>                 recurse && this.traceAll(thisObj, path+'.'+key, true);
>              }
>         }
>     },
>
>     untraceAll: function() {
>         for (var i=0; i<this.tracing.length; ++i) {
>             var thisTracing = this.tracing[i];
>             thisTracing.obj[thisTracing.methodName] =
>                 thisTracing.obj[thisTracing.methodName].traceOff;
>         }
>         console.log("tracing disabled");
>         tracer.tracing = [];
>     }
> }
>
> note: the indentCount variable isn't handled correctly yet. needs to be
> moved into the ua object.
>
>
> On Mon, May 13, 2013 at 5:23 AM, rene7705 <rene7705 at gmail.com> wrote:
>
>> Hi.
>>
>> I would like to create a better console log, one in which you can see per
>> user action what your javascript program does.
>>
>> I've found some source code somewhere on the net that allows you to log
>> all function calls;
>>
>> String.prototype.times = function(count) {
>>     return count < 1 ? '' : new Array(count + 1).join(this);
>> }
>>
>> var tracer = {
>>     nativeCodeEx: /\[native code\]/,
>>     indentCount: -4,
>>     tracing: [],
>>
>>     traceMe: function(func, methodName, path) {
>>         var traceOn = function() {
>>                 var startTime = +new Date;
>>                 var indentString = " ".times(tracer.indentCount += 4);
>>                 console.info(indentString + path + '(' +
>> Array.prototype.slice.call(arguments).join(', ') + ')');
>>                 var result = func.apply(this, arguments);
>>                 console.info(indentString + path , '-> ', result, "(",
>> new Date - startTime, 'ms', ")");
>>                 tracer.indentCount -= 4;
>>                 return result;
>>         }
>>         traceOn.traceOff = func;
>>         for (var prop in func) {
>>             traceOn[prop] = func[prop];
>>         }
>>         console.log("tracing " + methodName);
>>         return traceOn;
>>     },
>>
>>     traceAll: function(root, path, recurse) {
>>  if ((root == window) || !((typeof root == 'object') || (typeof root ==
>> 'function'))) {return;}
>>         for (var key in root) {
>>             if ((root.hasOwnProperty(key)) && (root[key] != root)) {
>>                 var thisObj = root[key];
>>                 if (typeof thisObj == 'function') {
>>                     if ((this != root) && !thisObj.traceOff &&
>> !this.nativeCodeEx.test(thisObj)) {
>>                         root[key] = this.traceMe(root[key], key,
>> path+'.'+key);
>>                         this.tracing.push({obj:root,methodName:key,
>> path:path+'.'+key});
>>                     }
>>                 }
>>                 recurse && this.traceAll(thisObj, path+'.'+key, true);
>>              }
>>         }
>>     },
>>
>>     untraceAll: function() {
>>         for (var i=0; i<this.tracing.length; ++i) {
>>             var thisTracing = this.tracing[i];
>>             thisTracing.obj[thisTracing.methodName] =
>>                 thisTracing.obj[thisTracing.methodName].traceOff;
>>         }
>>         console.log("tracing disabled");
>>         tracer.tracing = [];
>>     }
>> }
>> tracer.traceAll (myObject, 'myObject', true);
>>
>>
>> However, this does not track anonymous functions defined inside functions
>> (possibly as callbacks listed inside some object)...
>> I was wondering if anyone here knows of a way to track those anonymous
>> functions as well.
>>
>> I plan to build up some kind of array instead of log to the console.infodirectly, and display the results in a tree view or whatever is better than
>> a treeview.
>>
>> This component could have a lot of potential.. For instance, it could be
>> used to record user interaction on the website, and in case of an error
>> transmit what happened back to the server to be logged and displayed with
>> details to the developer later on.
>>
>> I'm also wondering about what would be the best way to exclude functions from
>> the log/view that are called very often (as part of an animation loop) but
>> often without doing anything (a scrollpane that doesn't need resizing at
>> that moment, for instance)
>>
>>
>>
>


More information about the Javascript mailing list