J'ai besoin de déboguer en pl/sql pour comprendre le temps des procédures, je veux utiliser:
SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
mais je ne comprends pas où va la sortie et comment puis-je la rediriger vers un fichier journal qui contiendra toutes les données que je veux collecter?
DBMS_OUTPUT
n'est pas le meilleur outil pour déboguer, car la plupart des environnements ne l'utilisent pas en mode natif. Si vous voulez capturer la sortie de DBMS_OUTPUT
cependant, vous utiliseriez simplement le DBMS_OUTPUT.get_line
procédure.
Voici un petit exemple:
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
Au lieu d'écrire dans un fichier, pourquoi ne pas écrire dans une table? Au lieu d'appeler DBMS_OUTPUT.PUT_LINE, vous pouvez appeler votre propre procédure DEBUG.OUTPUT, par exemple:
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;
L’utilisation d’une transaction autonome vous permet de conserver les messages de débogage générés à partir de transactions annulées (par exemple après la levée d’une exception), comme ce serait le cas si vous utilisiez un fichier.
La variable boolean g_debugging est une variable de package qui peut être définie par défaut sur false et définie sur true lorsque la sortie de débogage est requise.
Bien sûr, vous devez gérer cette table afin qu'elle ne croisse pas pour toujours! Une façon serait un travail qui s'exécute tous les soirs/toutes les semaines et supprime les messages de débogage "anciens".
Si vous testez simplement votre PL/SQL dans SQL Plus, vous pouvez le diriger vers un fichier comme celui-ci:
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
Les IDE tels que Toad et SQL Developer peuvent capturer la sortie de différentes manières, mais je ne connais pas comment.
utilisez set serveroutput on;
par exemple:
set serveroutput on;
DECLARE
x NUMBER;
BEGIN
x := 72600;
dbms_output.put_line('The variable X = '); dbms_output.put_line(x);
END;
En plus de la réponse de Tony, si vous cherchez à savoir où votre programme PL/SQL consacre son temps, cela vaut également la peine de vérifier this une partie de la documentation Oracle PL/SQL.
Notez également que toute cette sortie est générée côté serveur.
À l'aide de DBMS_OUTPUT, le texte est généré sur le serveur pendant l'exécution de la requête et stocké dans une mémoire tampon. Il est ensuite redirigé vers votre application client lorsque le serveur termine la récupération des données de la requête. En d'autres termes, vous n'obtenez ces informations qu'à la fin de la requête.
Avec UTL_FILE, toutes les informations enregistrées seront stockées dans un fichier sur le serveur. Lorsque l'exécution est terminée, vous devrez accéder à ce fichier pour obtenir les informations.
J'espère que cela t'aides.
En utilisant UTL_FILE
au lieu de DBMS_OUTPUT
va rediriger la sortie vers un fichier:
Il est possible d’écrire un fichier directement sur le serveur de base de données qui héberge votre base de données, ce qui changera tout au long de l’exécution de votre programme PL/SQL.
Ceci utilise le répertoire OracleTMP_DIR
; vous devez le déclarer et créer la procédure ci-dessous:
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;
/
Voici comment l'utiliser:
1) Lancez-le à partir de votre client 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) 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