Skip to content

Commit f53805c

Browse files
authored
Update mysqlmonitor.sh
1 parent b968be0 commit f53805c

File tree

1 file changed

+62
-95
lines changed

1 file changed

+62
-95
lines changed

mysqlmonitor.sh

Lines changed: 62 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,17 @@ if ! output=$(get_mysql_status 2>&1); then
6969
fi
7070
fi
7171

72-
# Handle CTRL+C and restore cursor on exit
73-
trap "echo -e '\nExiting MySQL Monitor. Goodbye!'; printf '\033[?25h'; exit" SIGINT
72+
tput smcup 2>/dev/null || true
73+
74+
# Handle CTRL+C and other term signals to restore screen and cursor before exit.
75+
cleanup() {
76+
printf '\033[?25h' # Show the cursor
77+
tput rmcup 2>/dev/null || true
78+
echo -e "\nExiting MySQL Monitor. Goodbye!"
79+
exit
80+
}
81+
82+
trap cleanup SIGINT SIGTERM
7483

7584
# Hide the cursor to reduce flicker
7685
printf '\033[?25l'
@@ -79,35 +88,28 @@ printf '\033[?25l'
7988
printf "\033[H\033[J"
8089

8190
while true; do
82-
# ====== Added Code Start: Check Terminal Size ======
83-
# Retrieve current terminal size
84-
read rows cols <<< $(stty size)
85-
86-
# Check if terminal size is below minimum requirements
91+
92+
# Read current terminal size
93+
read rows cols <<< "$(stty size)"
94+
95+
# If terminal size is below minimum, show a warning in the center
8796
if [[ $rows -lt $MIN_ROWS || $cols -lt $MIN_COLS ]]; then
88-
# Clear the screen
8997
printf "\033[H\033[J"
90-
91-
# Define warning message
92-
WARNING_MSG="❗ Terminal size too small. Please resize the window to at least ${MIN_COLS} columns and ${MIN_ROWS} rows. ❗"
93-
94-
# Calculate the position to center the message
98+
WARNING_MSG="❗ Terminal size too small. Resize to at least ${MIN_COLS}x${MIN_ROWS}. ❗"
9599
msg_length=${#WARNING_MSG}
96100
msg_row=$((rows / 2))
97101
msg_col=$(((cols - msg_length) / 2))
98-
99-
# Ensure message does not go negative
100-
if [[ $msg_col -lt 0 ]]; then
101-
msg_col=0
102+
(( msg_col < 0 )) && msg_col=0
103+
104+
# Move cursor to the calculated position and print warning in bold red
105+
printf "\033[${msg_row};${msg_col}H\033[1;31m%s\033[0m\n" "$WARNING_MSG"
106+
107+
read -t 2 -n 1 -r key
108+
if [[ $key == "q" || $key == "Q" ]]; then
109+
cleanup
102110
fi
103-
104-
# Move cursor to the calculated position and print the message
105-
printf "\033[${msg_row};${msg_col}H\033[1;31m%s\033[0m\n" "$WARNING_MSG" # Bold red text
106-
107-
# Skip the rest of the loop iteration
108111
continue
109112
fi
110-
# ====== Added Code End: Check Terminal Size ======
111113

112114
# Initialize an empty variable to hold all output
113115
output=""
@@ -117,7 +119,6 @@ while true; do
117119

118120
# Capture MySQL status and append to output
119121
mysql_data=$(get_mysql_status | awk '
120-
# Converts seconds to a human-readable "x d y h z m" etc.
121122
function prettyTime(sec) {
122123
years = int(sec / 31536000); sec %= 31536000
123124
months = int(sec / 2592000); sec %= 2592000
@@ -139,19 +140,18 @@ while true; do
139140
# Converts large numbers into user-friendly formats (K, M, B, T)
140141
function formatNumber(num) {
141142
if (num >= 1e12) {
142-
return sprintf("%.2fT", num / 1e12) # Trillions
143+
return sprintf("%.2fT", num / 1e12)
143144
} else if (num >= 1e9) {
144-
return sprintf("%.2fB", num / 1e9) # Billions
145+
return sprintf("%.2fB", num / 1e9)
145146
} else if (num >= 1e6) {
146-
return sprintf("%.2fM", num / 1e6) # Millions
147+
return sprintf("%.2fM", num / 1e6)
147148
} else if (num >= 1e3) {
148-
return sprintf("%.2fK", num / 1e3) # Thousands
149+
return sprintf("%.2fK", num / 1e3)
149150
} else {
150-
return num # Small numbers stay as is
151+
return num
151152
}
152153
}
153154
154-
# Convert values in MB to either XX MB or XX GB.
155155
function shortSizeMB(mb) {
156156
if (mb >= 1024) {
157157
gb = mb / 1024
@@ -162,7 +162,6 @@ while true; do
162162
}
163163
164164
BEGIN {
165-
# Short descriptions for variables
166165
desc["Aborted_clients"] = "Failed client connections."
167166
desc["Aborted_connects"] = "Failed MySQL server connections."
168167
desc["Connections"] = "Total connection attempts."
@@ -203,18 +202,12 @@ while true; do
203202
desc["Threads_running"] = "Threads currently running queries."
204203
desc["Uptime"] = ""
205204
206-
# Additional Metrics descriptions
207-
# Moved "Queries per Second"
208-
# desc["Queries per Second"] = "Should match traffic/app changes."
209205
desc["InnoDB Buffer Pool Free"] = "Zero/low? = innodb_buffer_pool_size."
210206
desc["InnoDB Buffer Pool Hit Ratio"] = "High QPS? Aim for high hit ratio."
211207
desc["Thread Cache Hit Ratio"] = "Faster connection handling. > 90%."
212208
desc["Table Cache Hit Ratio"] = "Faster table access speeds. > 90%."
213209
desc["Temp tables created on disk"] = "Keep this low! Disk I/O is slow."
214210
215-
# Define additional metrics labels
216-
# Removed "Queries per Second" from additional_labels
217-
# additional_labels[1] = "Queries per Second"
218211
additional_labels[1] = "InnoDB Buffer Pool Free"
219212
additional_labels[2] = "InnoDB Buffer Pool Hit Ratio"
220213
additional_labels[3] = "Thread Cache Hit Ratio"
@@ -229,149 +222,132 @@ while true; do
229222
}
230223
231224
END {
232-
# Build a list of keys
233225
count = 0
234226
for (v in data) {
235227
count++
236228
keys[count] = v
237229
}
238-
asort(keys) # Sort the array of keys
230+
asort(keys)
239231
240-
# Prepare the values
241-
# InnoDB Buffer Pool
242232
ibp_size_mb = ""
243233
if ("Innodb_buffer_pool_size" in data) {
244234
ibp_size_mb = data["Innodb_buffer_pool_size"] / (1024 * 1024)
245235
}
246-
# Estimate free pages in MB
236+
247237
ibp_free_mb = ""
248238
if ("Innodb_buffer_pool_pages_free" in data) {
249239
ibp_free_mb = data["Innodb_buffer_pool_pages_free"] * 16 / 1024
250240
}
251241
252-
# Queries per second (QPS)
253242
qps = ""
254243
if (("Questions" in data) && ("Uptime" in data) && (data["Uptime"] > 0)) {
255244
qps = data["Questions"] / data["Uptime"]
256245
}
257246
258-
# Temp table disk ratio
259247
tmp_disk_ratio = ""
260248
if (("Created_tmp_disk_tables" in data) && ("Created_tmp_tables" in data) && (data["Created_tmp_tables"] > 0)) {
261249
tmp_disk_ratio = 100 * data["Created_tmp_disk_tables"] / data["Created_tmp_tables"]
262250
}
263251
264-
# Thread Cache Hit Ratio
265252
thread_cache_ratio = ""
266253
if (("Threads_created" in data) && ("Connections" in data) && (data["Connections"] > 0)) {
267254
thread_cache_ratio = 100 * (1 - (data["Threads_created"] / data["Connections"]))
268255
}
269256
270-
# Correct Table Cache Hit Ratio Calculation
271257
table_cache_ratio = ""
272-
if (("Table_open_cache_hits" in data) && ("Table_open_cache_misses" in data) && (data["Table_open_cache_hits"] + data["Table_open_cache_misses"] > 0)) {
258+
if (("Table_open_cache_hits" in data) && ("Table_open_cache_misses" in data) &&
259+
(data["Table_open_cache_hits"] + data["Table_open_cache_misses"] > 0)) {
273260
table_cache_ratio = 100 * (data["Table_open_cache_hits"] / (data["Table_open_cache_hits"] + data["Table_open_cache_misses"]))
274261
}
275262
276-
# InnoDB Buffer Pool Hit Ratio, clamped to 0% if negative
277263
ibp_efficiency = ""
278-
if (("Innodb_buffer_pool_read_requests" in data) && ("Innodb_buffer_pool_reads" in data) && (data["Innodb_buffer_pool_read_requests"] > 0)) {
264+
if (("Innodb_buffer_pool_read_requests" in data) && ("Innodb_buffer_pool_reads" in data) &&
265+
(data["Innodb_buffer_pool_read_requests"] > 0)) {
279266
temp_ratio = 100 * (1 - (data["Innodb_buffer_pool_reads"] / data["Innodb_buffer_pool_read_requests"]))
280267
if (temp_ratio < 0) {
281268
temp_ratio = 0
282269
}
283270
ibp_efficiency = temp_ratio
284271
}
285272
286-
# Calculate column widths dynamically based on content
287273
col1_width = 0
288274
col2_width = 0
289275
col3_width = 0
290276
291277
for (v in data) {
292-
if (length(v) > col1_width) col1_width = length(v) # Longest Metric (varName)
293-
if (length(data[v]) > col2_width) col2_width = length(data[v]) # Longest Value (val)
294-
if (length(desc[v]) > col3_width) col3_width = length(desc[v]) # Longest Description (explanation)
278+
if (length(v) > col1_width) col1_width = length(v)
279+
if (length(data[v]) > col2_width) col2_width = length(data[v])
280+
if (length(desc[v]) > col3_width) col3_width = length(desc[v])
295281
}
296282
297-
# Include additional metrics labels in column width calculation
298283
for (i in additional_labels) {
299284
label_length = length(additional_labels[i])
300285
if (label_length > col1_width) {
301286
col1_width = label_length
302287
}
303288
}
304289
305-
# Ensure minimum widths for readability
306290
col1_width = (col1_width > 15 ? col1_width : 15)
307291
col2_width = (col2_width > 10 ? col2_width : 10)
308292
col3_width = (col3_width > 25 ? col3_width : 25)
309293
310-
# Initialize output within AWK
311294
output = ""
312295
313-
# Print the data with adjusted widths
314296
for (i=1; i<=count; i++) {
315297
varName = keys[i]
316298
explanation = (varName in desc) ? desc[varName] : "No description available"
317299
318300
if (varName == "Uptime") {
319-
val = prettyTime(data[varName]) # Format Uptime
320-
# Append the note "(Wait 24h for accuracy)" to the varName
301+
val = prettyTime(data[varName])
321302
output = output sprintf("%-" col1_width "s | %s %s\n", varName " (Wait 24h for accuracy)", val, explanation)
322-
# Skip further processing for Uptime
323303
continue
324304
}
325305
326306
val = formatNumber(data[varName])
327307
328-
# New: Append QPS to "Questions"
329308
if (varName == "Questions" && qps != "") {
330309
qps_formatted = sprintf("(%.2f QPS)", qps)
331310
varName = varName " " qps_formatted
332311
}
333312
334-
# Highlight specific values if needed
335313
if (varName == "Innodb_buffer_pool_pages_free" && data[varName] == 0) {
336-
output = output sprintf("\033[0;31m%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\033[0m\n", varName, val, explanation)
314+
output = output sprintf("\033[0;31m%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\033[0m\n",
315+
varName, val, explanation)
337316
} else {
338-
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", varName, val, explanation)
317+
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n",
318+
varName, val, explanation)
339319
}
340320
}
341321
342-
# Additional Metrics section
343322
output = output sprintf("------------------------------- MySQL Health Metrics --------------------------------\n")
344323
345-
# Moved Queries per Second
346-
# Removed the following block to eliminate the separate "Queries per Second" line
347-
# if (qps != "") {
348-
# output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", \
349-
# "Queries per Second", sprintf("%.2f QPS", qps), desc["Queries per Second"])
350-
# }
351-
352324
if (ibp_free_mb != "") {
353-
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", \
354-
"InnoDB Buffer Pool Free", shortSizeMB(ibp_free_mb), desc["InnoDB Buffer Pool Free"])
325+
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n",
326+
"InnoDB Buffer Pool Free", shortSizeMB(ibp_free_mb), desc["InnoDB Buffer Pool Free"])
355327
}
356328
357329
if (ibp_efficiency != "") {
358-
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", \
359-
"InnoDB Buffer Pool Hit Ratio", sprintf("%.1f%%", ibp_efficiency), desc["InnoDB Buffer Pool Hit Ratio"])
330+
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n",
331+
"InnoDB Buffer Pool Hit Ratio", sprintf("%.1f%%", ibp_efficiency),
332+
desc["InnoDB Buffer Pool Hit Ratio"])
360333
}
361334
362335
if (thread_cache_ratio != "") {
363-
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", \
364-
"Thread Cache Hit Ratio", sprintf("%.1f%%", thread_cache_ratio), desc["Thread Cache Hit Ratio"])
336+
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n",
337+
"Thread Cache Hit Ratio", sprintf("%.1f%%", thread_cache_ratio),
338+
desc["Thread Cache Hit Ratio"])
365339
}
366340
367341
if (table_cache_ratio != "") {
368-
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", \
369-
"Table Cache Hit Ratio", sprintf("%.1f%%", table_cache_ratio), desc["Table Cache Hit Ratio"])
342+
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n",
343+
"Table Cache Hit Ratio", sprintf("%.1f%%", table_cache_ratio),
344+
desc["Table Cache Hit Ratio"])
370345
}
371346
372347
if (tmp_disk_ratio != "") {
373-
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n", \
374-
"Temp tables created on disk", sprintf("%.1f%%", tmp_disk_ratio), desc["Temp tables created on disk"])
348+
output = output sprintf("%-" col1_width "s | %-" col2_width "s | %-" col3_width "s\n",
349+
"Temp tables created on disk", sprintf("%.1f%%", tmp_disk_ratio),
350+
desc["Temp tables created on disk"])
375351
}
376352
377353
print output
@@ -390,39 +366,30 @@ while true; do
390366
mem_free_bytes=${mem_array[2]}
391367
mem_avail_bytes=${mem_array[3]}
392368

