How to do logging in OpenEdge Progress?

浪尽此生 提交于 2021-01-28 09:09:53

问题


I've found different ways to log something in Progress 4GL but none are satisfying:

The simple MESSAGE statement has the drawback that it handles frames very badly:

ON CHOOSE OF btn-Q4
DO:
  MESSAGE "Line 1".
  MESSAGE "Line 2".
  MESSAGE "Line 3".

  PROMPT-FOR ...
    WITH FRAME ...
  ...
  MESSAGE "Alert message" VIEW-AS ALERT-BOX.
  
  PROMPT-FOR ...
    WITH FRAME ... /* (another frame) */
  ...
  MESSAGE "Another alert message" VIEW-AS ALERT-BOX.
  ...
  MESSAGE "Normal message".
END.

This starts by showing lines 1 and 2, there's a scrollbar for line 3, but this inaccessible due to the other dialogbox-like frames and once those are gone, the original messages lines are not there anymore.

Another possibility, already shown, is the MESSAGE ... VIEW-AS ALERT-BOX. This works fine, and there even is the possibility for copy-paste, but all messages are shown in individual alert boxes, which makes it very difficult to handle.

A third possibility, mentioned on this site, is the usage of a log-manager, but I don't have a file, called *log*manager* somewhere on my Progress 4GL installation, so I don't know how to use this.

Can anybody explain me how to do logging? What I would like is the following:

...
LOG("Line1").
...
      LOG("Line2").
...
  LOG("Line3").
...

The indentation stands for the location in the callstack ("Line3" is called by a function, while "Line2" is called by a subsubfunction, called by a subfunction, called by a function).

The idea is to see (in a copy-pastable format):

Ideally:

Line1
......Line2
..Line3

In case this is not possible, I settle for:

Line1
Line2
Line3

Does anbody know if this exists and how to realise it?

Thanks in advance


回答1:


If you just want to log some simple messages, you can redirect output to a file. Use the OUTPUT TO statement with some messages:

OUTPUT TO VALUE("logfile.txt").

PUT UNFORMATTED "Message 1" SKIP.
PUT UNFORMATTED "Message 2" SKIP.
PUT UNFORMATTED "Message 3" SKIP.

OUTPUT CLOSE.

This will create a "logfile.txt" file in your start-in folder. It will contain the following:

Message 1
Message 2
Message 3

The PUT UNFORMATTED statement sends a string to the file. The SKIP keyword adds a linefeed. The OUTPUT CLOSE statement closes the file.

If you want to add onto an existing file, use APPEND on the OUTPUT statement:

OUTPUT TO VALUE("logfile.txt") APPEND.



回答2:


Take a look at the doc on logging, especially the LOG-MANAGER command and the 4GLTrace log entry type.

LOG-MANAGER in general is very useful for "system" type info - there's a lot of tracing and debugging data available. It can also be used for application logging with the WRITE-MESSAGE method; while this works it's quite coarse, and so you'll probably have to write a wrapper around it if you want to use it (for filtering logging levels, for example).

If you're on a reasonably recent version, you can look at https://docs.progress.com/bundle/openedge-abl-develop-services/page/ABL-application-logging.html which provides a wrapper for this (and more).




回答3:


A simple logging library:

/* logger.p
 *
 * to instantiate:
 *
 *      run logger.p persistent
 *
 * three ways to call it from your code:
 *
 *   publish "logMsg" ( msgLevel, messageText ).        // requires no knowledge in the caller, no error if logger.p has not first been run persistently
 *   run doLogMsg ( msgLevel, messageText ).            // requires no knowledge in the caller, error if logger.p is not run first
 *   logMsg( msgLevel, messageText ).                   // requires forward declaration in the caller
 */


subscribe to "setLogName" anywhere run-procedure "setLogName".
subscribe to "logMsg"     anywhere run-procedure "doLogMsg".

define variable logMsgLevel    as integer   no-undo initial 3.
define variable logMsgFileName as character no-undo initial "application.log".

define stream logStream.

/* install self as a session super-procedure
 */

session:add-super-procedure( this-procedure ).

return.


/* housekeeping
 */

procedure setLogName:
  define input parameter logName as character no-undo.
  logMsgFileName = logName.
  return.
end.


procedure setLogLevel:
  define input parameter logLevel as integer no-undo.
  logMsgLevel = logLevel.
  return.
end.


/* to use this function directly from another procedure you must first declare it in that procedure:
 *
 *      function logMsg returns logical ( input msgLevel as integer, input msgText as character ) in super.
 */

function logMsg returns logical ( input msgLevel as integer, input msgText as character ):
  run doLogMsg( msgLevel, msgText ).
  return true.
end.


/* procedures do not need to be forward declared but we can not have a function and a procedure with the same name
 */

procedure doLogMsg:

  define input parameter msgLevel as integer   no-undo.
  define input parameter msgText  as character no-undo.

  if msgLevel <= logMsgLevel then
    do:
      output stream logStream to value( logMsgFileName ) append.
      put    stream logStream unformatted today " " string( time, "hh:mm:ss" ) " " msgText skip.
      output stream logStream close.
    end.

  return.

end.

An example test bed:

/* test logger.p
 */

/* run doLogMsg ( 3, "test a" ).  */

/* logMsg( 3, "test b" ).         */



function logMsg returns logical ( input msgLevel as integer, input msgText as character ) in super.     /* usually this is in a include file in the procedure header */

publish "logMsg" ( 3, "test 1" ).

run ./logger.p persistent.              /* loads logger.p into memory... */

run setLogName ( "test.log" ).

publish "logMsg" ( 3, "test 2" ).

run doLogMsg ( 3, "test 3" ).

logMsg( 3, "test 4" ).


来源:https://stackoverflow.com/questions/65406908/how-to-do-logging-in-openedge-progress

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!