问题描述
我发现了在 Progress 4GL 中记录某些内容的不同方法,但没有一种方法令人满意:
简单的 MESSAGE
语句的缺点是它处理帧非常糟糕:
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.
首先显示第 1 行和第 2 行,第 3 行有一个滚动条,但由于其他类似对话框的框架而无法访问,一旦这些框架消失,原始消息行就不再存在。
已经展示的另一种可能性是 MESSAGE ... VIEW-AS ALERT-Box
。这很好用,甚至还有复制粘贴的可能,但是所有消息都显示在单独的警报框中,这使得处理起来非常困难。
本网站上提到的第三种可能性是使用日志管理器,但我在 Progress 4GL 安装的某处没有名为 *log*manager*
的文件,所以我不知道如何使用这个。
谁能解释我如何进行日志记录?我想要的是以下内容:
...
LOG("Line1").
...
LOG("Line2").
...
LOG("Line3").
...
缩进代表在调用栈中的位置(“Line3”被函数调用,而“Line2”被子函数调用,被子函数调用,被函数调用)。
这个想法是(以可复制粘贴的格式):
理想情况下:
Line1
......Line2
..Line3
如果这是不可能的,我就满足于:
Line1
Line2
Line3
有人知道这是否存在以及如何实现吗?
提前致谢
解决方法
查看有关日志记录的 doc,尤其是 LOG-MANAGER
命令和 4GLTrace
日志条目类型。
LOG-MANAGER
通常对于“系统”类型信息非常有用 - 有很多跟踪和调试数据可用。它还可以通过 WRITE-MESSAGE
方法用于应用程序日志记录;虽然这很有效,但它非常粗糙,因此如果您想使用它(例如,用于过滤日志级别),您可能必须围绕它编写一个包装器。
如果您使用的是相当新的版本,您可以查看 https://docs.progress.com/bundle/openedge-abl-develop-services/page/ABL-application-logging.html,它为此(以及更多)提供了一个包装器。
,如果您只想记录一些简单的消息,您可以将输出重定向到一个文件。对一些消息使用 OUTPUT TO
语句:
OUTPUT TO VALUE("logfile.txt").
PUT UNFORMATTED "Message 1" SKIP.
PUT UNFORMATTED "Message 2" SKIP.
PUT UNFORMATTED "Message 3" SKIP.
OUTPUT CLOSE.
这将在您的开始文件夹中创建一个“logfile.txt”文件。它将包含以下内容:
Message 1
Message 2
Message 3
PUT UNFORMATTED
语句向文件发送一个字符串。 SKIP
关键字添加换行符。 OUTPUT CLOSE
语句关闭文件。
如果要添加到现有文件中,请在 APPEND
语句中使用 OUTPUT
:
OUTPUT TO VALUE("logfile.txt") APPEND.
,
一个简单的日志库:
/* 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.
示例测试台:
/* 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" ).