393-
# Convert bytes to gigabytes with two decimal places
394369
mem_total_gb=$(awk "BEGIN {printf \"%.2f\", $mem_total_bytes / 1024 / 1024 / 1024}")
395370
mem_used_gb=$(awk "BEGIN {printf \"%.2f\", $mem_used_bytes / 1024 / 1024 / 1024}")
396371
mem_free_gb=$(awk "BEGIN {printf \"%.2f\", $mem_free_bytes / 1024 / 1024 / 1024}")
397372
mem_avail_gb=$(awk "BEGIN {printf \"%.2f\", $mem_avail_bytes / 1024 / 1024 / 1024}")
398373

399-
# Calculate available memory percentage with floating-point precision
400374
avail_mem_percentage=$(awk "BEGIN {printf \"%.2f\", 100 * $mem_avail_bytes / $mem_total_bytes}")
401-
402-
# Determine if available memory is below 10%
403375
is_low_mem=$(awk "BEGIN {print ($avail_mem_percentage < 10)}")
404376

405377
if (( is_low_mem )); then
406378
mem_info="Total: ${mem_total_gb} GB, Used: ${mem_used_gb} GB, Free: ${mem_free_gb} GB, Available: ${mem_avail_gb} GB \033[0;31m(Warning!: ${avail_mem_percentage}%%)\033[0m"
407379
else
408380
mem_info="Total: ${mem_total_gb} GB, Used: ${mem_used_gb} GB, Free: ${mem_free_gb} GB, Available: ${mem_avail_gb} GB"
409381
fi
410-
# Append mem_info with an empty line before it
411-
output+=$'\n'"${mem_info}"$'\n'
412382

413-
# Add title followed by a newline
383+
output+=$'\n'"${mem_info}"$'\n'
414384
output+="${TITLE}"$'\n'
415385

416386
# Move cursor to top-left and print all output at once
387+
printf "\033[H\033[J" # Clear screen each time to avoid partial lines.
417388
printf "\033[H%s" "$output"
418389

419-
# Read user input with timeout
390+
# Wait for user input with timeout
420391
read -t "$INTERVAL" -n 1 -r key
421392
if [[ $key == "q" || $key == "Q" ]]; then
422-
echo -e "\nQuitting MySQL Monitor. Goodbye!"
423-
break
393+
cleanup
424394
fi
425395
done
426-
427-
# Restore the cursor before exiting (in case loop is exited without SIGINT)
428-
printf '\033[?25h'

0 commit comments

Comments
 (0)