ad_monitor_topWhat it does:
ad_monitor_top parses the output from "top" and stores the results in a table. This is useful to later create reports of load averages and memory usage in a time-sensitive way. Required Parameters in the monitoring section: * TopLocation: Full path to execute top Optional Parameters: * LoadAverageAlertThreshold: Minimum load average before emailing persons to notify that the machine is overloadedDefined in: /web/philip/tcl/ad-monitoring-defs.tcl
Source code:
# list indicating the order in which top outputs data
set proc_var_list [list pid username threads priority nice proc_size resident_memory state cpu_total_time cpu_pct command]
# location of the desired top function
set top_location [ad_parameter TopLocation monitoring]
# make sure we have a path to top and that the file exists
if { [empty_string_p $top_location] } {
ns_log Error "ad_monitor_top: cannot find top; TopLocation parameter in monitoring
is not defined"
return
} elseif { ![file exists $top_location] } {
ns_log Error "ad_monitor_top: Specified location for top ($top_location) does not exist"
return
}
# set top_output [exec $top_location]
if [catch { set top_output [exec $top_location] } errmsg] {
# couldn't exec top at TopLocation
if { ![file exists $top_location] } {
ad_return_error "top not found" "
The top procedure could not be found at $top_location:
<blockquote><pre> $errmsg </pre></blockquote>"
return
}
ad_return_error "insufficient top permissions" "
The top procedure at $top_location cannot be run:
<blockquote><pre> $errmsg </pre></blockquote>"
return
}
# else top execution went ok
set top_list [split $top_output "\n"]
## Run through the output of top, grab header lines and leave the rest.
# number of header lines grabbed
set ctr 0
# greet the database
set db [ns_db gethandle]
# id for this iteration of top-parsing
set top_id [database_to_tcl_string $db "select ad_monitoring_top_top_id.nextval from dual"]
# have we reached the list of process info yet?
set procflag 0
foreach line $top_list {
if { $procflag > 0 } {
#compress multiple spaces
regsub -all {[ ]+} [string trim $line] " " line
set proc_list [split $line]
#skip blank lines
if { [llength $proc_list] < 2 } { continue }
if { [llength $proc_list] < 11 } {
ns_log Notice "skipping top process line:
element list shorter than variable list."
continue }
#set proc-related vars
set pid [lindex $proc_list 0]
set username [lindex $proc_list 1]
set threads [lindex $proc_list 2]
set priority [lindex $proc_list 3]
set nice [lindex $proc_list 4]
set proc_size [lindex $proc_list 5]
set resident_memory [lindex $proc_list 6]
set state [lindex $proc_list 7]
set cpu_total_time [lindex $proc_list 8]
set cpu_pct [lindex $proc_list 9]
set command [lindex $proc_list 10]
ns_db dml $db "insert into ad_monitoring_top_proc
(proc_id, top_id, pid, command, username,
threads, priority, nice, proc_size,
resident_memory, state, cpu_total_time, cpu_pct)
values
(ad_monitoring_top_proc_proc_id.nextval, $top_id, $pid, '$command',
'$username', $threads, $priority, $nice, '$proc_size',
'$resident_memory', '$state', '$cpu_total_time', '$cpu_pct')"
continue
} elseif { [regexp -nocase {(.*PID.USERNAME.*)} $line match top_header] } {
## this is the start of proc info lines
incr procflag
continue
} elseif { [regexp -nocase {load av[a-z]*: (.*)} $line match load] } {
## this is the load header
incr ctr
# remove commas, multiple spaces
regsub -all {,} [string trim $load] "" load
regsub -all {[ ]+} $load " " load
set load_list [split $load " "]
# We keep all three load avgs, ignore the time at the end of the line
set load_1 [lindex load_list 0]
set load_5 [lindex load_list 1]
set load_15 [lindex load_list 2]
# send out any high-load alerts
if { $load_5 > [ad_parameter LoadAverageAlertThreshold monitoring 2.0] } {
wd_email_notify_list "High Load Average on [ad_url]" "The load average over the last 5 minutes for [ad_url] was $load_5"
}
} elseif { [regexp -nocase {mem[a-z]*: (.*)} $line match memory] } {
## this is the memory header
incr ctr
foreach mem [split $memory ","] {
regexp {^ *([^ ]*) (.*)} $mem match amount type
set amount [string trim [string toupper $amount]]
# convert all mem values to Kilobytes
regsub {K$} $amount "" amount
regsub {M$} $amount "000" amount
set type [string trim [string tolower $type]]
switch $type {
"real" { set memory_real $amount }
"free" { set memory_free $amount }
"swap free" { set memory_swap_free $amount }
"swap in use" { set memory_swap_in_use $amount }
}
}
}
if {$ctr == 2 } {
## we have all the header information we currently store.
## we should also store the rest of top's output...
## some of it can be gotten from the zoom package.
ns_db dml $db "insert into ad_monitoring_top
(top_id, timestamp, timehour, load_avg_1, load_avg_5, load_avg_15,
memory_real, memory_free, memory_swap_in_use, memory_swap_free)
values
($top_id, sysdate, to_char(sysdate, 'HH24'), $load_1, $load_5, $load_15,
$memory_real, $memory_free, $memory_swap_in_use, $memory_swap_free)"
incr ctr
}
# end of the foreach loop
}
if { $ctr < 2 } {
# didn't even get load and memory lines from top
ns_log Error "ad_monitor_top: Cannot parse output from top"
return
}