Kvällskodning – Pythonscript som kollar om dina sajter är uppe och varnar via SMS

Micke Kring
Micke Kring 665 visningar
7 minuters läsning

Har ni som jag en massa sajter som ni gärna vill hålla koll på huruvida de är uppe och rullar eller inte längre svarar? Kanske vill ni få en notis innan världen börjar höra av sig? Självklart finns det redan ett gäng sådana riktigt bra tjänster, som Pingdom och updown.io, men de är ju förknippade med en liten summa pengar. Om du bara vill ha en enklare tjänst som inte kostar något, så varför inte koda ihop något själv?

EDIT 28 december 2019: Utökat script med mail och enkel loggning finns nu längre ned.

I filmen nedan ser ni två terminal-fönster. I det vänstra kör jag scriptet, som var 5:e sekund frågar de sajter jag specificerat om de mår bra. Om sajterna svara med 200 så är allt fint. Om de inte mår bra, så skickas ett SMS till mig om det.
I det högra fönstret, så ser ni mig stoppa webbservern för kunskapshubben.se och sedan ser ni hur scriptet märker det och skickar SMS:et.

Det här är grundstommen och givetvis behöver vi bygga ut programmet så att det inte skickar ett SMS var 5:e sekund så länge sajten är nere. Men det är något att utgå från. Jag använder tjänsten Twilio för att skicka SMS, så du behöver ett konto och en API-nyckel. Den infon lagrar du i credentials-filen.
Givetvis skulle du kunna sätta upp det så att ett twitterkonto skickar ut en tweet när en sajt ligger nere. Eller att ett mail skickas.

Grundscriptet har jag tagit från https://gist.github.com/ameesters/3952890, så all kredd i världen till Martin Thoma Därefter har jag moddat det lite och lagt till SMS-delen.

main.py

Det här är filen som körs. Funkar med Python 3.x
I listan names lägger ni till de sajter ni vill testa.

#!/usr/bin/env python

import requests, time, os, yaml
from collections import namedtuple
from twilio.rest import Client

WebsiteStatus = namedtuple('WebsiteStatus', ['status_code', 'reason'])

names = ['https://mickekring.se', 'https://arstaskolan.se', 'https://site.arstaskolan.se', 'https://kodknack.se', 
'https://kurser.arstaskolan.se', 'https://mikportalen.se', 'https://www.kunskapshubben.se', 'https://support.arstaskolan.se', 
'https://www.bibblis.se', 'https://hearly.se', 'http://riktigtsant.se', 'https://makerspace.arstaskolan.se', 
'http://talasomted.se']

conf = yaml.load(open("credentials.yml"))

def get_status(site):
    try:
        response = requests.head(site, timeout=5)
        status_code = response.status_code
        reason = response.reason
    except requests.exceptions.ConnectionError:
        status_code = '000'
        reason = 'ConnectionError'
        sendSMS(site)
    website_status = WebsiteStatus(status_code, reason)
    return website_status

def sendSMS(site):
    account_sid = conf["twilio"]["account_sid"]
    auth_token = conf["twilio"]["auth_token"]
    client = Client(account_sid, auth_token)
    message = client.messages.create(
        to= conf["twilio"]["to_phone_number"],
        from_= conf["twilio"]["from_phone_number"],
        body="Varning!\n" + site + " svarar inte just nu.")
    print(message.sid)
    
def Main():
    while True:
        os.system("clear")
        for name in names:
            site = '{}'.format(name)
            website_status = get_status(site)
            print("{0:30} {1:10} {2:10}".format(site, website_status.status_code, website_status.reason))
        time.sleep(5)
        os.system("clear")

Main()

credentials.yml

Här lagrar vi våra känsliga uppgifter, som lösenord och API-nycklar.

twilio:
  account_sid: "abc123"
  auth_token: "abc123"
  from_phone_number: "+46123456789"
  to_phone_number: "+46123456789"

Utökat script 28 december 2019 – del 2 – mail och loggning

Jag la till lite funktionalitet som en enkel loggning samt möjlighet att skicka mail istället för – eller tillsammans med – SMS. Jag kör detta skarpt på en av mina Raspberry Pi och kommer återkomma med uppdateringar om hur det rullar.
Kom ihåg också att lägga till password för mail i credentials-filen.

