GeekTool, Perl, and ANSI color codes
GeekTool’s “shell” Geeklet is a great way of displaying the results of command-line scripts on your desktop. I currently have the following shell Geeklets on my computer for monitoring my sites:
- /usr/bin/curl http://www.example.com/server-status?auto
- /usr/bin/ssh monitor@web /usr/bin/uptime
- /usr/bin/ssh monitor@web "/bin/ps -axe | /usr/bin/grep httpd | /usr/bin/wc -l | /usr/bin/sed -E 's/ +//;'"
- /usr/bin/ssh monitor@web "/usr/bin/tail -40 /var/log/apache2/error_log"
- /usr/bin/ssh monitor@web bin/freemem
- /usr/bin/ssh monitor@web bin/hightimes
The first one is just grabbing the text version of Apache’s server status page. The second one displays the uptime and current load. The third one counts up the number of httpd processes currently running. And the fourth one displays the last 40 lines of Apache’s error log.
The final two are a little more complex: freemem and hightimes are Perl scripts I’ve written to display color-coded warnings. It’s easy to add ANSI escape codes using Perl. The escape character is ‘\e’. Follow it by an open bracket, the code, and the letter m1. Look for the codes on Wikipedia’s ANSI escape code.
[toggle code]
- #!/usr/bin/perl
- $critical="\e[31m"; #red
- $warning="\e[35m"; #magenta
- $notice="\e[33m"; #yellow
- $clear="\e[0m";
- @processes = `/bin/ps -u _www -o time,pid | /usr/bin/sort -nr`;
-
for $process (@processes) {
- chomp $process;
-
if ($process =~ m/^ +([0-9:.]+) +([0-9]+)/) {
- ($time, $processId) = ($1, $2);
-
if ($time =~ m/([0-9]+):([0-9]+)\.([0-9]+)/) {
- ($hours, $minutes, $minuteFraction) = ($1, $2, $3);
-
if ($hours) {
- print "$critical$process$clear\n";
-
} elsif ($minutes > 10) {
- print "$warning$process$clear\n";
-
} elsif ($minutes > 5) {
- print "$notice$process$clear\n";
-
} else {
- #at the end of cputime-intensive processes
- exit;
- }
-
} else {
- print "${critical}UNKNOWN TIME FORMAT: $time$clear\n";
- }
- }
- }
This runs the ‘ps’ command, getting only processes owned by _www, and displaying only the time and pid columns. The results of ps get piped through sort so that the most time-consuming processes are at the top.
Processes owned by _www that take up a lot of cpu time are displayed in red; those that might be about to take up a lot of cpu time are displayed magenta; and those that are probably just dipping over the line temporarily are displayed in yellow. Otherwise, it doesn’t display at all.
[toggle code]
- #!/usr/bin/perl
- $okay="\e[32m"; #green
- $critical="\e[31m"; #red
- $problem="\e[33m"; #yellow
- $clear="\e[0m";
- $usage = `/usr/bin/vm_stat`;
- $warning = $critical;
-
if ($usage =~ m/page size of ([0-9]+) bytes/) {
- $pageSize = $1;
-
if ($usage =~ m/Pages free: *([0-9]+)/) {
- $free = $1;
- $free = int($free*$pageSize/(1024*1024));
-
if ($free > 8000) {
- $warning = $okay;
-
} elsif ($free > 6000) {
- $warning = $problem;
- }
- $message = "$free megabytes free";
-
} else {
- $message = "Unable to find free pages";
- }
-
} else {
- $message = "Unable to find page size";
- }
- print $warning, $message, $clear, "\n";
-
if ($warning eq $critical) {
- exit(1);
- }
This parses the output of vm_stat to get the current free memory. It also will adjust the green response dot you see in some of the screenshot’s geeklets. The green dot normally means only that the script did okay. For direct commands, you can’t make it be anything else. For your own scripts, however, if you want to change the color of that button you can exit with an error. In Perl, this is as simple as “exit(1)”.
That’s why the free memory script checks to see if the warning is critical before exiting. If the free memory is low enough to justify a critical color code, the script exits with an error code. GeekTool responds to this by turning the normally green dot red.
The hightimes script doesn’t bother with an exit code because it doesn’t display anything at all if there’s nothing out of the ordinary.
Obviously, this isn’t a replacement for a good system monitoring tool like Zenoss2. But for keeping an eye on something command-line oriented through both good and bad, GeekTool is a great little tool.
- February 10, 2011: Using Term::ANSIColor with GeekTool
-
I was looking for something else this morning and ran across Term::ANSIColor. Instead of having to look up the color codes in a table and output them exactly right, Term::ANSIColor makes manipulating ANSI codes much easier—and thus less likely to error.
There may be some cases where I don’t want to introduce any dependencies or overhead, but for the most part, Term::ANSIColor should be a much better choice.
In each of the two scripts, it’s just a matter of replacing the variables. Instead of:
- $critical="\e[31m"; #red
- $warning="\e[35m"; #magenta
- $notice="\e[33m"; #yellow
- $clear="\e[0m";
Import Term::ANSIColor:
- use Term::ANSIColor;
- $critical = color 'red on_black';
- $warning = color 'magenta on_black';
- $notice = color 'yellow on_black';
- $clear = color 'reset';
Everything else remains the same.
And for the vm_stat script:
- use Term::ANSIColor;
- $okay = color 'green';
- $critical = color 'red';
- $problem = color 'yellow';
- $clear = color 'reset';
One odd issue I ran into is that GeekTool appears to need the ‘reset’ to be followed by a carriage return. Running this Whammy Burger script directly on the command line will act normally—print the text in green—but running it in GeekTool will display an “[0m” at the end of the green text.
- #!/usr/bin/perl
- use Term::ANSIColor;
- print color 'green';
- print "Whammy Burger!\n";
- print color 'reset';
The solution is to move the final ‘\n’ below the reset.
I’m not sure what the ‘m’ means. Monitor?
↑Which is what provides the graphs in the screenshot. They’re created using Zenoss and displayed via a public URL, using Geektool’s image geeklet.
↑
- ANSI escape code
- “ANSI escape sequences are used to control text formatting, color, and other output options on text terminals.”
- GeekTool
- “GeekTool is a System Preferences module for Mac OS 10.5. It lets you display on your desktop different kind of informations, provided by 3 default plugins.” The plugins let you monitor files (such as error logs), view images (such as live graphs), and display the results of command-line scripts.
- Zenoss
- “Open Source Server and Network Monitoring”. Zenoss is built in Python and, at least on OS X, was very easy to set up.
More GeekTool
- Bluetooth battery early warning system
- Use GeekTool, or crontab or launchd and notifications, to know when your bluetooth batteries need recharging.
- icalBuddy and eventsFrom/to
- Ali Rantakari’s icalBuddy has an error in the documentation for the “eventsFrom/to” command-line option. Rather than “tomorrow at time” use “time tomorrow”.
- Put a relative clock on your Desktop with GeekTool
- There are a lot of desktop clocks that show the absolute time. But sometimes you just want to know if the time is today, or yesterday, or two days ago. Here’s how to do it with Python and GeekTool.
- Apple Mail on the Desktop with GeekTool
- Here’s a simple AppleScript to use with GeekTool to put your inbox on the Desktop.
- GeekTool, TaskPaper, and XML
- A script to convert a TaskPaper file to XML so as to filter it for specific tags and display the results on the Desktop.
- One more page with the topic GeekTool, and other related pages
Note: I’m guessing what the time format is for ps in the first script. I don’t understand what the “ps.1p” means in %l:ps.1p, in the man page description. That’s why I have an error condition for unknown time formats.