File Coverage

blib/lib/Oracle/Trace.pm
Criterion Covered Total %
statement 102 107 95.3
branch 22 38 57.8
condition 4 7 57.1
subroutine 18 19 94.7
pod 9 10 90.0
total 155 181 85.6


line stmt bran cond sub pod time code
1             #
2             # $Id: Trace.pm,v 1.6 2003/12/24 20:38:54 oratrc Exp $
3             #
4             package Oracle::Trace;
5              
6 1     1   39790 use 5.008001;
  1         3  
  1         41  
7 1     1   5 use strict;
  1         1  
  1         48  
8 1     1   6 use warnings;
  1         5  
  1         40  
9 1     1   6 use Data::Dumper;
  1         2  
  1         61  
10 1     1   839 use FileHandle;
  1         12452  
  1         5  
11 1     1   932 use Oracle::Trace::Header;
  1         2  
  1         28  
12 1     1   7 use Oracle::Trace::Entry;
  1         1  
  1         16  
13 1     1   459 use Oracle::Trace::Footer;
  1         2  
  1         33  
14 1     1   5 use Oracle::Trace::Utils;
  1         2  
  1         1239  
15              
16             our @ISA = qw(Oracle::Trace::Utils);
17              
18             our $VERSION = do { my @r = (q$Revision: 1.8 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
19              
20             my $DEBUG = $ENV{Oracle_Trace_DEBUG} || 0;
21             my $EXTENDED = $ENV{Oracle_Trace_EXTENDED} || 0;
22             my $RECURSE = $ENV{Oracle_Trace_RECURSE} || 0;
23             my $RESOLUTION = 1000000;
24              
25             =item new
26              
27             Create a new object for a given Orace Trace file.
28              
29             my $o_trc = Oracle::Trace->new($tracefile);
30              
31             =cut
32              
33             sub new {
34 1     1 1 14 my $proto = shift;
35 1 50       6 my $class = ref($proto) ? ref($proto) : $proto;
36 1         12 my $self = bless({
37             _entries => [],
38             _filehandle => undef,
39             _footer => undef,
40             _header => undef,
41             _stats => {},
42             _tracefile => shift,
43             }, $class)->init;
44 1 50       4 $self->debug(Dumper($self)) if $DEBUG >= 2;
45 1         4 return $self;
46             }
47              
48             =item init
49              
50             Initialise the object (check the tracefile).
51              
52             $o_trc->init.
53              
54             =cut
55              
56             sub init {
57 1     1 1 3 my $self = shift;
58 1         7 my $s_file = $self->{_tracefile};
59 1 50       26 $self->fatal("non-existent trace file($s_file)") unless -f $s_file;
60 1 50       10 $self->fatal("non-readable trace file($s_file)") unless -r _;
61 1 50       4 $self->fatal("no-data in trace file($s_file)") unless -s _;
62 1         3 return $self;
63             }
64              
65             =item opentracefile
66              
67             Perform basic exists/read/etc. checks on given tracefile.
68              
69             Returns object or undef.
70              
71             $o_trc = $o_trc->checkfile($tfile);
72              
73             =cut
74              
75             # user_dump_dest or background_dump_dest
76              
77             sub opentracefile {
78 1     1 1 3 my $self = shift;
79 1   50     3 my $s_file = shift || '';
80 1 50       11 my $FH = FileHandle->new($s_file) or $self->fatal("failed to open trace file($s_file) $!");
81 1 50       104 $self->debug("incoming trace file($s_file) => FH($FH)") if $DEBUG;
82 1         2 return $FH;
83             }
84              
85             # Chunk
86              
87             sub parse {
88 1     1 0 351 my $self = shift;
89 1         4 my $FH = $self->opentracefile($self->{_tracefile});
90 1         2 my $i_ent = 0;
91 1         4 my %args = ('_extended'=>$EXTENDED, '_recurse'=>$RECURSE);
92 1         4 local $/ = "=====================\n";
93 1         58 while (<$FH>) {
94 26         57 my $entry = $_;
95 26         150 $entry =~ s#$/$##;
96 26 50       54 $self->debug("entry[$.]") if $DEBUG >= 2;
97 26 100       51 if ($self->{_header}) {
98 25         90 my $e = Oracle::Trace::Entry->new(%args)->parse($entry);
99 25 100 66     300 if ($RECURSE || !$e->{_child}) {
100 4         5 push @{$self->{_entries}}, $e;
  4         6  
101 4         19 $i_ent++;
102             }
103             } else {
104 1         18 $self->{_header} = Oracle::Trace::Header->new(%args)->parse($entry);
105 1         5 my $release = join('',$self->header->keys('Oracle\d+.+?Release'));
106 1 50       16 $RESOLUTION = 100 if $release =~ /Oracle[678]/;
107             }
108             }
109 1 50       4 $self->debug("entries read: $. and retained: $i_ent") if $DEBUG >= 1;
110 1         13 $self->{_footer} = Oracle::Trace::Footer->new(%args)->parse();
111 1 50       22 return $self->{_header} ? $self : undef;
112             };
113              
114             =item header
115              
116             Return the C
object.
117              
118             my $o_hdr = $o_trc->header;
119              
120             =cut
121              
122 7     7 1 784 sub header { my $self = shift; return $self->{_header}; }
  7         50  
123              
124             =item entries
125              
126             Return Entry objects which comply with given regex criteria.
127              
128             my @o_ents = $o_trc->entries('type'=>'EXEC #\d+', 'key'=>dep, 'value'=>0);
129              
130             =cut
131              
132             sub entries {
133 7     7 1 775 my $self = shift;
134 7         13 my %crit = @_;
135 7 100       14 if (keys %crit) {
136 4         5 my @entries = ();
137 4         10 ENTRY:
138 4         5 foreach my $e (@{$self->{_entries}}) {
139 16         46 my $i_vals = my @vals = $e->values(%crit);
140 16 100       46 push(@entries, $e) if $i_vals;
141             }
142 4         21 return @entries;
143             } else {
144 3         6 return @{$self->{_entries}};
  3         172  
145             }
146             }
147              
148             =item oids
149              
150             Return the unique object ids for the currently known Cies
151              
152             my @oids = $o_trc->oids;
153              
154             =cut
155              
156 0     0 1 0 sub oids { return map { $_->oid } $_[0]->entries(@_); }
  0         0  
157              
158             =item footer
159              
160             Return the C
object
161              
162             my $o_ftr = $o_trc->footer;
163              
164             =cut
165              
166 2     2 1 377 sub footer { return $_[0]->{_footer}; }
167              
168             =item test_report
169              
170             Return a B test_report of the current object.
171              
172             print $o_trc->test_report('string');
173              
174             =cut
175              
176             sub test_report {
177 1     1 1 513 my $self = shift;
178 1   50     5 my $type = shift || 'string';
179 1         2 my $report = '';
180 1 50       3 if ($type eq 'string') {
    0          
181 1         6 my $i_rep = my @rep = $self->entries('type'=>'other'); #, 'value' => 'select');
182 1         4 my $x_rep = my @xep = $self->entries('type'=>'other','key'=>'.*','value'=>'.*'); #, 'value' => 'select');
183 1         5 my $rep = $self->mini_report('10', @rep);
184 1         8 $report = join("\n",
185             ' instance name: '.join('',$self->header->value('Instance name')),
186             ' release: '.join('',$self->header->keys('Oracle.+?Release')),
187             ' info: '.join("\n", $self->header->value('other')),
188             ' header lines: '.$self->header->keys.' oid: '.$self->header->oid,
189             ' entries: '.$self->entries,
190             ' root statements: '.$self->entries('type'=>'PARSING IN CURSOR #\d+','key'=>'dep','value'=>'0'),
191             ' parse errors: '.$self->entries('type'=>'PARSE ERROR #\d+','key'=>'dep','value'=>'0'),
192             # ' select oids: '.join(', ', map{$_->oid} @sel),
193             sprintf('%5d', $i_rep).' reports (top ten): '.$rep,
194             ' footer lines: '.$self->footer->keys,
195             '',
196             );
197             } elsif ($type eq 'html') {
198 0         0 $report = 'html unsupported yet...
';
199             } else {
200 0         0 $self->error("unsupported report type($type)");
201             }
202 1         7 return $report;
203             };
204              
205             =item mini_report
206              
207             Return a B string of descending order timings for the statements
208             retrieved from the given objects.
209              
210             my $s_str = $o_trc->mini_report($i_max, @o_objs);
211              
212             Note that we use microsecond resolution for Oracle 9i and above and
213             centisecond resolution otherwise
214              
215             =cut
216              
217             sub mini_report {
218 1     1 1 2 my $self = shift;
219 1         2 my $i_max = shift;
220 1         9 my @objs = @_;
221              
222 1         2 my %rep = ();
223             STMT:
224 1         3 foreach my $o (@objs) {
225 4         15 ($rep{$o->elapsed}) = $o->statement;
226 4 50       14 if ($EXTENDED) {
227 0         0 $rep{$o->elapsed} .= "\n\t\t".join("\n\t\t", $o->stats);
228             }
229             }
230 1         2 my $rep = "\n";
231 1         2 my $i_rep = 0;
232 4         9 REP:
233 1         7 foreach my $k (reverse sort {$a <=> $b} keys %rep) {
234 4         5 $i_rep++;
235 4         48 $rep .= sprintf('%15.3f', $k/$RESOLUTION)." secs <- $rep{$k}\n";
236 4 50       9 last REP if $i_rep >= 10;
237             }
238              
239 1         6 return $rep;
240             }
241            
242             1;
243              
244             __END__