canjs / can-connect

Model layer utilities for every JavaScript framework! Assemble real-time, high performance, restful data connections.
https://canjs.com/doc/can-connect.html
MIT License
29 stars 16 forks source link

make it easy to log what's happening in can-connect #417

Open justinbmeyer opened 6 years ago

justinbmeyer commented 6 years ago

I'd like to make a little utility to log what's happening in can-connect. I'm working on this now in an effort to debug bitballs.

Posting relevant code:

var connect = require("can-connect");
var WeakReferenceMap = require("can-connect/helpers/weak-reference-map");
var WeakReferenceSet = require("can-connect/helpers/weak-reference-set");
var sortedSetJSON = require("can-connect/helpers/sorted-set-json");
var eventQueue = require("can-event-queue/map/map");

// shared across all connections
var pendingRequests = 0;
var noRequestsTimer = null;
var requests = {
    increment: function(connection){
        pendingRequests++;
        clearTimeout(noRequestsTimer);
    },
    decrement: function(connection){
        pendingRequests--;
        if(pendingRequests === 0) {
            // this calls to the connection so that `notifyThereAreNoPendingRequests` can be trapped
            noRequestsTimer = setTimeout(connection.notifyThereAreNoPendingRequests,module.exports.requestCleanupDelay);
        }
        if(pendingRequests < 0) {
            pendingRequests = 0;
        }
    },
    count: function(){
        return pendingRequests;
    },
    notifyThereAreNoPendingRequests: function(){
        requests.dispatch("end");
    }
};
eventQueue(requests);

var constructorStore = connect.behavior("constructor/store",function(baseConnection){

    var behavior = {
        // do this so this method can be logged
        notifyThereAreNoPendingRequests: function(){
            requests.notifyThereAreNoPendingRequests();
        },

This is the log function. It nests stack calls. Traps repeat calls over time.

function logCalls(obj, indent){

    console.log(  (indent||"") +obj.title+"\n" );
    obj.children.forEach(function(child){
        logCalls(child,(indent||"")+"  ");
    });
}

var lasts = [];
var logStack = [];
function logger(obj, root) {
    if(!root) {
        root = obj;
    }
    Object.keys(obj).forEach(function(key){
        if(obj.hasOwnProperty(key)) {
            if(typeof obj[key] === "function" && !canReflect.isConstructorLike(obj[key])) {
                var old = obj[key]
                obj[key] = function(){
                    var log = {
                        title: ""+root.name+" connection."+key+" ("+obj.__behaviorName+")",
                        meta: {name: key, behavior: obj, fn: old, arguments: arguments, this: this},
                        children: [],
                        get clickMeToLogMore(){
                            logCalls(this,"")
                            return  "stack logged down below";
                        }
                    };

                    if(logStack.length) {
                        logStack[logStack.length-1].children.push(log);
                    }
                    logStack.push(log);
                    var result = old.apply(this, arguments);
                    var last = logStack.pop();
                    if(logStack.length === 0) {

                        if(lasts.length === 0) {
                            setTimeout(function(){
                                var lastsClone = lasts.slice(0);
                                lasts = [];
                                lastsClone.forEach(function(last){
                                    console.log(last)
                                });
                            },10);
                        }
                        if(lasts.length) {
                            var lastLast = lasts[lasts.length - 1];
                            if(lastLast.title === last.title) {
                                if(lastLast.type === "repeat") {
                                    lastLast.children.push(last);
                                } else {

                                    lasts[lasts.length - 1] = {
                                        title: last.title,
                                        type: "repeat",
                                        children: [lastLast, last]
                                    }
                                }
                            } else {
                                lasts.push(last);
                            }
                        } else {
                            lasts.push(last);
                        }
                    }
                    return result;
                }
            }
        }
    })
    var proto = Object.getPrototypeOf(obj);
    if(proto && proto.__behaviorName) {
        logger(proto, root)
    }
}

logger(Player.connection);