dammIT - notificationshttps://dammit.nl/2019-07-16T17:51:43+02:00A rantboxReceive Sentry messages as Telegram notifications2019-07-16T17:51:43+02:002019-07-16T17:51:43+02:00Michiel Scholtentag:dammit.nl,2019-07-16:/sentry-to-telegram.html<p>To be able to receive <a href="https://sentry.io/">Sentry</a> notifications on Telegram (without using the plugin which only works in the self-hosted Sentry server), one can use webhooks. As I have <a href="https://dammit.nl/webhaak-all-the-things.html">webhaak</a> to <strike>ducttape together</strike> webhook all the things, I created a script to send messages to our dev chat, filtering away some …</p><p>To be able to receive <a href="https://sentry.io/">Sentry</a> notifications on Telegram (without using the plugin which only works in the self-hosted Sentry server), one can use webhooks. As I have <a href="https://dammit.nl/webhaak-all-the-things.html">webhaak</a> to <strike>ducttape together</strike> webhook all the things, I created a script to send messages to our dev chat, filtering away some that are not relevant.</p>
<pre><code>#!/bin/bash
set -e
# Any subsequent(*) commands which fail will cause the shell script to exit immediately
if [ "$#" -ne 4 ]; then
echo "USAGE: sentry_to_telegram.sh [projectname] [culprit] [url] [message]"
exit 1
fi
PROJECTNAME="${1}"
CULPRIT="${2}"
URL="${3}"
MESSAGE="${4}"
# Filter away known things
if [[ $MESSAGE == *"Het ElementTree object kon niet"* ||
$MESSAGE == *"Meerdere resultaten gevonden in "* ||
$MESSAGE == *"Found multiple results in"* ||
$MESSAGE == *"Cannot find object for id"* ]];
then
exit
fi
# Make the URL a bit more neat
URL=${URL//?referrer=webhooks_plugin/}
# The message to send
REPORT="[${PROJECTNAME}] ${MESSAGE}
in ${CULPRIT}
${URL}"
#REPORT="${REPORT//_/\_/}"
# AwesomeCorp dev groupchat
CHATID="-4242424242"
KEY="YOUR:KEY-HERE"
TIME="10"
URL="https://api.telegram.org/bot$KEY/sendMessage"
curl -s --max-time $TIME -d "chat_id=$CHATID&disable_web_page_preview=1&text=$REPORT" $URL >/dev/null
exit
curl -X "POST" "https://api.telegram.org/bot${KEY}/sendMessage" \
-H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" \
--data-urlencode "text=${REPORT}" \
--data-urlencode "chat_id=${CHATID}" \
--data-urlencode "disable_web_page_preview=true" \
--data-urlencode "parse_mode=markdown"
</code></pre>
<p>This script is called from webhaak, with a config like the following:</p>
<pre><code> sentry:
triggerkey: 7c6bd635948eea920fc15df87400a45b056c9779f4305bf0
notify: false
command: /srv/scripts/sentry_to_telegram.sh "PROJECT_NAME" "CULPRIT" "URL" "TITLE"
</code></pre>
<p>You can see it in context in this <a href="https://github.com/aquatix/webhaak/blob/master/example_config/examples.yaml">webhaak example config</a>. The <code>notify: false</code> takes care no PushOver notification is sent every time the webhook is called.</p>webhaak all the things2019-07-15T10:45:18+02:002019-07-15T10:45:18+02:00Michiel Scholtentag:dammit.nl,2019-07-15:/webhaak-all-the-things.html<p><img alt="Literal screenshot of Python sourcecode of webhaak project" src="https://shuttereye.org/images/7f/7f5f7ebfbfbf8fdf_2000-2000.jpg"></p>
<p>If you're not using <a href="https://en.wikipedia.org/wiki/Webhook">webhooks</a> yet to automate things from automatically generating documentation, running tests, updating websites and web applications based on events, please go read up on them.</p>
<p>In the meanwhile, I've basically hooked up all my personal projects based on webhooks in GitHub and <a href="https://gitea.io/en-us/">gitea</a>, powered by my …</p><p><img alt="Literal screenshot of Python sourcecode of webhaak project" src="https://shuttereye.org/images/7f/7f5f7ebfbfbf8fdf_2000-2000.jpg"></p>
<p>If you're not using <a href="https://en.wikipedia.org/wiki/Webhook">webhooks</a> yet to automate things from automatically generating documentation, running tests, updating websites and web applications based on events, please go read up on them.</p>
<p>In the meanwhile, I've basically hooked up all my personal projects based on webhooks in GitHub and <a href="https://gitea.io/en-us/">gitea</a>, powered by my own <a href="https://github.com/aquatix/webhaak/">webhaak</a> webhook processor. webhaak can update Git repository checkouts, run commands, send push notifications <a href="https://github.com/aquatix/webhaak/tree/master/example_config">and more</a>, all based on a fairly simple <a href="https://github.com/aquatix/webhaak/blob/master/example_config/examples.yaml">yaml based config file</a>. I even hooked up Sentry messages to notifications in our work Telegram chat. Reminds me that I'll add that as another example.</p>
<p>I'm rather happy with it, and adding new functionalities or tie-in scripts whenever I need them. Maybe it's useful for you too. Of course, <a href="https://github.com/aquatix/webhaak/issues">requests are welcome</a> :)</p>diskspacealarm.py2018-06-01T15:51:12+02:002018-06-01T15:51:12+02:00Michiel Scholtentag:dammit.nl,2018-06-01:/diskspacealarm.html<p>Because it's Friday, I was bitten by a filled-up volume on my VPS again, because <a href="https://prometheus.io/">Prometheus</a> somehow is randomly crashing my VPS, and because I like thinkering and Python, I wrote a little notification script.</p>
<p>Yes, it checks for available disk space on your nodes, with configuration per hostname (it's …</p><p>Because it's Friday, I was bitten by a filled-up volume on my VPS again, because <a href="https://prometheus.io/">Prometheus</a> somehow is randomly crashing my VPS, and because I like thinkering and Python, I wrote a little notification script.</p>
<p>Yes, it checks for available disk space on your nodes, with configuration per hostname (it's all contained in the source file).</p>
<p>It takes paths and the amount of GB you want available as configuration under <code>FILESYSTEMS</code>.</p>
<p>Here it is:</p>
<pre><code>import http.client, urllib
import os
import socket
import sys
HOSTNAME = socket.getfqdn()
APP_TOKEN = '<your_pushover_app_token>'
USER_KEY = '<your_pushover_userkey>'
FILESYSTEMS = {
'host001.example.com': [
('/', 1),
('/var/local', 5),
('/home', 5),
],
'host002': [
('/', 5),
('/stuff', 100),
],
}
def needs_notifying(size_trigger, size_available):
"""Checks whether we need to send a notification
Args:
size_trigger: minimum amount of free space in GB
size_available: currently available free space in bytes
"""
return size_available <= (size_trigger * 1024*1024*1024)
def send_message(message):
conn = http.client.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json",
urllib.parse.urlencode({
"token": APP_TOKEN,
"user": USER_KEY,
"message": message,
}), { "Content-type": "application/x-www-form-urlencoded" })
conn.getresponse()
def send_lowdisk_message(messages):
message = '[{}] Low disk space on the following volumes:\n{}'.format(HOSTNAME, '\n'.join(messages))
send_message(message)
try:
filesystems = FILESYSTEMS[HOSTNAME]
except KeyError:
send_message('[spacealarm] No filesystem configuration found for {}'.format(HOSTNAME))
sys.exit(1)
messages = []
for filesystem in filesystems:
statvfs = os.statvfs(filesystem[0])
#statvfs.f_frsize * statvfs.f_blocks # Size of filesystem in bytes
#statvfs.f_frsize * statvfs.f_bfree # Actual number of free bytes
#statvfs.f_frsize * statvfs.f_bavail # Number of free bytes that ordinary users
# are allowed to use (excl. reserved space)
if needs_notifying(filesystem[1], statvfs.f_frsize * statvfs.f_bavail):
messages.append('{}: {:.1f}MB free'.format(filesystem[0], statvfs.f_frsize * statvfs.f_bavail / 1024/1024))
if messages:
send_lowdisk_message(messages)
</code></pre>Get a push notification when your laptop is low on battery2016-11-21T13:38:06+01:002016-11-21T13:38:06+01:00Michiel Scholtentag:dammit.nl,2016-11-21:/20161121-get-a-push-notification-when-your-laptop-is-low-on-battery.html<p>A while ago <a href="https://dammit.nl/20150307-getting-a-push-message-on-your-phone-or-watch-when-your-laptop-battery-is-running-low.html">I wrote about getting notified on battery low</a>. It is quite useful when you leave your laptop unattended for a while, to get a notification on your phone and/or smartwatch when that laptop is about to run out of juice. It has saved me a few …</p><p>A while ago <a href="https://dammit.nl/20150307-getting-a-push-message-on-your-phone-or-watch-when-your-laptop-battery-is-running-low.html">I wrote about getting notified on battery low</a>. It is quite useful when you leave your laptop unattended for a while, to get a notification on your phone and/or smartwatch when that laptop is about to run out of juice. It has saved me a few hard shutdowns (or interrupted tasks because of forced hibernation).</p>
<p>The <code>udev</code> rule in that article should still work (if your device/battery emits those kinds of events at least), but for me the PushBullet method used there stopped working.</p>
<p>As I recently started using <a href="https://pushover.net/">PushOver</a> next to PushBullet, I decided to redo the little setup with a cronjob and <a href="https://github.com/jnwatts/pushover.sh">a PushOver shell script</a>. The cronjob works around the battery subsystem not emitting an event when you need it, the shell script has less dependencies than a Python script.</p>
<p>An example <em>with</em> the <code>udev</code> rule could look like this:</p>
<pre><code>/etc/udev/rules.d/99-lowbat.rules
# Suspend the system when battery level drops to 5% or lower
SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{capacity}=="[0-5]", RUN+="/home/youruser/bin/powerlow_notification.sh"
</code></pre>
<p>(Rule based on a snippet found on <a href="https://wiki.archlinux.org/index.php/Laptop#hibernate_on_low_battery_level">this handy wikipage</a>)</p>
<p>Myself, I wrote a cronjob to be run every 5 minutes (you can use whatever interval you prefer of course), which looks like this:</p>
<pre><code>#!/bin/bash
BATTERYLEVEL=$(cat /sys/class/power_supply/BAT0/capacity)
if [ $BATTERYLEVEL -lt 15 ]; then
/home/youruser/workspace/pushover.sh/pushover.sh -t "Power low on $HOSTNAME" "Battery power now is ${BATTERYLEVEL}%"
fi
</code></pre>
<p>This takes the current battery level from the <code>udev</code> system path, checks whether the value is less than 15 (percent) and sends a message through PushOver if it is. It will do so every 5 minutes until it's over 15 again, but that's fine with me (and a small price to pay on a system without the battery events). It might be made a bit more clever with keeping track of 'did I just send a message already' state files, but that exercise is left for the reader :)</p>
<p>Then, the crontab entry looks thusly:</p>
<pre><code># Check battery level every five minutes, PushOver message when below a certain percentage
*/5 * * * * /home/youruser/bin/cron/check_battery_level
</code></pre>
<p><em>N.B.:</em> the little <a href="https://github.com/jnwatts/pushover.sh"><code>pushover.sh</code></a>) script that I used, has a config file, located in <code>${HOME}/.config/pushover.conf</code>, which takes your PushOver application token, your user token and optional CURL options:</p>
<pre><code>TOKEN="your application's token here"
USER="your user/group key here"
CURL_OPTS="options to pass to curl"
</code></pre>
<p>Your user token is on the <a href="https://pushover.net/">homepage of PushOver</a> if you are logged in. The Application Token ('TOKEN') you can create by scrolling down that page and create a new application in Your Applications. There you can give it a nice icon and such too.</p>I made a thing to make your phone go 'pling' (when your train goes 'whatever')2015-09-19T12:07:36+02:002015-09-19T12:07:36+02:00Michiel Scholtentag:dammit.nl,2015-09-19:/20150919-i-made-a-thing-to-make-your-phone-go-pling-when-your-train-goes-whatever.html<p>I made a thing: <a href="https://pypi.python.org/pypi/nsapi">https://pypi.python.org/pypi/nsapi</a>.</p>
<p>You can use it with my other thing at <a href="https://github.com/aquatix/ns-notifications">https://github.com/aquatix/ns-notifications</a> to get notified when your train is late, or to know when you can do a sprint upstairs on the next station because your otherwise impossible …</p><p>I made a thing: <a href="https://pypi.python.org/pypi/nsapi">https://pypi.python.org/pypi/nsapi</a>.</p>
<p>You can use it with my other thing at <a href="https://github.com/aquatix/ns-notifications">https://github.com/aquatix/ns-notifications</a> to get notified when your train is late, or to know when you can do a sprint upstairs on the next station because your otherwise impossible transfer is delayed a bit and you can catch it now.</p>
<p>See the <a href="https://github.com/aquatix/ns-notifications/blob/master/settings_example.py">settings_example.py</a> and the <a href="https://github.com/aquatix/ns-notifications/blob/master/README.md">ns-notifications README</a> to configure.</p>
<p>Enjoy!</p>
<p>PS: yeah, it makes use of the official Nationale Spoorwegen (NS/Dutch Railways) API, and you need to request a key with them to use it. That's easy though and worth it if you like timely notifications.</p>Getting a push message on your phone or watch when your laptop battery is running low2015-03-07T14:43:30+01:002015-03-07T14:43:30+01:00Michiel Scholtentag:dammit.nl,2015-03-07:/20150307-getting-a-push-message-on-your-phone-or-watch-when-your-laptop-battery-is-running-low.html<p>When your laptop is sitting on a table and you're doing some other stuff in the meanwhile, it might quietly be running out of battery. In that case, you likely want to be nudged to find it a power outlet before it has to shut down or hibernate.</p>
<p>Wouldn't it …</p><p>When your laptop is sitting on a table and you're doing some other stuff in the meanwhile, it might quietly be running out of battery. In that case, you likely want to be nudged to find it a power outlet before it has to shut down or hibernate.</p>
<p>Wouldn't it be nice to get a push message on your phone (or even smartwatch, because hey, it's 2015)? You can :)</p>
<p>On Linux, there's <code>udev</code>, which takes care of a lot of the subsystems of your machines. Add a rule by creating a file called <code>90-lowbattery.rules</code> in <code>/etc/udev/rules.d/</code> and add the following line:</p>
<pre><code>SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{capacity}=="20", RUN+="/root/bin/pingphone.sh battery_20percent"
</code></pre>
<p>You can customise the exact RUN command of course. The 'capacity' part is the percentage of battery left; in this case 20%.</p>
<p>If you don't know <a href="https://www.pushbullet.com/">PushBullet</a> yet, now is the time to introduce you to this excellent push platform. It's really quite nifty, cross-platform and has plenty of uses in day-to-day life. The <code>pingphone.sh</code> script looks like this:</p>
<pre><code>#!/bin/bash
echo "`date +%Y%m%d_%H%M` $1" >> /root/bin/pingphone.log
. /root/.virtualenvs/pushbullet/bin/activate
python /root/bin/pyPushBullet/pushbullet_cmd.py yourpushbulletkey1234567890abcde note 123456 "laptop battery low" "$1"
</code></pre>
<p>Replace the <code>yourpushbulletkey1234567890abcde</code> part with your actual PushBullet API key and the <code>123456</code> with the deviceID you want the note to be pushed to. (Actually it's of the format <code>udeCmddJpl</code> and you can get the relevant one by doing a <code>python /root/bin/pyPushBullet/pushbullet_cmd.py yourpushbulletkey1234567890abcde getdevices</code>). The <code>$1</code> is the message <code>battery_20percent</code> of the RUN command, which you can of course let say anything you like.</p>
<p>As you see, it uses a Python script to push a note through PushBullet. Clone <a href="https://github.com/Azelphur/pyPushBullet">pyPushBullet</a> into a dir (like <code>/root/bin</code>) and correct the above command line to have it point there. As pyPushBullet needs a few support libraries, the cleanest way to install these is by creating a <a href="http://docs.python-guide.org/en/latest/dev/virtualenvs/">virtualenv</a> and <code>pip install</code> them in there:</p>
<pre><code>mkvirtualenv pushbullet
pip install websocket-client
pip install requests
pip install python-magic
</code></pre>
<p>This creates a <code>pushbullet</code> directory in <code>/root/.virtualenvs/</code> and installs the three dependencies in there that pyPushBullet needs to do its thing. This environment gets activated by sourcing the <code>activate</code> script on the third line in the <code>pingphone.sh</code> script, as seen above.</p>
<p>Now test the script by running:</p>
<pre><code>/root/bin/pingphone.sh test
</code></pre>
<p>This should land a push message on your device.</p>
<p>All kinds of other things can be fired by these <code>udev</code> triggers. If you'd like your machine to automatically suspend for example (if it is not already configured to do so), you can have it look like this: <code>RUN+="/usr/bin/systemctl suspend"</code></p>