Y a-t-il un moyen de débusquer la sortie de PL/SQL dans Oracle?

j'ai un script SQL qui est appelé depuis un script shell et qui prend beaucoup de temps à exécuter. Il contient actuellement des déclarations dbms_output.put_line à divers points. Le résultat de ces instructions d'impression apparaissent dans les fichiers journaux, mais seulement une fois le script terminé.

y a-t-il un moyen de s'assurer que la sortie apparaît dans le fichier journal pendant que le script est en cours d'exécution?

38
demandé sur MatthewMartin 2009-09-24 19:52:48

5 réponses

pas vraiment. Le mode de fonctionnement de DBMS_OUTPUT est le suivant: votre bloc PL/SQL s'exécute sur le serveur de base de données sans interaction avec le client. Donc quand vous appelez PUT_LINE, c'est juste mettre ce texte dans un tampon en mémoire sur le serveur. Lorsque votre bloc PL/SQL est terminé, le contrôle est retourné au client (je suppose que SQLPlus dans ce cas); à ce moment-là, le client sort le texte du tampon en appelant GET_LINE, et l'affiche.

donc le seul moyen que vous pouvez faire apparaître la sortie dans le fichier journal plus fréquemment est de briser un grand bloc PL/SQL en plusieurs petits blocs, donc le contrôle est retourné au client plus souvent. Cela peut ne pas être pratique selon ce que votre code fait.

D'autres alternatives sont d'utiliser UTL_FILE pour écrire dans un fichier texte, qui peut être effacé quand vous le souhaitez, ou d'utiliser une procédure de transaction autonome pour insérer des déclarations de débogage dans une table de base de données et de commettre après chacun.

49
répondu Dave Costa 2009-09-24 16:06:19

deux alternatives:

  1. vous pouvez insérer vos détails de journalisation dans une table de journalisation en utilisant une transaction autonome. Vous pouvez interroger cette table de journalisation dans un autre développeur SQLPLUS/Toad/sql, etc... session. Vous devez utiliser une transaction autonome pour qu'il soit possible de lancer votre journalisation sans interférer dans le traitement de la transaction dans votre script sql principal.

  2. une autre alternative est de utilisez une fonction pipelinée qui renvoie vos informations de journalisation. Voir ici pour un exemple: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html lorsque vous utilisez une fonction pipelinée, vous n'avez pas besoin d'utiliser un autre développeur SQLPLUS/Toad/sql, etc... session.

6
répondu tuinstoel 2009-09-25 07:00:35

le tampon de DBMS_OUTPUT est lu lorsque la procédure DBMS_OUTPUT.get_line est appelée. Si votre application client est SQL*Plus, cela signifie qu'elle ne sera purgée qu'une fois la procédure terminée.

vous pouvez appliquer la méthode décrite dans this SO pour écrire le tampon DBMS_OUTPUT à un fichier.

4
répondu Vincent Malgrat 2017-05-23 12:34:19

S'il est possible pour vous, vous devez remplacer les appels à dbms_output.put_line par votre propre fonction.

voici le code pour cette fonction WRITE_LOG -- si vous voulez avoir la possibilité de choisir entre 2 solutions de journalisation:

écrire des journaux à une table dans un autonome "opération 1519220920"

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;
/

ou écrivez directement sur le serveur DB qui héberge votre base de données

utilise le Oracle directory 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

puis le WRITE_LOG procédure qui peut basculer entre les 2 Utilisations, OU être désactivé pour éviter la perte de performances ( 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;
/

et voici comment tester ce qui précède:

1) Lancez ceci ( file mode ) à partir de votre 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) sur le serveur de base de données, ouvrez un shell et

    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
3
répondu J. Chomel 2016-08-23 15:19:18

si vous avez accès au shell système depuis L'environnement PL/SQL, vous pouvez appeler netcat:

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

p_msg - est un message log v_host est un hôte qui exécute un script python qui lit les données depuis la socket sur le port v_port .

j'ai utilisé cette conception lorsque j'ai écrit aplogr pour la surveillance en temps réel de la coque et des rondins pl/sql.

0
répondu olekb 2018-01-10 12:04:27