tcl program standards

Clovertech Forums Read Only Archives Cloverleaf Cloverleaf tcl program standards

  • Creator
    Topic
  • #48438
    Rich Durkee
    Participant

      I have looked at many tcl programs on the old and new CloverTech web site and in my shop. It seems that there are either many standards or no standards when it comes to the “echos” or “puts” statements and the data displayed in the process logs, because it looks like each programmer  does it differently.

      As I look through our logs I see many different formats of log entries from programs. Obviously we do not have a very good standard.

      Having one would probably make the logs smaller and more readable and easier to find which program put the entry into the log.

      One program I saw concatenated the program name and the connection name followed by the information. That seems like a good idea. What other information should be in a log entry. It seems like the time would be good, since I don’t see that in the log very often.

      Should the program log an entry at program start time and program end time? A log entry should probably be displayed when a message is killed or data in the message is changed or other critical things are done. Unfortunately I have seen a lot of testing/debugging log entries that are in Production that should have been removed after testing and prior the program being moved to production. How do other handle that?

      I like standards but have come become an Engine Programmer several years after our system was installed and the previous Programmer had no standards, which is why we have the mish-mash we have today. I would like to slowly correct the situation, but would like to have a plan before I begin.

      Thanks for reading. Comments?

      Rich Durkee

      Genesys Regional Medical Center

      Grand Blanc, Michigan

    Viewing 1 reply thread
    • Author
      Replies
      • #58635
        Richard Hart
        Participant

          Rich.

          I hope this helps ..

          We use TCL translations extensivley and have a library ‘Print’ command.

          A print command request looks like this …

                 Print GlobGCRT$HciConnName “Global ACKDEST    = [GlobGCRT$HciConnName GET ACKDEST]” “I”

                 Print GlobGCRT$HciConnName “Global ACKMSGTYPE = [GlobGCRT$HciConnName GET ACKMSGTYPE]” “I”

                 Print GlobGCRT$HciConnName “Global ACKTYPE    = [GlobGCRT$HciConnName GET ACKTYPE]” “I”

                 Print GlobGCRT$HciConnName “Global ACKDISP    = [GlobGCRT$HciConnName GET ACKDISP]” “I”

          Where the Glob… is a function using a unique namespace to ‘set’ and ‘get’ variables, so configuration variables are thread and code specific.

          The code is ..

          proc Print { aGlobals aString {aCode “D” } } {

                 #

                 # GLOBAL VARIABLES

                 #   HciConnName – global variable set by the system

                 #

             global HciConnName

             set myDebug [ $aGlobals GET DEBUG ]

             set myName [ $aGlobals GET NAME ]

                 #

                 # if this is a Non-debug message, OR the debug flag is TRUE

                 # print the message

                 #

             if { $aCode != “D” || $myDebug == “TRUE” } {

                     #

                     # set the message prefix, either error or debug

                     #

                 switch $aCode {

                     “C” {

                             set myctx “CRITICAL”

                             $aGlobals SET STOP TRUE

                         }

                     “E” { set myctx “ERROR” }

                     “W” { set myctx “WARNING” }

                     “I” { set myctx “INFO ” }

                     “D” { set myctx “DEBUG” }

                     default { set myctx “INFO” }

                 }

                 set myThreadName “[fmtclock [getclock] %X] $HciConnName $myName”

                     #

                     # now display the message …

                     #

                 echo “$myThreadName:$myctx: $aString”

             }

          };# end of Print

          A Typical thread startup (a thread sending data) looks like this …

          15:36:27 ris_test_ih_adt_snd gen_code_msginfo:INFO : RCS Info $Id: gen_code_msginfo.tcl,v 1.3 2003/08/18 07:35:49 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_msginfo:INFO : RCS Info $Id: gen_library.tcl,v 1.36 2005/12/08 07:14:38 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_msginfo:INFO : RcsVerChk min = 1.7

          15:36:27 ris_test_ih_adt_snd gen_code_msginfo:INFO : RcsVerChk chk = 1.36

          15:36:27 ris_test_ih_adt_snd gen_code_msginfo:INFO : MODE = start; CONTEXT = send_data_ok; APPL = ris; LEVEL = test; SITE = ih; DATA = adt; FLOW = snd

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RCS Info $Id: gen_code_resend.tcl,v 1.9 2006/03/30 03:11:15 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RCS Info $Id: gen_library.tcl,v 1.36 2005/12/08 07:14:38 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RcsVerChk min = 1.2

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RcsVerChk chk = 1.36

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : MODE = start; CONTEXT = send_data_ok; APPL = ris; LEVEL = test; SITE = ih; DATA = adt; FLOW = snd

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : Load the Configuration file

          15:36:27 ris_test_ih_adt_snd gen_code_resend:DEBUG: START

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RCS Info $Id: gen_code_resend.tcl,v 1.9 2006/03/30 03:11:15 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RCS Info $Id: gen_library.tcl,v 1.36 2005/12/08 07:14:38 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RcsVerChk min = 1.2

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RcsVerChk chk = 1.36

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : MODE = start; CONTEXT = reply_gen; APPL = ris; LEVEL = test; SITE = ih; DATA = adt; FLOW = snd

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : Load the Configuration file

          15:36:27 ris_test_ih_adt_snd gen_code_resend:DEBUG: START

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RCS Info $Id: gen_code_resend.tcl,v 1.9 2006/03/30 03:11:15 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RCS Info $Id: gen_library.tcl,v 1.36 2005/12/08 07:14:38 he00387 Exp $

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RcsVerChk min = 1.2

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : RcsVerChk chk = 1.36

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : MODE = start; CONTEXT = sms_ib_reply; APPL = ris; LEVEL = test; SITE = ih; DATA = adt; FLOW = snd

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : Load the Configuration file

          15:36:27 ris_test_ih_adt_snd gen_code_resend:DEBUG: START

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : MAXIMUM Retries Allowed = 0

          15:36:27 ris_test_ih_adt_snd gen_code_resend:INFO : AE ACK [ACK|NAK] = ACK

          A ‘run’ looks like this …

          15:41:29 ris_test_ih_adt_rcv :INFO : Testing with [ACK_NO]. Values ‘ACK_NO’, ‘ACK_AR’, ‘ACK_AE’, ‘ACK_A2’, ‘ACK_R2’, ‘ACK_E2’, ”

          15:41:29 ris_test_ih_adt_rcv :DEBUG: Separator = >|<; Component = >^<; Repetition = >~< 15:41:29 ris_test_ih_adt_rcv :DEBUG: RECV: >MSH|^~&|HL7LAB||CLOVERLEAF|qdxi01p|200510131611||ORU^R01|101|D|2.1|||||^MPID|||A9994292||< 15:41:29 ris_test_ih_adt_rcv :DEBUG: [ACK_NO] IGNORE MSG KILL: MSH|^~&|HL7LAB||CLOVERLEAF|qdxi01p|200510131611||ORU^R01|101|D|2.1|||||^MPID|||A9994292|| 15:41:39 ris_test_ih_adt_snd gen_code_resend:INFO : No response within timeout. Resending saved message …

          15:41:39 ris_test_ih_adt_snd gen_code_resend:DEBUG: KILL Msg

          15:41:39 ris_test_ih_adt_snd gen_code_resend:DEBUG: PROTO Saved Msg

          15:41:39 ris_test_ih_adt_snd gen_code_resend:DEBUG: RETURN [{KILL message1} {PROTO message0}]

          15:41:39 ris_test_ih_adt_snd gen_code_resend:DEBUG: Separator = >|<; Component = >^<; Repetition = >~< 15:41:39 ris_test_ih_adt_snd gen_code_resend:DEBUG: SEND CTRLID [101]

          15:41:39 ris_test_ih_adt_snd gen_code_resend:DEBUG: RETURN []

          We also ensure that translation prints the old and new values, so we can produce reports etc

          eg

          08:01:04 sud_test_ih_lab_in :DEBUG: Separator = >|<; Component = >^<; Repetition = >~< 08:01:04 sud_test_ih_lab_in :DEBUG: WARNING: XlateMsg: Translation function ‘XlatePreMSH’ Does not exist 08:01:04 sud_test_ih_lab_in :DEBUG: WARNING: XlateMsg: Translation function ‘XlatePrePID’ Does not exist 08:01:04 sud_test_ih_lab_in :DEBUG: WARNING: XlateMsg: Translation function ‘XlatePrePV1’ Does not exist 08:01:04 sud_test_ih_lab_in :INFO : Ultra site is >PMH< 08:01:04 sud_test_ih_lab_in :DEBUG: WARNING: XlateMsg: Translation function ‘XlatePreOBX’ Does not exist 08:01:04 sud_test_ih_lab_in :DEBUG: Site is >PM< 08:01:04 sud_test_ih_lab_in :INFO : OLD:>MSH|^~&|HL7LAB||CLOVERLEAF|qdxi01d|200603290800||ORU^R01|22795|D|2.1|||||^MPID|||L0747933||KINGSTON^ALEC||19550515|M|||17 JUMP STREET^^FREMANTLE|||||||LP06030

          02901||||^MPV1||I|3B|||||||||||||||||||||||||||||||||||||||||||||||^MOBR|1||P-3002901D|HCOAGS^COAG PROFILE FOR JFS^L||200603290755|200603290755|||||||200603290755||0404311K^HAGGETT&TIMOTHY||||PMH^PRIN

          CESS MARGART||200603290800|||F|||||||||||^MOBX|1|TX|RECEIVED^^L||29/03/2006 07:55||||||F|||||^M< 08:01:04 sud_test_ih_lab_in :INFO : NEW:>MSH|^~&|SUD@IH|QDX|RCV_PM_LAB|ICM|200603290800||ORU^R01|22795:1560:SUD@IH:T:03141014|D|2.3|||||^MPID|||L0747933^^^MRN||KINGSTON^ALEC||19550515|M|||17 JUMP STR

          EET^^FREMANTLE|||||||PM@0000L0747933^^^Acct No|^MPV1||Inpatient|ZZZZ-IH^^^P1|||||||||||||||ZZZZ|^MOBR|1|^PCS|P-3002901D^LAB|HCOAGS^COAG PROFILE FOR JFS^L||200603290755|200603290755|||||||200603290755|

          |||P-3002901D||PMH^PRINCESS MARGART||200603290800|||F|^MOBX|1|TX|REGBYLAB^^L||29/03/2006 07:55||||||F|||||^M<

        • #58636
          Anonymous
          Participant

            Rich,

            You didn’t exactly ask this question but here’s an answer anyway; should you use ‘puts’ or ‘echo’?  Over time, the core TCL commands have been optimized more than the extended commands so you should use core commands over extended commands when possible.  ‘echo’ is an extended command and ‘puts’ is a core command.  In my own code I’ve started using ‘puts’.  This doesn’t mean that you should go change all your ‘echo’s in to ‘puts’ in your old code, it just means, in programmer-ese, you get some slight benefit for using ‘puts’.

            On the other question about a standard way to put messages into the log, I have my own technique and so do many others.  Quovadx has pretty much kept hands off when it comes to coding technique.  I present my ideas in classes but each implementer has their own variations.

            There is a standard procedure called ‘dputs’ that you can run to do logging.  Go into a ‘hcitcl’ sessoin in a shell and type ‘dputs’.  It’s cool in that if the debug variable either doesn’t exist or is 0 then the procedure redefines itself to be a no-op.  You’ll have to go poke around in the Cloverleaf TCL library directory to find the procedure.

            I have my own technique because I wanted my log entry to have more info than what ‘dputs’ has.  I call mine ‘dEcho’ (even though it uses ‘puts’).

            Either way, my print to the log statements stay in my code and I turn them on or off using a debug variable.  That way when I go to production I set the variable to 0.  When I want debugging then I set the variable to 1.

            Cheers,

        Viewing 1 reply thread
        • The forum ‘Cloverleaf’ is closed to new topics and replies.