Skip to content

Commit 478a9ed

Browse files
pt-mongodb-stalk tool
1 parent 6580ee9 commit 478a9ed

2 files changed

Lines changed: 313 additions & 16 deletions

File tree

bin/pt-mongodb-stalk

Lines changed: 208 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ mongo_currentop_count() {
810810
fi
811811
mongo_eval "
812812
const __pt = db.getSiblingDB('admin');
813-
const __doc = __pt.runCommand({currentOp: 1, active: true, idleConnections: false});
813+
const __doc = __pt.runCommand({currentOp: 1, active: true, idleConnections: false, allUsers: true});
814814
const __parts = '$field'.split('.');
815815
const __re = ${js_regex};
816816
let __count = 0;
@@ -836,6 +836,56 @@ mongo_currentop_count() {
836836
"
837837
}
838838

839+
mongo_repl_lag_seconds() {
840+
mongo_eval "
841+
const __pt = db.getSiblingDB('admin');
842+
let __doc = {};
843+
try {
844+
__doc = __pt.runCommand({replSetGetStatus: 1});
845+
} catch (e) {
846+
print('');
847+
quit(0);
848+
}
849+
if (!__doc || !Array.isArray(__doc.members)) {
850+
print('');
851+
quit(0);
852+
}
853+
854+
let __primary = null;
855+
for (const __member of __doc.members) {
856+
if (__member.stateStr === 'PRIMARY' && __member.optimeDate) {
857+
__primary = __member;
858+
break;
859+
}
860+
}
861+
if (!__primary) {
862+
print(0);
863+
quit(0);
864+
}
865+
866+
const __primaryMs = new Date(__primary.optimeDate).getTime();
867+
let __maxLag = 0;
868+
for (const __member of __doc.members) {
869+
if (__member._id === __primary._id || !__member.optimeDate) {
870+
continue;
871+
}
872+
const __state = __member.stateStr || '';
873+
if (!/^(SECONDARY|STARTUP2|RECOVERING|ROLLBACK)$/.test(__state)) {
874+
continue;
875+
}
876+
const __memberMs = new Date(__member.optimeDate).getTime();
877+
if (isNaN(__memberMs)) {
878+
continue;
879+
}
880+
const __lag = Math.max(0, Math.floor((__primaryMs - __memberMs) / 1000));
881+
if (__lag > __maxLag) {
882+
__maxLag = __lag;
883+
}
884+
}
885+
print(__maxLag);
886+
"
887+
}
888+
839889
_js_quote() {
840890
printf '%s' "$1" | perl -0pe 's/\\/\\\\/g; s/'"'"'/\\'"'"'/g; $_="'"'"'$_'"'"'"'
841891
}
@@ -996,7 +1046,7 @@ collect_mongodb_data_one() {
9961046
collect_mongodb_data_loop() {
9971047
local d="$1"
9981048
(mongo_admin_json "db.runCommand({serverStatus: 1})" > "$(sample_file "$d" "serverStatus" "json")") &
999-
(mongo_admin_json "db.runCommand({currentOp: 1, active: true, idleConnections: false})" > "$(sample_file "$d" "currentOp" "json")") &
1049+
(mongo_admin_json "db.runCommand({currentOp: 1, active: true, idleConnections: false, allUsers: true})" > "$(sample_file "$d" "currentOp" "json")") &
10001050
}
10011051

10021052
collect_mongodb_data_two() {
@@ -1091,10 +1141,28 @@ set_trg_func() {
10911141
fi
10921142

10931143
func=$(echo "$func" | tr '[:upper:]' '[:lower:]')
1094-
if [ "$func" = "status" ] || [ "$func" = "currentop" ]; then
1095-
TRIGGER_FUNCTION="trg_$func"
1096-
return 0
1097-
fi
1144+
case "$func" in
1145+
status|currentop|cpu|memory|writewait|repllag)
1146+
TRIGGER_FUNCTION="trg_$func"
1147+
return 0
1148+
;;
1149+
mem)
1150+
TRIGGER_FUNCTION="trg_memory"
1151+
return 0
1152+
;;
1153+
processcpu|process-cpu|proc_cpu|proc-cpu)
1154+
TRIGGER_FUNCTION="trg_process_cpu"
1155+
return 0
1156+
;;
1157+
processmemory|process-memory|proc_memory|proc-memory)
1158+
TRIGGER_FUNCTION="trg_process_memory"
1159+
return 0
1160+
;;
1161+
replicationlag|replciationlag|waitforreplicationlag|waitforreplciationlag)
1162+
TRIGGER_FUNCTION="trg_repllag"
1163+
return 0
1164+
;;
1165+
esac
10981166

