Markus Winand's Blog

Oracle Trace File Rotation

In Maintainability on 2010-02-01 at 17:30

Under very rare circumstances, I need Oracle SQL trace files from a long period of time. Because trace files usually grow large—especially over several days—there is the need to rotate the trace file during that time so that they can be compressed and put away. The problem is that there is no “rotate tracefile“ button in Oracle. However, I have found a “undocumented feature“ that does exactly that—without disabling tracing.

My procedure uses the close_trace call of oradebug. This call closes the currently written trace file for a session. Alex Gorbachev has used this to delete big trace files that are still open. My procedure goes a little bit further and exposes one more side effect of oradebug close_trace.

Warning: The technique described here uses the undocumented and unsupported oradebug facility. Although I am not aware of any negative side effects of this procedure, the use of this method takes place at your own risk.

The oradebug utility can be used from the SQL*Plus prompt. If you have an account with sufficient rights (sigh) you can attach to any session using the oradebug setorapid command. To obtain the required Oracle PID, just query the v$process view:

SQL> SELECT s.sid, s.serial#, p.pid 
       FROM v$session s, v$process p 
      WHERE s.paddr=p.addr;

       SID    SERIAL#        PID
---------- ---------- ----------
         1          1          2
[... skipped ...]
        20       3126         21

26 rows selected.

SQL> oradebug setorapid 21
Oracle pid: 21, Unix process pid: 145, image: oracle@test.fatalmind.com
SQL>

Once attached to a specific process, every oradebug operation is applied to that particular process. The trick to rotate the trace file is very simple and exploits a “feature” of UNIX file systems; that is, that the name of the file is used only at the moment the file is opened. Once the file is open, all access is managed with the so called inode and the name is not relevant for the read and write operations anymore. The inode system has some more implications, one of them is frequently used to rotate log files without data loss. Another implications makes it hard to delete open files, as Alex Gorbachev explained.

The log rotation trick is to rename the open file and then cause the writing process to re-open that file. All write operations to the renamed file will be written properly to new file name—more correctly expressed: to the file which can be accessed under the new name. If the writing process re-opens the file under its original name, it will create a new file because there is no file with that name anymore. Every subsequent write operation goes to the new file. The original file will not grow anymore and can be taken away safely.

Although the oradebug command name close_trace doesn’t suggest that the trace file is reopened, it is—if SQL tracing is enabled. So we have everything to rotate a trace file. Consider the following example:

$ ls -lrt TEST_ora_14457.trc*
-rw-r----- 1 oracle oinstall 14758723 2010-02-01 TEST_ora_14457.trc
$ mv  TEST_ora_14457.trc  TEST_ora_14457.trc.old

After renaming the file, the file still grows as the SQL trace is written. You can now use oradebug close_trace to actually rotate the file:

SQL> oradebug close_trace
Statement processed.
SQL> 

The verification in the file system shows that the ‘old’ file became bigger, and the new file is also filling up:

$ ls -lrt TEST_ora_14457.trc*
-rw-r----- 1 oracle oinstall 18878704 2010-02-01 TEST_ora_14457.trc.old
-rw-r----- 1 oracle oinstall  1555972 2010-02-01 TEST_ora_14457.trc
$ 

Because I often need to trace many sessions, I wrote a very tiny script (switch_traces.sql) that creates another script to re-open all trace files:

set echo off
set feedback off
set pages 0
set heading off
set define off

spool oradebug_close_traces.sql

select cmd from (
select pid, 1 o, 'oradebug setorapid ' || pid cmd from v$process
UNION ALL
select pid, 2 o, 'oradebug flush' from v$process
UNION ALL
select pid, 3 o, 'oradebug close_trace' from v$process) order by pid,o;

spool off

prompt
prompt c&p >>> @oradebug_close_traces.sql <<< to switch traces

set feedback on
set pages 1000
set heading on
set echo on

This script will close all traces in all sessions and continue tracing to new files if SQL tracing is enabled. You might want to add additional where clauses to limit your scope—e.g., to skip background processes. The script will also issue a flush before the close_trace. I don’t know if this is required or not, it doesn’t seem to make any harm. The use of the script is very simple:

SQL> @switch_traces.sql
SQL> set echo off
oradebug setorapid 1
oradebug flush
oradebug close_trace

[... skipped ...]

oradebug setorapid 29
oradebug flush
oradebug close_trace

c&p >>> @oradebug_close_traces.sql <<< to switch traces
SQL> @oradebug_close_traces.sql
SQL> oradebug setorapid 1
ORA-00072: process "Unix process pid: 0, image: PSEUDO" is not active
SQL> oradebug flush
Statement processed.
SQL> oradebug close_trace
Statement processed.
SQL> oradebug setorapid 2
Oracle pid: 2, Unix process pid: 137, image: oracle@test.fatalmind.com
SQL> oradebug flush
Statement processed.
SQL> oradebug close_trace
Statement processed.

[... skipped ...]

Oracle pid: 29, Unix process pid: 138, image: oracle@test.fatalmind.com
SQL> oradebug flush
Statement processed.
SQL> oradebug close_trace
Statement processed.
SQL>

In case you have not forgotten to rename your trace files you will see the new files growing now.

Read also my previous article To Trace or Not to Trace for information about fine grained SQL tracing.


Do not use offset for pagination. Learn why.

SQL Performance Tuning Book for developers