シェルスクリプト内から呼び出され、実行に時間がかかるSQLスクリプトがあります。現在dbms_output.put_line
、さまざまな時点でのステートメントが含まれています。これらの印刷ステートメントからの出力はログファイルに表示されますが、スクリプトが完了した場合に限ります。
スクリプトの実行中に出力がログファイルに表示されるようにする方法はありますか?
シェルスクリプト内から呼び出され、実行に時間がかかるSQLスクリプトがあります。現在dbms_output.put_line
、さまざまな時点でのステートメントが含まれています。これらの印刷ステートメントからの出力はログファイルに表示されますが、スクリプトが完了した場合に限ります。
スクリプトの実行中に出力がログファイルに表示されるようにする方法はありますか?
あまり。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からこれ(ファイルモード)を起動します。
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スクリプトでのトランザクション処理を妨げることなくログをコミットできるようにするには、自律型トランザクションを使用する必要があります。
もう1つの方法は、ログ情報を返すパイプライン関数を使用することです。例については、こちらを参照してください。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
バッファをファイルに書き込むことができます。
を使用して、セッションメタデータMODULEおよび/またはACTIONを設定しdbms_application_info()
ます。
OEMで監視します。例:
Module: ArchiveData
Action: xxx of xxxx
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を作成したときにこの設計を使用しました。