10991167
return 1
11001168
}
@@ -1109,6 +1177,92 @@ trg_currentop() {
11091177
mongo_currentop_count "$var"
11101178
}
11111179

1180+
trg_cpu() {
1181+
local cpu user nice system idle iowait irq softirq steal guest guest_nice
1182+
local idle_all non_idle total total_delta idle_delta value
1183+
local cpu_state last_total last_idle
1184+
1185+
read -r cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat || return 1
1186+
iowait=${iowait:-0}
1187+
irq=${irq:-0}
1188+
softirq=${softirq:-0}
1189+
steal=${steal:-0}
1190+
idle_all=$((idle + iowait))
1191+
non_idle=$((user + nice + system + irq + softirq + steal))
1192+
total=$((idle_all + non_idle))
1193+
cpu_state="$PT_TMPDIR/cpu-trigger-state"
1194+
1195+
if [ ! -f "$cpu_state" ]; then
1196+
echo "$total $idle_all" > "$cpu_state"
1197+
echo 0
1198+
return 0
1199+
fi
1200+
1201+
read -r last_total last_idle < "$cpu_state" || {
1202+
echo "$total $idle_all" > "$cpu_state"
1203+
echo 0
1204+
return 0
1205+
}
1206+
total_delta=$((total - last_total))
1207+
idle_delta=$((idle_all - last_idle))
1208+
echo "$total $idle_all" > "$cpu_state"
1209+
1210+
if [ "$total_delta" -le 0 ]; then
1211+
echo 0
1212+
return 0
1213+
fi
1214+
1215+
value=$(awk -v total="$total_delta" -v idle="$idle_delta" 'BEGIN { printf "%.2f\n", ((total - idle) / total) * 100 }')
1216+
echo "$value"
1217+
}
1218+
1219+
trg_memory() {
1220+
awk '
1221+
/^MemTotal:/ { total = $2 }
1222+
/^MemAvailable:/ { available = $2 }
1223+
/^MemFree:/ { free = $2 }
1224+
/^Buffers:/ { buffers = $2 }
1225+
/^Cached:/ { cached = $2 }
1226+
END {
1227+
if (available == "" && free >= 0) {
1228+
available = free + buffers + cached
1229+
}
1230+
if (total > 0 && available >= 0) {
1231+
printf "%.2f\n", ((total - available) / total) * 100
1232+
}
1233+
}
1234+
' /proc/meminfo
1235+
}
1236+
1237+
trg_process_cpu() {
1238+
local pid value
1239+
pid=$(get_mongo_pid)
1240+
[ -n "$pid" ] || return 1
1241+
value=$(ps -p "$pid" -o %cpu= 2>/dev/null | awk '{gsub(/,/, "."); printf "%.2f\n", $1 + 0; exit}')
1242+
[ -n "$value" ] && echo "$value"
1243+
}
1244+
1245+
trg_process_memory() {
1246+
local pid value
1247+
pid=$(get_mongo_pid)
1248+
[ -n "$pid" ] || return 1
1249+
value=$(ps -p "$pid" -o %mem= 2>/dev/null | awk '{gsub(/,/, "."); printf "%.2f\n", $1 + 0; exit}')
1250+
[ -n "$value" ] && echo "$value"
1251+
}
1252+
1253+
trg_writewait() {
1254+
local value
1255+
value=$(mongo_status_value "globalLock.currentQueue.writers")
1256+
if [ -z "$value" ]; then
1257+
value=0
1258+
fi
1259+
echo "$value"
1260+
}
1261+
1262+
trg_repllag() {
1263+
mongo_repl_lag_seconds
1264+
}
1265+
11121266
oktorun() {
11131267
if [ "$OKTORUN" -eq 0 ]; then
11141268
[ -z "$EXIT_REASON" ] && EXIT_REASON="OKTORUN is false"
@@ -1372,8 +1526,8 @@ model as C<pt-stalk>, but uses MongoDB administration commands instead of
13721526
MySQL commands.
13731527
13741528
The default trigger watches C<serverStatus.connections.current>. You can also
1375-
watch C<currentOp> and count active operations whose field matches a regular
1376-
expression.
1529+
watch C<currentOp>, host CPU usage, host memory usage, queued writers, and
1530+
replica set replication lag.
13771531
13781532
=head1 OPTIONS
13791533
@@ -1435,7 +1589,8 @@ Do not collect if the disk has less than this percent free space.
14351589
14361590
type: string; default: status
14371591
1438-
Trigger source. Valid built-in values are C<status> and C<currentop>.
1592+
Trigger source. Valid built-in values are C<status>, C<currentop>, C<cpu>,
1593+
C<memory>, C<writewait>, and C<repllag>.
14391594
14401595
With C<status>, L<"--variable"> is a dot-separated path inside
14411596
C<serverStatus>. Example:
@@ -1446,7 +1601,25 @@ With C<currentop>, L<"--variable"> is a dot-separated field path inside each
14461601
C<currentOp.inprog> document and L<"--match"> is a regex. The trigger value is
14471602
the number of matching operations. Example:
14481603
1449-
--function currentop --variable ns --match '^app\.orders$' --threshold 10
1604+
--function currentop --variable command.aggregate --match '^orders$' --threshold 10
1605+
1606+
With C<cpu>, the trigger value is host CPU busy percentage from C</proc/stat>.
1607+
With C<memory>, the trigger value is host memory used percentage from
1608+
C</proc/meminfo>. C<mem> is accepted as an alias for C<memory>. Example:
1609+
1610+
--function cpu --threshold 85
1611+
--function memory --threshold 90
1612+
1613+
With C<writewait>, the trigger value is
1614+
C<serverStatus.globalLock.currentQueue.writers>. Example:
1615+
1616+
--function writewait --threshold 5
1617+
1618+
With C<repllag>, the trigger value is the maximum replica set member lag behind
1619+
the primary, in seconds, from C<replSetGetStatus>. C<replicationlag> and
1620+
C<waitForReplicationLag> are accepted as aliases. Example:
1621+
1622+
--function repllag --threshold 30
14501623
14511624
You can also specify a file that defines C<trg_plugin>.
14521625
@@ -1554,7 +1727,7 @@ collect immediately.
15541727
15551728
=item --threshold
15561729
1557-
type: int; default: 100
1730+
type: float; default: 100
15581731
15591732
Collection is triggered when L<"--variable"> is greater than this value.
15601733
@@ -1592,7 +1765,8 @@ User for login.
15921765
15931766
type: string; default: connections.current
15941767
1595-
Variable to watch inside C<serverStatus> or C<currentOp>.
1768+
Variable to watch inside C<serverStatus> or C<currentOp>. This option is ignored
1769+
by C<cpu>, C<memory>, C<writewait>, and C<repllag>.
15961770
15971771
=item --verbose
15981772
@@ -1641,7 +1815,28 @@ Run in stalking mode using currentOp matches instead of a serverStatus metric:
16411815
16421816
pt-mongodb-stalk \
16431817
--host localhost --port 30001 --user admin --password admin --authenticationDatabase admin \
1644-
--function currentop --variable ns --match '^app\.orders$' --threshold 10 --cycles 2 --interval 1 --iterations 1 \
1818+
--function currentop --variable command.aggregate --match '^orders$' --threshold 10 --cycles 2 --interval 1 --iterations 1 \
1819+
--dest /tmp/pt-mongodb-stalk
1820+
1821+
Run in stalking mode when host CPU is above 85 percent:
1822+
1823+
pt-mongodb-stalk \
1824+
--host localhost --port 30001 --user admin --password admin --authenticationDatabase admin \
1825+
--function cpu --threshold 85 --cycles 3 --interval 1 --iterations 1 \
1826+
--dest /tmp/pt-mongodb-stalk
1827+
1828+
Run in stalking mode when host memory is above 90 percent:
1829+
1830+
pt-mongodb-stalk \
1831+
--host localhost --port 30001 --user admin --password admin --authenticationDatabase admin \
1832+
--function memory --threshold 90 --cycles 3 --interval 1 --iterations 1 \
1833+
--dest /tmp/pt-mongodb-stalk
1834+
1835+
Run in stalking mode when replica set lag is above 30 seconds:
1836+
1837+
pt-mongodb-stalk \
1838+
--host localhost --port 30001 --user admin --password admin --authenticationDatabase admin \
1839+
--function repllag --threshold 30 --cycles 2 --interval 1 --iterations 1 \
16451840
--dest /tmp/pt-mongodb-stalk
16461841
16471842
=head1 COPYRIGHT, LICENSE, AND WARRANTY

0 commit comments

Comments
 (0)