シェルスクリプト内から呼び出され、実行に時間がかかるSQLスクリプトがあります。現在、dbms_output.put_line
さまざまな時点でのステートメント。これらのprintステートメントからの出力はログファイルに表示されますが、スクリプトが完了すると1回だけです。
スクリプトの実行中に出力がログファイルに表示されるようにする方法はありますか?
あんまり。 DBMS_OUTPUTの機能は次のとおりです。PL/ SQLブロックは、クライアントとの対話なしでデータベースサーバー上で実行されます。したがって、PUT_LINEを呼び出すと、そのテキストがサーバー上のメモリ内のバッファーに入れられます。 PL/SQLブロックが完了すると、制御がクライアントに返されます(この場合はSQLPlusを想定しています)。その時点で、クライアントはGET_LINEを呼び出してバッファからテキストを取得し、表示します。
したがって、ログファイルに出力をより頻繁に表示させる唯一の方法は、大きなPL/SQLブロックを複数の小さなブロックに分割することです。そのため、制御がより頻繁にクライアントに返されます。これは、コードの実行内容によっては実用的ではない場合があります。
他の方法としては、UTL_FILEを使用してテキストファイルに書き込みます。このファイルはいつでもフラッシュできます。または、自律トランザクションプロシージャを使用して、データベーステーブルにデバッグステートメントを挿入し、各ステートメントの後にコミットします。
可能であれば、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;
/
これは、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_LOG
2つの使用を切り替えることができるプロシージャ、またはパフォーマンスの損失を避けるために非アクティブにするプロシージャ(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からこの(file mode)を起動します。
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
2つの選択肢:
自律型トランザクションを使用して、ロギングテーブルにロギングの詳細を挿入できます。このロギングテーブルは、別のSQLPLUS/Toad/sql開発者などのセッションでクエリできます。メインのSQLスクリプトでトランザクション処理を妨げることなくロギングをコミットできるようにするには、自律型トランザクションを使用する必要があります。
別の方法は、ログ情報を返すパイプライン関数を使用することです。例についてはこちらをご覧ください: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html 使用する場合別のSQLPLUS/Toad/sql開発者などのセッションを使用する必要がないパイプライン関数。
DBMS_OUTPUT
のバッファは、プロシージャDBMS_OUTPUT.get_line
が呼び出されたときに読み込まれます。クライアントアプリケーションがSQL * Plusである場合、プロシージャが終了した後にのみフラッシュされることを意味します。
このSO で説明されている方法を適用して、DBMS_OUTPUT
バッファーをファイルに書き込むことができます。
PL/SQL環境からシステムシェルにアクセスできる場合は、netcatを呼び出すことができます。
BEGIN RUN_Shell('echo "'||p_msg||'" | nc '||p_Host||' '||p_port||' -w 5'); END;
p_msg
-ログメッセージですv_Host
は、ポートv_port
のソケットからデータを読み取るpythonスクリプトを実行しているホストです。
aplogr をシェルとpl/sqlのリアルタイムログモニタリング用に記述したときに、この設計を使用しました。