I filmen nedan ser ni hur det funkar samt vad som händer när jag släcker ned skolans webbservrar. 🙂

Kod

#!/usr/bin/env python

import requests, time, os, yaml
from time import strftime
from collections import namedtuple
from twilio.rest import Client
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import email
import email.mime.application
import smtplib

WebsiteStatus = namedtuple('WebsiteStatus', ['status_code', 'reason'])

### Names - Add all url's you'd like to monitor 
names = ['https://mickekring.se', 'https://arstaskolan.se', 'https://site.arstaskolan.se', 'https://kodknack.se', 
'https://kurser.arstaskolan.se', 'https://mikportalen.se', 'https://www.kunskapshubben.se', 'https://support.arstaskolan.se', 
'https://www.bibblis.se', 'https://hearly.se', 'http://riktigtsant.se', 'https://makerspace.arstaskolan.se', 
'http://talasomted.se']

### Reads passwords and stuff from file
conf = yaml.load(open("credentials.yml"))

### Creating list to save sites that are down
sentWarning = []

def get_status(site):
    try:
        response = requests.head(site, timeout=5)
        status_code = response.status_code
        reason = response.reason
        
        if site in sentWarning:
            sentWarning.remove(site)
            msgToSend = ("Your site - " + site + "  - is now up and running again.")
            subjToSend = "WebCheck Go - Your site is UP"
            sendMail(site, msgToSend, subjToSend)
            #sendSMS(site, msgToSend, subjToSend)
            logging(site, subjToSend)
        else:
            pass
    
    except requests.exceptions.ConnectionError:
        status_code = '000'
        reason = 'ConnectionError'
        
        if site not in sentWarning:
            sentWarning.append(site)
            msgToSend = ("Your site - " + site + " - is currently down.")
            subjToSend = "WebCheck Error - Your site is DOWN"
            sendMail(site, msgToSend, subjToSend)
            #sendSMS(site, msgToSend, subjToSend)
            logging(site, subjToSend)
        else:
            pass
    
    website_status = WebsiteStatus(status_code, reason)
    return website_status

def sendSMS(site, msgToSend, subjToSend):
    account_sid = conf["twilio"]["account_sid"]
    auth_token = conf["twilio"]["auth_token"]
    client = Client(account_sid, auth_token)
    message = client.messages.create(
        to= conf["twilio"]["to_phone_number"],
        from_= conf["twilio"]["from_phone_number"],
        body=subjToSend + "\n" + msgToSend)
    print(">>> Successfully sent SMS")

def sendMail(site, msgToSend, subjToSend):
    msg = MIMEMultipart()
    message = msgToSend
    password = conf["email"]["password"]
    msg['From'] = "m.m@mail.se"
    msg['To'] = "m.m@mail.com"
    msg['Subject'] = subjToSend
    msg.attach(MIMEText(message, 'plain'))
    server = smtplib.SMTP('smtp-relay.sendinblue.com: 587')
    server.starttls()
    server.login(msg['From'], password)
    server.sendmail(msg['From'], msg['To'], msg.as_string())
    server.quit()
    print(">>> Successfully sent email to %s:" % (msg['To']))

def logging(site, subjToSend):
    with open("updownlog.csv", "a") as updownlog:
        updownlog.write("\n{0},".format(strftime("%Y-%m-%d %H:%M:%S")) + site + "," + subjToSend + "")
        print(">>> Successfully logged incident.")
    
def Main():
    while True:
        try:
            os.system("clear")
            print("Testing sites\n")
            for name in names:
                site = '{}'.format(name)
                website_status = get_status(site)
                print("{0:30} {1:10} {2:10}".format(site, website_status.status_code, website_status.reason))
            time.sleep(5)
            os.system("clear")
        except:
            pass

if __name__ == "__main__":
    Main()

Frågor?

Ni är som vanligt välkommen att ställa frågor eller undra saker i kommentarsfältet nedan eller via valfritt socialt media.

Dela den här artikeln
Följ:
Fixar och trixar med tekniska lösningar och mycket mer. Ser till att användarna förstår systemen och att systemen förstår användarna. Har mina rötter i musiken och kombinerar konstnärlighet med teknik.