Bad App Alert? You could take this to mean that I’m alerting you of a problem with an app or that I’m showing you how to be notified when an app is behaving badly. It’s a little of both.
UPDATE: Added extra note under Save the Script for adjusting script to open an app when clicking on the notification.
I use Apple’s Notes constantly on Mac and iPhone since it can store in the cloud, appearing instantly on any device, and has new features like folders, multimedia, and security. However, on Mac it regularly freaks out for no apparent reason, going to 100% CPU without stopping, and must be force quit. While annoying, it’s not difficult to deal with.
However, I hate that it tries to destroy the computer until I stumble across the situation. Often I return to my MacBook to find it hot to the touch and I immediately know who the likely culprit is so I glance at smcFanControl in the menu bar to confirm the CPU temperature is way too high. I fire up Activity Monitor to find Notes using 100% CPU and force quit it. Excessively long high temperatures and prolonged CPU usage are probably not great for the computer if it’s not actually doing anything for that brief time then stopping. Or sometimes on battery power I realize too late that all of my portable work time is gone. It would be nice to be notified when an app is behaving badly instead of waiting to happen across it later.
Based on the excellent answer to a StackExchange question, I came up with the following to get a notification if any app started using too much CPU:
1. Save the Script
First step is to get the script from the link above. Here is a copy of it for reference:
#!/bin/bash cpulimit=50 prefix=${TMPDIR}cron_cpu current=$(ps -erco %cpu,command | tail -n+2 | sed 's/^ *//') echo "$current" > $prefix$(date +%s) a=($prefix*); for ((i=0;i<=${#a[@]}-3;i++)); do rm "${a[i]}"; done [[ $(awk '{s+=$1}END{printf "%i",s}' <<< "$current") -lt $cpulimit ]] && exit averages=$(awk '{cpu=$1;sub(/[^ ]+ /,"");a[$0]+=cpu;c[$0]++}END{for(i in a){printf "%.1f %s\n",a[i]/c[$0],i}}' $prefix* | sort -rn) if [[ $(awk '{s+=$1}END{printf "%i",s}' <<< "$averages") -ge $cpulimit ]]; then terminal-notifier -title "CPU use" -message "$(head -n5 <<< "$averages" | paste -sd / -)" fi
I saved mine as “cpuwatch.sh” in my handy scripts folder.
After using this for a while I found myself wanting to click on the notification to see more details. I wanted it to take me directly to Activity Monitor so I changed the terminal-notifier line in the script to this (adding -activate to the end):
terminal-notifier -title "CPU use" -message "$(head -n5 <<< "$averages" | paste -sd / -)" -activate 'com.apple.ActivityMonitor'
2. Get Terminal Notifier
The simplest way I got Terminal Notifier was with the following Terminal command from their page:
$ [sudo] gem install terminal-notifier
3. Add PATH to the Script
The previous step installed terminal-notifier into /usr/local/bin. While the script worked fine this way in Terminal, it needed to know where to find Terminal Notifier when running automatically so this line was added to the script:
export PATH=/usr/local/bin:$PATH
4. Add to launchctl
To automate this we needed to add this to launchctl. The simplest way is to create a new job with something like LaunchControl.* Just add the path, add a Start Interval (I used 60 seconds), and optionally add a Standard Output to look for any errors with the script or this setup (this is how I found the PATH issue). *See Startup Item Help for an expanded discussion about adding to launchctl.
You’re done! Now if an app is using a lot of CPU you’ll get a notification. If notifications get too annoying I may bump up the threshold in the script, but hopefully Apple will update Notes soon before it eats my MacBook.
Leave a Reply
You must be logged in to post a comment.