Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
e180b0af
Commit
e180b0af
authored
Apr 26, 2001
by
Chris McDonough
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added detailed profile mode.
parent
be02b281
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
389 additions
and
141 deletions
+389
-141
utilities/requestprofiler.py
utilities/requestprofiler.py
+389
-141
No files found.
utilities/requestprofiler.py
View file @
e180b0af
#!/usr/bin/env python
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
...
...
@@ -85,66 +86,157 @@
""" Request log profiler script """
__version__
=
'$Revision: 1.
2
$'
[
11
:
-
2
]
__version__
=
'$Revision: 1.
3
$'
[
11
:
-
2
]
import
string
,
sys
,
time
,
getopt
import
string
,
sys
,
time
,
getopt
,
tempfile
class
ProfileException
(
Exception
):
pass
class
Request
:
def
__init__
(
self
):
self
.
start
=
0
self
.
end
=
0
self
.
url
=
None
self
.
start
=
None
self
.
method
=
None
self
.
t_recdinput
=
None
self
.
isize
=
None
self
.
t_recdoutput
=
None
self
.
osize
=
None
self
.
httpcode
=
None
self
.
t_end
=
None
self
.
elapsed
=
"I"
self
.
url
=
''
self
.
active
=
"NA"
def
put
(
self
,
code
,
t
,
desc
):
if
code
not
in
(
'A'
,
'B'
,
'I'
,
'E'
):
raise
"unknown request code %s"
%
code
if
code
==
'B'
:
self
.
url
=
desc
self
.
start
=
t
if
code
==
'E'
:
self
.
end
=
t
self
.
elapsed
=
int
(
self
.
end
-
self
.
start
)
self
.
method
,
self
.
url
=
string
.
split
(
string
.
strip
(
desc
))
elif
code
==
"I"
:
self
.
t_recdinput
=
t
self
.
isize
=
string
.
strip
(
desc
)
elif
code
==
"A"
:
self
.
t_recdoutput
=
t
self
.
httpcode
,
self
.
osize
=
string
.
split
(
string
.
strip
(
desc
))
elif
code
==
'E'
:
self
.
t_end
=
t
self
.
elapsed
=
int
(
self
.
t_end
-
self
.
start
)
def
isfinished
(
self
):
return
not
self
.
elapsed
==
"I"
def
prettystart
(
self
):
if
self
.
start
is
not
None
:
t
=
time
.
localtime
(
self
.
start
)
return
time
.
strftime
(
'%Y-%m-%dT%H:%M:%S'
,
t
)
else
:
return
"NA"
def
win
(
self
):
if
self
.
t_recdinput
is
not
None
and
self
.
start
is
not
None
:
return
self
.
t_recdinput
-
self
.
start
else
:
return
"NA"
def
wout
(
self
):
if
self
.
t_recdoutput
is
not
None
and
self
.
t_recdinput
is
not
None
:
return
self
.
t_recdoutput
-
self
.
t_recdinput
else
:
return
"NA"
def
wend
(
self
):
if
self
.
t_end
is
not
None
and
self
.
t_recdoutput
is
not
None
:
return
self
.
t_end
-
self
.
t_recdoutput
else
:
return
"NA"
def
endstage
(
self
):
if
self
.
t_end
is
not
None
:
stage
=
"E"
elif
self
.
t_recdoutput
is
not
None
:
stage
=
"A"
elif
self
.
t_recdinput
is
not
None
:
stage
=
"I"
else
:
stage
=
"B"
return
stage
def
total
(
self
):
stage
=
self
.
endstage
()
if
stage
==
"B"
:
return
0
if
stage
==
"I"
:
return
self
.
t_recdinput
-
self
.
start
if
stage
==
"A"
:
return
self
.
t_recdoutput
-
self
.
start
if
stage
==
"E"
:
return
self
.
elapsed
def
prettyisize
(
self
):
if
self
.
isize
is
not
None
:
return
self
.
isize
else
:
return
"NA"
def
prettyosize
(
self
):
if
self
.
osize
is
not
None
:
return
self
.
osize
else
:
return
"NA"
def
prettyhttpcode
(
self
):
if
self
.
httpcode
is
not
None
:
return
self
.
httpcode
else
:
return
"NA"
def
__str__
(
self
):
body
=
(
self
.
prettystart
(),
self
.
win
(),
self
.
wout
(),
self
.
wend
(),
self
.
total
(),
self
.
endstage
(),
self
.
prettyosize
(),
self
.
prettyhttpcode
(),
self
.
active
,
self
.
url
)
return
self
.
fmt
%
body
fmt
=
"%19s %4s %4s %4s %3s %1s %7s %4s %4s %s"
def
getheader
(
self
):
body
=
(
'Start'
,
'WIn'
,
'WOut'
,
'WEnd'
,
'Tot'
,
'S'
,
'OSize'
,
'Code'
,
'Act'
,
'URL'
)
return
self
.
fmt
%
body
class
Cumulative
:
def
__init__
(
self
,
url
):
self
.
url
=
url
self
.
request
s
=
[]
self
.
time
s
=
[]
self
.
hangs
=
0
self
.
allelapsed
=
None
def
put
(
self
,
request
):
if
not
request
.
end
:
self
.
hangs
=
self
.
hangs
+
1
self
.
requests
.
append
(
request
)
elapsed
=
request
.
elapsed
if
elapsed
==
"I"
:
self
.
hangs
=
self
.
hangs
+
1
self
.
times
.
append
(
elapsed
)
def
all
(
self
):
if
self
.
allelapsed
==
None
:
self
.
allelapsed
=
[]
for
request
in
self
.
request
s
:
self
.
allelapsed
.
append
(
request
.
elapsed
)
for
elapsed
in
self
.
time
s
:
self
.
allelapsed
.
append
(
elapsed
)
self
.
allelapsed
.
sort
()
return
self
.
allelapsed
def
__str__
(
self
):
if
verbose
:
url
=
self
.
url
else
:
url
=
self
.
url
[:
22
]
s
=
"%s
\
t
%s
\
t
%s
\
t
%s
\
t
%s
\
t
%s
\
t
%s
\
t
%s"
%
(
self
.
hangs
,
self
.
hits
(),
self
.
total
(),
self
.
max
(),
self
.
min
(),
self
.
median
(),
self
.
mean
(),
url
body
=
(
self
.
hangs
,
self
.
hits
(),
self
.
total
(),
self
.
max
(),
self
.
min
(),
self
.
median
(),
self
.
mean
(),
self
.
url
)
return
s
return
self
.
fmt
%
body
def
getheader
(
self
):
return
self
.
fmt
%
(
'Hangs'
,
'Hits'
,
'Total'
,
'Max'
,
'Min'
,
'Median'
,
'Mean'
,
'URL'
)
fmt
=
"%5s %5s %5s %5s %5s %6s %5s %s"
def
hits
(
self
):
return
len
(
self
.
request
s
)
return
len
(
self
.
time
s
)
def
max
(
self
):
return
max
(
self
.
all
())
...
...
@@ -153,7 +245,7 @@ class Cumulative:
return
min
(
self
.
all
())
def
mean
(
self
):
l
=
len
(
self
.
request
s
)
l
=
len
(
self
.
time
s
)
if
l
==
0
:
return
"I"
else
:
...
...
@@ -177,76 +269,124 @@ class Cumulative:
i2
=
i
+
1
v1
=
all
[
i
]
v2
=
all
[
i2
]
if
v1
==
"
I"
or
v2
==
"I
"
:
return
"I"
if
v1
==
"
NA"
or
v2
==
"NA
"
:
return
"I"
else
:
return
(
all
[
i
]
+
all
[
i2
])
/
2
def
total
(
self
):
t
=
0
all
=
self
.
all
()
if
len
(
all
)
==
1
:
return
all
[
0
]
for
elapsed
in
self
.
all
():
if
elapsed
!=
"I"
:
t
=
t
+
elapsed
for
elapsed
in
all
:
if
elapsed
==
"I"
:
continue
t
=
t
+
elapsed
return
t
def
analyze
(
f
,
top
,
sortf
,
start
=
None
,
end
=
None
):
requests
=
{}
def
parsebigmlogline
(
line
):
tup
=
string
.
split
(
line
,
None
,
3
)
if
len
(
tup
)
==
3
:
code
,
id
,
timestr
=
tup
return
code
,
id
,
timestr
,
''
elif
len
(
tup
)
==
4
:
return
tup
else
:
return
None
def
analyze
(
f
,
top
,
sortf
,
start
=
None
,
end
=
None
,
mode
=
'cumulative'
):
beginrequests
=
{}
cumulative
=
{}
finished
=
{}
unfinished
=
{}
while
1
:
line
=
f
.
readline
()
line
=
string
.
strip
(
line
)
if
not
line
:
break
tup
=
string
.
split
(
line
,
None
,
3
)
if
len
(
tup
)
==
3
:
code
,
id
,
timestr
=
tup
desc
=
''
elif
len
(
tup
)
==
4
:
code
,
id
,
timestr
,
desc
=
tup
else
:
line
=
string
.
strip
(
line
)
tup
=
parsebigmlogline
(
line
)
if
tup
is
None
:
print
"Could not interpret line: %s"
%
line
continue
#gmtimetup = time.strptime(timestr, '%Y-%m-%dT%H:%M:%S')
# this doesn't work on windows
code
,
id
,
timestr
,
desc
=
tup
timestr
=
string
.
strip
(
timestr
)
year
=
int
(
timestr
[:
4
])
month
=
int
(
timestr
[
5
:
7
])
day
=
int
(
timestr
[
8
:
10
])
hour
=
int
(
timestr
[
11
:
13
])
minute
=
int
(
timestr
[
14
:
16
])
second
=
int
(
timestr
[
17
:
19
])
gmttup
=
(
year
,
month
,
day
,
hour
,
minute
,
second
,
0
,
0
,
-
1
)
fromepoch
=
time
.
mktime
(
gmttup
)
if
start
is
not
None
:
if
fromepoch
<
start
:
continue
if
end
is
not
None
:
if
fromepoch
>
end
:
continue
request
=
requests
.
get
(
id
)
fromepoch
=
getdate
(
timestr
)
if
start
is
not
None
and
fromepoch
<
start
:
continue
if
end
is
not
None
and
fromepoch
>
end
:
break
request
=
unfinished
.
get
(
id
)
if
request
is
None
:
if
code
!=
"B"
:
continue
# garbage at beginning of file
request
=
Request
()
requests
[
id
]
=
request
request
.
put
(
code
,
fromepoch
,
desc
)
unfinished
[
id
]
=
request
request
.
put
(
code
,
int
(
fromepoch
),
desc
)
if
request
.
isfinished
():
del
unfinished
[
id
]
finished
[
id
]
=
request
request
.
active
=
len
(
unfinished
)
finished
.
update
(
unfinished
)
requests
=
finished
.
values
()
requests
=
requests
.
values
()
cumulative
=
{}
for
request
in
requests
:
url
=
request
.
url
stats
=
cumulative
.
get
(
url
)
if
stats
is
None
:
stats
=
Cumulative
(
url
)
cumulative
[
url
]
=
stats
stats
.
put
(
request
)
requests
=
cumulative
.
values
()
requests
.
sort
(
sortf
)
write
(
requests
,
top
,
"Hangs
\
t
Hits
\
t
Total
\
t
Max
\
t
Min
\
t
Median
\
t
Mean
\
t
URL"
)
def
write
(
requests
,
top
=
0
,
header
=
''
):
i
=
0
print
header
for
stat
in
requests
:
i
=
i
+
1
print
stat
if
i
==
top
:
break
if
mode
==
'cumulative'
:
for
request
in
requests
:
url
=
request
.
url
stats
=
cumulative
.
get
(
url
)
if
stats
is
None
:
stats
=
Cumulative
(
url
)
cumulative
[
url
]
=
stats
stats
.
put
(
request
)
cumulative
=
cumulative
.
values
()
if
mode
==
'cumulative'
:
dict
=
cumulative
elif
mode
==
'detailed'
:
dict
=
requests
else
:
raise
"Invalid mode."
dict
.
sort
(
sortf
)
write
(
dict
,
top
)
def
write
(
requests
,
top
=
0
):
if
len
(
requests
)
==
0
:
print
"No data.
\
n
"
return
i
=
0
header
=
requests
[
0
].
getheader
()
print
header
for
stat
in
requests
:
i
=
i
+
1
if
verbose
:
print
str
(
stat
)
else
:
print
str
(
stat
)[:
78
]
if
i
==
top
:
break
def
getdate
(
val
):
try
:
val
=
string
.
strip
(
val
)
year
,
month
,
day
=
int
(
val
[:
4
]),
int
(
val
[
5
:
7
]),
int
(
val
[
8
:
10
])
hour
,
minute
,
second
=
int
(
val
[
11
:
13
]),
int
(
val
[
14
:
16
]),
int
(
val
[
17
:
19
])
t
=
time
.
mktime
((
year
,
month
,
day
,
hour
,
minute
,
second
,
0
,
0
,
-
1
))
return
t
except
:
raise
ProfileException
,
"bad date %s"
%
val
def
codesort
(
v1
,
v2
):
v1
=
v1
.
endstage
()
v2
=
v2
.
endstage
()
if
v1
==
v2
:
return
0
if
v1
==
"B"
:
return
-
1
# v1 is smaller than v2
if
v1
==
"I"
:
if
v2
==
"B"
:
return
1
# v1 is larger than v2
else
:
return
-
1
if
v1
==
"A"
:
if
v2
in
[
'B'
,
'I'
]:
return
1
else
:
return
-
1
if
v1
==
"E"
:
return
1
class
Sort
:
def
__init__
(
self
,
fname
,
ascending
=
0
):
...
...
@@ -269,37 +409,101 @@ class Sort:
def
detailedusage
():
details
=
usage
(
0
)
pname
=
sys
.
argv
[
0
]
details
=
details
+
"""
Each line in the profile indicates information about a Zope method (URL)
collected via the detailed request log (the -M log).
Reports are of two types: cumulative or detailed. The default is cumulative.
Data is taken from the Zope detailed request log (the -M log).
For cumulative reports, each line in the profile indicates information
about a Zope method (URL) collected via the detailed request log (the -M log).
For detailed reports, each line in the profile indicates information about
a single request.
'filename' is the path to the '-M' log that contains detailed request data.
If a 'sort' value is specified, sort the profile info by the spec. The sort
spec may be any of 'hits', 'hangs', 'max', 'min', 'mean', 'median', or 'total'.
The default is 'total'. The sort order is decending unless indicated.
If a 'sort' value is specified, sort the profile info by the spec. The sort
order is descending unless indicated. The default cumulative sort spec is
'total'. The default detailed sort spec is 'start'.
For cumulative reports, the following sort specs are accepted:
'hits' -- the number of hits against the method
'hangs' -- the number of unfinished requests to the method
'max' -- the maximum time in secs taken by a request to this method
'min' -- the minimum time in secs taken by a request to this method
'mean' -- the mean time in secs taken by a request to this method
'median' -- the median time in secs taken by a request to this method
'total' -- the total time in secs across all requests to this method
'url' -- the URL/method name (ascending)
For detailed (non-cumulative) reports, the following sort specs are accepted:
'start' -- the start time of the request to ZServer (ascending)
'win' -- the num of secs ZServer spent waiting for input from client
'wout' -- the secs ZServer spent waiting for output from ZPublisher
'wend' -- the secs ZServer spent sending data to the client
'total' -- the secs taken for the request from begin to end
'endstage' -- the last successfully completed request stage (B, I, A, E)
'osize' -- the size in bytes of output provided by ZPublisher
'httpcode' -- the HTTP response code provided by ZPublisher (ascending)
'active' -- total num of requests pending at the end of this request
'url' -- the URL/method name (ascending)
'hits' -- the number of hits against the method
'hangs' -- the number of unfinished requests to the method
'max' -- the maximum time in secs taken by a request to this method
'min' -- the minimum time in secs taken by a request to this method
'mean' -- the mean time in secs taken by a request to this method
'median' -- the median time in secs taken by a request to this method
'total' -- the total time in secs across all requests to this method
'url' -- the URL/method name (ascending)
NOTE: 'active' count may be fooled by Zope restarts, which aren't
reflected in the -M log.
If the 'top' argument is specified, only report on the top 'n'
request
s in
the
log (as per the sort). The default is 10
.
If the 'top' argument is specified, only report on the top 'n'
entrie
s in
the
profile (as per the sort). The default is to show all data in the profile
.
If the 'verbose' argument is specified, do not trim url to fit into 80 cols.
If the 'today' argument is specified, limit results to hits received today."""
If the 'today' argument is specified, limit results to hits received today.
If the 'start' argument is specified in the form 'DD/MM/YYYY HH:MM:SS' (UTC),
limit results to hits received after this date/time.
If the 'end' argument is specified in the form 'DD/MM/YYYY HH:MM:SS' (UTC),
limit results to hits received before this date/time.
Examples:
%(pname)s debug.log
Show cumulative report statistics for information in the file 'debug.log',
by default sorted by 'total'.
%(pname)s debug.log --detailed
Show detailed report statistics sorted by 'start' (by default).
%(pname)s debug.log --cumulative --sort=mean --today --verbose
Show cumulative report statistics sorted by mean for entries in the log
which happened today, and do not trim the URL in the resulting report.
%(pname)s debug.log --detailed --start='2001/05/10 06:00:00'
--end='2001/05/11 23:00:00'
Show detailed report statistics for entries in 'debug.log' which
begin after 6am UTC on May 10, 2001 and which end before
11pm UTC on May 11, 2001.
%(pname)s debug.log --top=100 --sort=max
Show cumulative report of the the 'top' 100 methods sorted by maximum
elapsed time."""
%
{
'pname'
:
pname
}
return
details
def
usage
(
basic
=
1
):
usage
=
(
"""
Usage: %s filename [--sort=spec] [--top=n] [--verbose] [--today] [--help]
Usage: %s filename [--cumulative|--detailed]
[--sort=spec]
[--top==n]
[--verbose]
[ --today | [--start=date] [--end=date] ]
[--help]
Provides a profile of the detailed (-M) Zope request log.
"""
%
sys
.
argv
[
0
]
...
...
@@ -308,56 +512,100 @@ Provides a profile of the detailed (-M) Zope request log.
usage
=
usage
+
"""
If the --help argument is given, detailed usage docs are provided."""
return
usage
if
__name__
==
'__main__'
:
if
len
(
sys
.
argv
)
==
1
:
print
usage
()
sys
.
exit
(
0
)
if
sys
.
argv
[
1
]
==
'--help'
:
print
detailedusage
();
sys
.
exit
(
0
)
mode
=
'cumulative'
sortby
=
None
trim
=
0
top
=
1
0
top
=
0
verbose
=
0
sortby
=
'total'
start
=
None
end
=
None
try
:
opts
,
extra
=
getopt
.
getopt
(
sys
.
argv
[
2
:],
''
,
[
'sort='
,
'top='
,
'help'
,
'verbose'
,
'today'
]
sys
.
argv
[
2
:],
''
,
[
'sort='
,
'top='
,
'help'
,
'verbose'
,
'today'
,
'cumulative'
,
'detailed'
,
'start='
,
'end='
]
)
except
:
print
usage
()
sys
.
exit
(
0
)
for
opt
,
val
in
opts
:
if
opt
==
'--sort'
:
sortby
=
val
if
opt
==
'--top'
:
top
=
int
(
val
)
if
opt
==
'--help'
:
print
detailedusage
();
sys
.
exit
(
0
)
if
opt
==
'--verbose'
:
global
verbose
verbose
=
1
if
opt
==
'--today'
:
now
=
time
.
gmtime
(
time
.
time
())
# for testing - now = (2001, 04, 19, 0, 0, 0, 0, 0, -1)
start
=
list
(
now
)
start
[
3
]
=
start
[
4
]
=
start
[
5
]
=
0
start
=
time
.
mktime
(
start
)
end
=
list
(
now
)
end
[
3
]
=
23
;
end
[
4
]
=
59
;
end
[
5
]
=
59
end
=
time
.
mktime
(
end
)
if
sortby
in
[
'url'
,
'hits'
,
'hangs'
,
'max'
,
'min'
,
'median'
,
'mean'
,
'total'
]:
if
sortby
==
'url'
:
# ascending
sortf
=
Sort
(
sortby
,
ascending
=
1
)
for
opt
,
val
in
opts
:
if
opt
==
'--sort'
:
sortby
=
val
if
opt
==
'--top'
:
top
=
int
(
val
)
if
opt
==
'--help'
:
print
detailedusage
();
sys
.
exit
(
0
)
if
opt
==
'--verbose'
:
global
verbose
verbose
=
1
if
opt
==
'--today'
:
now
=
time
.
gmtime
(
time
.
time
())
# for testing - now = (2001, 04, 19, 0, 0, 0, 0, 0, -1)
start
=
list
(
now
)
start
[
3
]
=
start
[
4
]
=
start
[
5
]
=
0
start
=
time
.
mktime
(
start
)
end
=
list
(
now
)
end
[
3
]
=
23
;
end
[
4
]
=
59
;
end
[
5
]
=
59
end
=
time
.
mktime
(
end
)
if
opt
==
'--start'
:
start
=
getdate
(
val
)
if
opt
==
'--end'
:
end
=
getdate
(
val
)
if
opt
==
'--detailed'
:
mode
=
'detailed'
d_sortby
=
sortby
if
opt
==
'--cumulative'
:
mode
=
'cumulative'
validcumsorts
=
[
'url'
,
'hits'
,
'hangs'
,
'max'
,
'min'
,
'median'
,
'mean'
,
'total'
]
validdetsorts
=
[
'start'
,
'win'
,
'wout'
,
'wend'
,
'total'
,
'endstage'
,
'isize'
,
'osize'
,
'httpcode'
,
'active'
,
'url'
]
if
mode
==
'cumulative'
:
if
sortby
is
None
:
sortby
=
'total'
assert
sortby
in
validcumsorts
,
(
sortby
,
mode
,
validcumsorts
)
if
sortby
in
[
'url'
]:
sortf
=
Sort
(
sortby
,
ascending
=
1
)
else
:
sortf
=
Sort
(
sortby
)
elif
mode
==
'detailed'
:
if
sortby
is
None
:
sortby
=
'start'
assert
sortby
in
validdetsorts
,
(
sortby
,
mode
,
validdetsorts
)
if
sortby
in
[
'start'
,
'url'
,
'httpcode'
]:
sortf
=
Sort
(
sortby
,
ascending
=
1
)
elif
sortby
==
'endstage'
:
sortf
=
codesort
else
:
sortf
=
Sort
(
sortby
)
else
:
sortf
=
Sort
(
sortby
)
try
:
analyze
(
open
(
sys
.
argv
[
1
]),
top
,
sortf
,
start
,
end
)
except
:
import
traceback
traceback
.
print_exc
()
print
usage
();
sys
.
exit
(
0
)
else
:
raise
'Invalid mode'
analyze
(
open
(
sys
.
argv
[
1
]),
top
,
sortf
,
start
,
end
,
mode
)
except
AssertionError
,
val
:
a
=
"%s is not a valid %s sort spec, use one of %s"
print
a
%
(
val
[
0
],
val
[
1
],
val
[
2
])
sys
.
exit
(
0
)
except
getopt
.
error
,
val
:
print
val
sys
.
exit
(
0
)
except
ProfileException
,
val
:
print
val
sys
.
exit
(
0
)
except
SystemExit
:
sys
.
exit
(
0
)
except
:
import
traceback
traceback
.
print_exc
()
print
usage
()
sys
.
exit
(
0
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment