53

シェルスクリプト内から呼び出され、実行に時間がかかるSQLスクリプトがあります。現在dbms_output.put_line、さまざまな時点でのステートメントが含まれています。これらの印刷ステートメントからの出力はログファイルに表示されますが、スクリプトが完了した場合に限ります。

スクリプトの実行中に出力がログファイルに表示されるようにする方法はありますか?

4

6 に答える 6

62

あまり。DBMS_OUTPUTの動作方法は次のとおりです。PL/SQLブロックは、クライアントとの対話なしでデータベース・サーバー上で実行されます。したがって、PUT_LINEを呼び出すと、そのテキストがサーバー上のメモリ内のバッファに入れられるだけです。PL / SQLブロックが完了すると、制御がクライアントに戻されます(この場合はSQLPlusを想定しています)。その時点で、クライアントはGET_LINEを呼び出してバッファからテキストを取得し、それを表示します。

したがって、出力をログファイルに頻繁に表示させる唯一の方法は、大きなPL / SQLブロックを複数の小さなブロックに分割することです。これにより、制御がクライアントに返される頻度が高くなります。コードの動作によっては、これは実用的でない場合があります。

他の方法は、UTL_FILEを使用してテキストファイルに書き込むことです。テキストファイルはいつでもフラッシュできます。または、自律トランザクションプロシージャを使用して、デバッグステートメントをデータベーステーブルに挿入し、各ファイルの後にコミットします。

于 2009-09-24T16:06:19.317 に答える
14

可能であれば、dbms_output.put_lineへの呼び出しを独自の関数に置き換える必要があります。

この関数のコードは次のWRITE_LOG とおりです。2つのロギングソリューションから選択できるようにしたい場合は、次のようにします。

自律型トランザクションでテーブルにログを書き込む

CREATE OR REPLACE PROCEDURE to_dbg_table(p_log varchar2)
  -- table mode: 
  -- requires
  -- CREATE TABLE dbg (u varchar2(200)   --- username
  --                 , d timestamp       --- date
  --                 , l varchar2(4000)  --- log 
  -- );
AS
   pragma autonomous_transaction;
BEGIN
  insert into dbg(u, d, l) values (user, sysdate, p_log);
  commit;
END to_dbg_table;
/

または、データベースをホストするDBサーバーに直接書き込みます

これはOracleディレクトリを使用します TMP_DIR

CREATE OR REPLACE PROCEDURE to_dbg_file(p_fname varchar2, p_log varchar2)
  -- file mode: 
  -- requires
--- 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', p_fname, 'A');
  utl_file.put_line(l_file, p_log);
  utl_file.fflush(l_file);
  utl_file.fclose(l_file);
END to_dbg_file;
/


WRITE_LOG

次に、WRITE_LOG2つの使用を切り替えるか、パフォーマンスの低下を回避するために非アクティブ化できる手順(g_DEBUG:=FALSE)。

CREATE OR REPLACE PROCEDURE write_log(p_log varchar2) AS
  -- g_DEBUG can be set as a package variable defaulted to FALSE
  -- then change it when debugging is required
  g_DEBUG boolean := true;
  -- the log file name can be set with several methods...
  g_logfname varchar2(32767) := 'my_output.log';
  -- choose between 2 logging solutions:
  -- file mode: 
  g_TYPE varchar2(7):= 'file';
  -- table mode: 
  --g_TYPE varchar2(7):= 'table';
  -----------------------------------------------------------------
BEGIN
  if g_DEBUG then
    if g_TYPE='file' then
      to_dbg_file(g_logfname, p_log);
    elsif g_TYPE='table' then
      to_dbg_table(p_log);
    end if;
  end if;  
END write_log;
/

上記をテストする方法は次のとおりです。

1)SQLPLUSからこれ(ファイルモード)を起動します。

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)データベースサーバーで、シェルを開き、

    tail -f -n500/directory/where/oracle/can/write/on/DB_server/my_output.log
于 2016-08-23T15:19:18.253 に答える
8

2つの選択肢:

  1. 自律型トランザクションを使用して、ログの詳細をログテーブルに挿入できます。このロギングテーブルは、別のSQLPLUS / Toad/sql開発者などのセッションでクエリできます。メインのSQLスクリプトでのトランザクション処理を妨げることなくログをコミットできるようにするには、自律型トランザクションを使用する必要があります。

  2. もう1つの方法は、ログ情報を返すパイプライン関数を使用することです。例については、こちらを参照してください。http: //berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.htmlパイプライン関数を使用する場合、別のSQLPLUS / Toad/sql開発者などを使用する必要はありません。 ...セッション。

于 2009-09-25T07:00:35.350 に答える
3

DBMS_OUTPUTプロシージャDBMS_OUTPUT.get_lineが呼び出されると、のバッファが読み取られます。クライアントアプリケーションがSQL*Plusの場合、プロシージャが終了したときにのみフラッシュされることを意味します。

このSOで説明されている方法を適用して、DBMS_OUTPUTバッファをファイルに書き込むことができます。

于 2009-09-24T16:04:29.413 に答える
3

を使用して、セッションメタデータMODULEおよび/またはACTIONを設定しdbms_application_info()ます。
OEMで監視します。例:

Module: ArchiveData
Action: xxx of xxxx
于 2019-10-08T21:42:38.293 に答える
0

PL / SQL環境からシステムシェルにアクセスできる場合は、netcatを呼び出すことができます。

 BEGIN RUN_SHELL('echo "'||p_msg||'" | nc '||p_host||' '||p_port||' -w 5'); END;

p_msg-ログメッセージ v_hostは、ポートのソケットからデータを読み取るPythonスクリプトを実行しているホストですv_port

リアルタイムのシェルおよびpl/sqlログ監視用のaplogrを作成したときにこの設計を使用しました。

于 2017-11-27T19:20:13.707 に答える