如何将 DBMS_OUTPUT.PUT_LINE 的输出重定向到文件?

发布于 2024-08-05 03:02:18 字数 214 浏览 20 评论 0原文

我需要在 pl/sql 中进行调试来计算程序的时间,我想使用:

SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);

但我不明白输出去哪里以及如何将其重定向到包含我想要收集的所有数据的日志文件?

I need to debug in pl/sql to figure times of procedures, I want to use:

SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);

but I don't understand where the output goes to and how can I redirect it to a log file that will contain all the data I want to collect?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

魔法少女 2024-08-12 03:02:18

DBMS_OUTPUT 不是最好的调试工具,因为大多数环境本身并不使用它。但是,如果您想捕获DBMS_OUTPUT 的输出,则只需使用DBMS_OUTPUT.get_line 过程即可。

这是一个小例子:

SQL> create directory tmp as '/tmp/';

Directory created

SQL> CREATE OR REPLACE PROCEDURE write_log AS
  2     l_line VARCHAR2(255);
  3     l_done NUMBER;
  4     l_file utl_file.file_type;
  5  BEGIN
  6     l_file := utl_file.fopen('TMP', 'foo.log', 'A');
  7     LOOP
  8        EXIT WHEN l_done = 1;
  9        dbms_output.get_line(l_line, l_done);
 10        utl_file.put_line(l_file, l_line);
 11     END LOOP;
 12     utl_file.fflush(l_file);
 13     utl_file.fclose(l_file);
 14  END write_log;
 15  /

Procedure created

SQL> BEGIN
  2     dbms_output.enable(100000);
  3     -- write something to DBMS_OUTPUT
  4     dbms_output.put_line('this is a test');
  5     -- write the content of the buffer to a file
  6     write_log;
  7  END;
  8  /

PL/SQL procedure successfully completed

SQL> host cat /tmp/foo.log

this is a test

DBMS_OUTPUT is not the best tool to debug, since most environments don't use it natively. If you want to capture the output of DBMS_OUTPUT however, you would simply use the DBMS_OUTPUT.get_line procedure.

Here is a small example:

SQL> create directory tmp as '/tmp/';

Directory created

SQL> CREATE OR REPLACE PROCEDURE write_log AS
  2     l_line VARCHAR2(255);
  3     l_done NUMBER;
  4     l_file utl_file.file_type;
  5  BEGIN
  6     l_file := utl_file.fopen('TMP', 'foo.log', 'A');
  7     LOOP
  8        EXIT WHEN l_done = 1;
  9        dbms_output.get_line(l_line, l_done);
 10        utl_file.put_line(l_file, l_line);
 11     END LOOP;
 12     utl_file.fflush(l_file);
 13     utl_file.fclose(l_file);
 14  END write_log;
 15  /

Procedure created

SQL> BEGIN
  2     dbms_output.enable(100000);
  3     -- write something to DBMS_OUTPUT
  4     dbms_output.put_line('this is a test');
  5     -- write the content of the buffer to a file
  6     write_log;
  7  END;
  8  /

PL/SQL procedure successfully completed

SQL> host cat /tmp/foo.log

this is a test
信仰 2024-08-12 03:02:18

作为写入文件的替代方案,写入表怎么样?您可以调用自己的 DEBUG.OUTPUT 过程,而不是调用 DBMS_OUTPUT.PUT_LINE,如下所示:

procedure output (p_text varchar2) is
   pragma autonomous_transaction;
begin
   if g_debugging then
      insert into debug_messages (username, datetime, text)
      values (user, sysdate, p_text);
      commit;
   end if;
end;

使用自治事务允许您保留从回滚的事务中生成的调试消息(例如,引发异常后),就像在以下情况下发生的情况一样:你正在使用一个文件。

g_debugging 布尔变量是一个包变量,可以默认为 false,并在需要调试输出时设置为 true。

当然,您需要管理该表以使其不会永远增长!一种方法是每晚/每周运行一项作业,并删除任何“旧”的调试消息。

As an alternative to writing to a file, how about writing to a table? Instead of calling DBMS_OUTPUT.PUT_LINE you could call your own DEBUG.OUTPUT procedure something like:

procedure output (p_text varchar2) is
   pragma autonomous_transaction;
begin
   if g_debugging then
      insert into debug_messages (username, datetime, text)
      values (user, sysdate, p_text);
      commit;
   end if;
end;

The use of an autonomous transaction allows you to retain debug messages produced from transactions that get rolled back (e.g. after an exception is raised), as would happen if you were using a file.

The g_debugging boolean variable is a package variable that can be defaulted to false and set to true when debug output is required.

Of course, you need to manage that table so that it doesn't grow forever! One way would be a job that runs nightly/weekly and deletes any debug messages that are "old".

烟花肆意 2024-08-12 03:02:18

使用
设置服务器输出打开;

例如:

set serveroutput on;

DECLARE
x NUMBER;
BEGIN
x := 72600;
dbms_output.put_line('The variable X = '); dbms_output.put_line(x);
END;

use
set serveroutput on;

for example:

set serveroutput on;

DECLARE
x NUMBER;
BEGIN
x := 72600;
dbms_output.put_line('The variable X = '); dbms_output.put_line(x);
END;

如果您只是在 SQL Plus 中测试您的 PL/SQL,您可以将其定向到如下文件:

spool output.txt
set serveroutput on

begin
  SELECT systimestamp FROM dual INTO time_db;
  DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
end;
/

spool off

Toad 和 SQL Developer 等 IDE 可以通过其他方式捕获输出,但我不熟悉如何操作。

