问题
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