+ Antworten
Ergebnis 1 bis 3 von 3
  1. #1
    Registriert seit
    Oct 2008
    Beiträge
    1,033

    Standard Debugging-Hilfe, die auch zur Laufzeit im System bleibt

    Hi all,
    ich habe mir mal ein paar Stunden Zeit genommen, eine etwas umfangreichere Debugging-Methode, di ich schon in einigenanderen Sytsemen benutzt habe, in IPS (oder besser: PHP) umzusetzen. Bin in PHP noch blutiger Anfänger, insofern wird's bestimmt mal noch Verbesserungen geben.

    Was soll das Ding tun?

    Es soll die typischen "echo" Befehle, die man beim Testen und Programmieren in Scripte ein- und wieder aus- und wieder ein- und wieder ausbaut, um sie dann bei Änderungen nach einer Woche oder so wieder ein- und auszubauen, ersetzen.

    Die Idee ist simpel: Ich baue Meldungen in den Code ein, schalte die aber zur Laufzeit aus (nein: ich schalte sie zur Programmier/Testzeit ein).

    Ich habe oft den Wunsch, "zu tracken", wo mein Script gerade is, also die Zeile, um zu wissen, ob eine bestimmte "if" schon durch ist oder nicht. Dazu gebe ich dann oft per echo aus: "jetzt dieses" ... "vor xyz" ... "nach xyz" usw. Ist ne Sissyphusarbeit und nicht selten bleibt ein echo drin ...

    Seit heute mache ich das so, dass ich eine Zeile Code schreibe:

    Debug( "ein Text");

    oder

    Debug( "ein Text", Wichtigkeit)

    wobei ich die Wichtigkeit als Zahl ausdrücke - je kleiner die Zahl, desto wichtiger die Meldung.

    Will ich später mal "tracken, was mein Script macht oder wo evtl. ein Fehler ist (es fehlt ne Variable, ich habe eine Kategorie umbenannt etc.), dann setze ich einfach eine Variable in meinem Objektbaum auf 1, 5 10, oder 1000, und erhalte im Meldungsfenster brav alle Infos abgeliefert. Von Makro bis Minutiös.

    Hier ist der Code und die Doku dazu. Hoffe dass das alles einigermassen verständlich ist (ich habe ne eigene Datenbank hier, wo die Doku parallel zum Code ist und farbliche Gestaltung ermöglicht etc. da kommt das besser).



    PHP-Code:

    /* *************************************************************************
        function Debug()
        throws message to log depending on the DebugLevel value either set locally
        (calling script) or globally (variable in object tree)
        
        Version 2.0 // 2010-06-10
        Author: jw
        
        see separate documentation
    **************************************************************************** */

    // TEST VALUES FOR TESTING THE FUNCTION

    //$DebugLevel = 5; // this is a local usage which is NOT recommended for wild life

    //Debug();
    //Debug("Message from level 1 and above");
    //Debug("This message will occur from DebugLevel 5 and above", 5);
    //Debug("Here with Codeline and from DebugLevel 100", 100, __LINE__);
    //Debug("Message from Level 5 WITHOUT Codeline but special sender-ID", 5, 0, "Sender is Scriptcode");
    //Debug("Message from Level 5 WITHOUT Codeline but scriptname as sender-ID", 5, 0, IPS_GetName($IPS_SELF);
    //Debug("Message from Level 5 WITH Codeline but scriptname as sender-ID", 5, __LINE__, IPS_GetName($IPS_SELF);
    //Debug("Message suppotrting [MyDebug] as an entry to the tree", 5, __LINE__, ".default.", "MyDebug:0");
    //Debug(".value.", 0, 0, "", "DebuggingVariable:0"); // THIS MESSAGE READS THE ACTUAL DEBUG LEVEL


    function Debug$Msg=".default."$Level=1$CodeLine=0$MsgSender=".default."$DebugLevelObject="DebugLevel:0" ){
        
    // Version 2.0
        
    global $DebugLevel;
        if ( 
    $Msg == ".value." ):
            
    $Level 0;
            
    $Msg=".default.";
        endif;
        if (!@
    is_numeric$DebugLevel )): // DebugLevel not set in calling script
           
    $DebugLevelObjectName = @strtok($DebugLevelObject":"); //name of variable used
           
    $DebugLevelObjectParentID = @intval(strtok(":")); // if given, use different tree structure (default is 0)
           
    if ( $DebugLevelObjectName == ""): //empty parameter supplied
              
    $DebugLevelObjectName "DebugLevel";
           endif;
           
    $id = @IPS_GetObjectIDByName$DebugLevelObjectName$DebugLevelObjectParentID  );
              if (
    $id === false):
                
    $DebugLevel 0;
            else:
                
    $DebugLevel floatval(GetValue$id));
            endif;
        endif;
        if ( 
    $DebugLevel $Level ):
            
    // nothing to do because debug level set is lower than level to throw message
           
    return;
        endif;
        
    $MsgCodeLine "";
        if (
    $CodeLine 0):
            
    // write line of code of calling script into message
           
    $MsgCodeLine " [L: " $CodeLine "]";
        endif;
        if ( 
    $MsgSender == ".default." || $MsgSender == ""):
            
    // default sender info
            
    $MsgSender "*** DEBUG *** " $MsgCodeLine;
        else:
           
    // special sender defined by caller
            
    $MsgSender $MsgSender $MsgCodeLine;
        endif;
        if ( 
    $Msg == ".default." ):
           
    // default message ==> publish actual debug level
           
    $Msg "DebugLevel = " $DebugLevel;
        endif;
        
    IPS_LogMessage$MsgSender $Msg);
    };



    // EXTREMELY COMPRESSED VERSION OF Debug()
    function DebugC$M=".default."$L=1$C=0$S=".default."$D="DebugLevel:0" ){
        
    // Version 2.0.c
        
    global $DebugLevel;
        if ( 
    $M == ".value." ){    $L=0;
            
    $M ".default.";};
        if (!@
    is_numeric$DebugLevel )){
           
    $DN = @strtok($D":");
           
    $DI = @intval(strtok(":"));
           if (
    $DN == ""$DN "DebugLevel";
           
    $i = @IPS_GetObjectIDByName$DN$DI  );
            if (
    $i === false){ $DebugLevel 0;
                }else 
    $DebugLevel floatval(GetValue$i));
        };
        if ( 
    $DebugLevel $L ) return;
        
    $CO "";
        if (
    $C 0$CO " [L: " $C "]";
        if ( 
    $S == ".default." || $S == "" $SS "*** debug *** " $CO;
        else     
    $SS $S $CO;
        if ( 
    $M == ".default." $M "DebugLevel = " $DebugLevel;
        
    IPS_LogMessage$SS $M);
    };


    /* ########################### END OF SCRIPT - DOCUMENTATION ##################

    The Debug() and DebugC() (c=compressed version) supply a tiny tool for programmers
    to include lines of code throwing debugging-infos into the log WITHOUT (!) the need
    of removing those code lines after coding is finished.

    More than this: at any time, even without touching the code, you can "switch"
    the messages on and off.

    And, even more: You can have different granularity of messages being produced
    depending on the value yo assign to a "Debugging variable".

    Therefor, even on a perfectly running system, you can easily switch on and off
    runtime messages with information about what, why, when without accessing the code itself.


    **** DOES IT CONSUME RESSOURCES? ****************************
    The called function is simply returned with no result and almost no time
    consumption (approx. 3.5 ms per run) if the according DebugLevel is set to zero.

    Even when producing an output, the time of IPS_LogMessage is the by far most
    "expensive" function used, but only IF a message is produced (i.e. the DebugLevel
    at runtime is high).


    **** FUNCTIONALITY & USAGE: *********************************
    All you have to do is:

    1.) Incorporate the function into your code
    recommendadtion: use it by include)

    2.) Write one of the following lines (see more examples at the end) into your code:

    3.) Supply a DebugLevel value (read on for a few seconds to see, how)



    **** CODE IN YOUR SCRIPT ***********************************

    The PARAMETERS are ALL optional, so the simplest usage is

        Debug()
        
    However, to get a specific result as an entry, you will rather use lines like:


        Debug( "this is breakpoint number X")

        Debug( "here we are at codeline", 1000, __LINE__)
        
        Debug( "here we are at codeline", 1000, __LINE__ , "Scriptname=SwitchAllOn")


    See an in depth discussion about the usage at the end of this documentation.

    REMARK: If you have not set up anything, you will see NO result.
    There is one other step, step 3 as of the said above


    **** HOW TO GET THE MESSAGE OUTPUT TO THE LOG: ***************
    The debug function only produces any output to the logfile, if a value called

        $DebugLevel
        
    has a certain value OR a variable in the object tree has the according value.

    You can set this by either:

        -     put $DebugLevel = <value> locally to your script (NOT RECOMMENDED because
            you need to modify your script each time you will see or hide the messages)

        -    having a "DebugLevel" variable of numeric type as a child to the
            main object( IPSymcon)
            (RECOMMENDED because: this allows to switch the functionality conveniently
            on and off through a variety of actions like in the tree, modify the value
            and also, potentially code used from others will also support this with no changes]
            
        -    having ANY numeric variable SOMEWHERE in the object tree AND (!!) supplying
            the name and parent object ID of that variable as a parameter to Debug
            function (see below)


    **** IN DEPTH DESCRIPTION OF PARAMETERS: ************************

    to the logfile, you might use parameters to steer the information returned.
    CALL:

    Debug( [string] Messagetext, [integer] DebugLevelThresold, [integer] Codeline, [string] Sender Name, [string] DebugLevelVariableObject)

    PARAMETERS:
    [string] Messagetext:
        The Message you want to be shown in the log entry
        if this parameter is ".default.", the actual set DebugLevel (if not 0) is the output
        
    [integer] DebugLevelThresold
        This is the valus that will make the message visible or invisible.
        It allows for a fine granulated debugging method.
        RECOMMENDADTION:
        Use high values (i.e. 1000) for most critical messages that are supposed
        to never appear during the regular runs of your code while using lower values
        that will adddress topics that will more likely appear after your coding is
        finished i.e. access to objects taht might dissapear or value limits
        
        IF YOU OMIT this parameter, the function will produce the output at any value
        of DebugLevel from 1.0 and higher.
        
        This parameter needs to be used if the parameters following will be used!
        The number "1" is the "default" and will make sure that the message is being
        thrown on any DebugLevel from 1.0 and higher.
        
        
    [integer] Codeline
        This will show the value purged to the function, appended to the sender info.
        Use the magic constant "__LINE__" of PHP to supply the actual codeline of
        the script debugged to the debug function. This allows a very fast identification
        of the lines that might produced problems, especially some weeks/months/years
        after coding.

        IF YOU OMIT this parameter, the informaion is simply not produced.

        This parameter needs to be used if the parameters following will be used!
        Use the number "0" for not using the feature.


    [string] Sender Name
        This will be the value set into the "Sender" column of the log file.
        RECOMMENDATION
            Use the Scriptname and/or ID if you do not want "*** DEBUG ***" to be the
            output in the log file.

            Of course, as with IPS_LogMessage, you can supply any other string value as well.
            Be advised that the current version of IPS does not support "" (empty string),
            so, this value will be converted to "*** DEBUG ***"!

            If you omit ("") the parameter, "*** DEBUG ***" or "***debug***" (lower
            case) is used so you see that the message is a debugging value and not a
            regular output.


    [string] DebugLevelVariableObject)
        IF you decide to have your own numeric variable somewhere in your IPS tree
        and dislike the place to be right below the "0" object, you can do so.
        
        Put that variable ANYWHERE you want, name it as you like.
        
        The only DISADVANTAGE in this case is, that you need to supply an additional
        parameter to the debug function, which is the very last one. And in turn,
        you need to supply all of the parameters then.
        

    **** WHAT THE HACK IS DebugC()?? ***********************************
        i have written DebugC() just for fun to show how compact (and unreadable) code
        can be if the human factor would be ignored. Basically, this consums a tick
        less computation time since it is less characters to read from disk, to parse
        and to interpret at runtime.
        
        ... also, with that code you can be relatively sure that no customer would
        change it - at least not functionable ...

    ################################# E O D #################################### */ 
    Geändert von jwka (11.06.10 um 17:52 Uhr)

  2. #2
    Registriert seit
    Sep 2007
    Ort
    Didderse
    Beiträge
    682

    Na wenn du noch nen "blutiger Anfänger" bist, bin ich ne Amöbe

  3. #3
    Registriert seit
    Oct 2008
    Beiträge
    1,033

    Standard "Lokale" variable pro Script - falls nötig

    Habe bei meinem post von gestern noch vergessen, dass man neben der "globalen Schaltung" natürlich auch auf eine "lokale" Schaltung je Script gehen kann.

    Ich mach das so, dass ich folgende CodeZeilen in meine Script ganz am Anfang einbaue und unter dem Script eine Variable anlege, die ich dann individuell setzen kann. Der Typ sollte normalerweise Integer sein, aber da PHP ziemlich gutmütig ist, tut's praktisch jeder Typ.

    PHP-Code:

    // check if local debug level is set
    $DebugLevel = @GetValue(IPS_GETObjectIDByName("DebugLevel"$IPS_SELF));
    if (
    $DebugLevel === false): // var does not exist locally --> destroy to use global one (if exist)
        
    unset($DebugLevel);
    else:
        
    // convert to usable number. Note: Any crab will lead to 0 assuming no debug messages
        
    $DebugLevel intval($DebugLevel);
    endif; 
    HINWEIS:
    Diese kleine Routine ist "gezielt" etwas unsauber, um den code kurz zu halten.

    Das "unset" bei nicht ex. Variable führt dazu, dass die Debug() routine auf die globale Definition zurückgreift (sonst würde der Wert angenommen, auch wenn er 0 wäre)

    jwka

Ähnliche Themen

  1. Überlegungen welches System
    Von jacky0815 im Forum Haustechnik
    Antworten: 7
    Letzter Beitrag: 30.04.10, 08:35
  2. Hilfe?
    Von _Sven_ im Forum Allgemeine Diskussion (2.x/3.x)
    Antworten: 0
    Letzter Beitrag: 07.02.10, 22:27
  3. hilfe: welches kabelgebundene system für rolladen + licht?
    Von daniel u im Forum Allgemeine Diskussion
    Antworten: 23
    Letzter Beitrag: 11.11.08, 22:02
  4. Anfänger Plant komplettumbau mit FS20 System und braucht Hilfe !
    Von drcracker im Forum Sonstige Funkkomponenten / Wetterstationen
    Antworten: 5
    Letzter Beitrag: 29.12.07, 18:00
  5. Welches System ist das richtige für mich?
    Von candela im Forum Allgemeine Diskussion
    Antworten: 11
    Letzter Beitrag: 21.11.07, 20:46