If you are just testing your PL/SQL in SQL Plus you can direct it to a file like this:

spool output.txt
set serveroutput on

begin
  SELECT systimestamp FROM dual INTO time_db;
  DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
end;
/

spool off

IDEs like Toad and SQL Developer can capture the output in other ways, but I'm not familiar with how.

落在眉间の轻吻 2024-08-12 03:02:18

除了 Tony 的回答之外,如果您想了解 PL/SQL 程序将时间花在哪里,还值得查看 Oracle PL/SQL 文档的此 部分。

In addition to Tony's answer, if you are looking to find out where your PL/SQL program is spending it's time, it is also worth checking out this part of the Oracle PL/SQL documentation.

就是爱搞怪 2024-08-12 03:02:18

使用 UTL_FILE 而不是 DBMS_OUTPUT 会将输出重定向到文件:

http://oreilly.com/catalog/oraclebip/chapter/ch06.html

Using UTL_FILE instead of DBMS_OUTPUT will redirect output to a file:

http://oreilly.com/catalog/oraclebip/chapter/ch06.html

一花一树开 2024-08-12 03:02:18

附带说明一下,请记住所有这些输出都是在服务器端生成的。

使用 DBMS_OUTPUT,文本在服务器执行查询时生成并存储在缓冲区中。当服务器完成查询数据检索时,它会重定向到您的客户端应用程序。也就是说,您只有在查询结束时才能获取此信息。

使用UTL_FILE,所有记录的信息都将存储在服务器的文件中。执行完成后,您必须导航到此文件才能获取信息。

希望这有帮助。

As a side note, remember that all this output is generated in the server side.

Using DBMS_OUTPUT, the text is generated in the server while it executes your query and stored in a buffer. It is then redirected to your client app when the server finishes the query data retrieval. That is, you only get this info when the query ends.

With UTL_FILE all the information logged will be stored in a file in the server. When the execution finishes you will have to navigate to this file to get the information.

Hope this helps.

奈何桥上唱咆哮 2024-08-12 03:02:18

可以将文件直接写入托管数据库的数据库服务器,这将随着 PL/SQL 程序的执行而改变。

这使用Oracle 目录 TMP_DIR;您必须声明它,并创建以下过程:

CREATE OR REPLACE PROCEDURE write_log(p_log varchar2)
  -- file mode; thisrequires
--- CREATE OR REPLACE DIRECTORY TMP_DIR as '/directory/where/oracle/can/write/on/DB_server/';
AS
  l_file utl_file.file_type;
BEGIN
  l_file := utl_file.fopen('TMP_DIR', 'my_output.log', 'A');
  utl_file.put_line(l_file, p_log);
  utl_file.fflush(l_file);
  utl_file.fclose(l_file);
END write_log;
/

以下是如何使用它:

1) 从 SQL*PLUS 客户端启动它:

BEGIN
  write_log('this is a test');
  for i in 1..100 loop
    DBMS_LOCK.sleep(1);
    write_log('iter=' || i);
  end loop;
  write_log('test complete');
END;
/

2) 在数据库服务器上,打开 shell 并

    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log

Its possible write a file directly to the DB server that hosts your database, and that will change all along with the execution of your PL/SQL program.

This uses the Oracle directory TMP_DIR; you have to declare it, and create the below procedure:

CREATE OR REPLACE PROCEDURE write_log(p_log varchar2)
  -- file mode; thisrequires
--- CREATE OR REPLACE DIRECTORY TMP_DIR as '/directory/where/oracle/can/write/on/DB_server/';
AS
  l_file utl_file.file_type;
BEGIN
  l_file := utl_file.fopen('TMP_DIR', 'my_output.log', 'A');
  utl_file.put_line(l_file, p_log);
  utl_file.fflush(l_file);
  utl_file.fclose(l_file);
END write_log;
/

Here is how to use it:

1) Launch this from your SQL*PLUS client:

BEGIN
  write_log('this is a test');
  for i in 1..100 loop
    DBMS_LOCK.sleep(1);
    write_log('iter=' || i);
  end loop;
  write_log('test complete');
END;
/

2) on the database server, open a shell and

    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
情深已缘浅 2024-08-12 03:02:18

一个旧线程,但还有另一种选择。

从 9i 开始,您可以使用管道表函数。

首先,创建一个类型作为 varchar 表:

CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767);

其次,将代码包装在管道函数声明中:

CREATE FUNCTION fn_foo (bar VARCHAR2) -- your params
  RETURN t_string_max PIPELINED IS 
  -- your vars
BEGIN
  -- your code
END;
/

将所有 DBMS_OUTPUT.PUT_LINE 替换为 PIPE ROW

最后,这样称呼它:

SELECT * FROM TABLE(fn_foo('param'));

希望有帮助。

An old thread, but there is another alternative.

Since 9i you can use pipelined table function.

First, create a type as a table of varchar:

CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767);

Second, wrap your code in a pipelined function declaration:

CREATE FUNCTION fn_foo (bar VARCHAR2) -- your params
  RETURN t_string_max PIPELINED IS 
  -- your vars
BEGIN
  -- your code
END;
/

Replace all DBMS_OUTPUT.PUT_LINE for PIPE ROW.

Finally, call it like this:

SELECT * FROM TABLE(fn_foo('param'));

Hope it helps.

﹏半生如梦愿梦如真 2024-08-12 03:02:18

试试这个:

SELECT systimestamp INTO time_db FROM dual ;

DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);

Try This:

SELECT systimestamp INTO time_db FROM dual ;

DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文