This commit is contained in:
Justine 2019-11-01 12:32:43 +01:00
commit 405ebc5462
6 changed files with 855 additions and 0 deletions

539
JuMonitor.py Normal file
View File

@ -0,0 +1,539 @@
#!/usr/bin/env python3
# encoding: utf-8
import os
import sys
import smtplib
from getpass import getpass
import datetime
import time
import threading
import configparser
import argparse
#JuMonitor : A simple monitoring script
#This scripts regularly pings client machines, and can send alerts by mail.
#We use threading to do two things at the same time : pinging clients, and putting back dead clients in the live list of clients to ping them again. We also have a thread for log sending.
#We use SMTP with TLS here, but it's easy to use unsecure TLS : see the sendMail() function
#This script is made for Linux. Please use free software and OS !
#BIEN VERIFIER QUE LE PING DES MORTS ET LES RAISE FONCTIONNENT
#A faire : En plus du ping, proposer d'ouvrir des connexions. On peut peut-être faire du wget sur les pages web?
#A faire : Proposer le résultat sous la forme de tableau à envoyer régulièrement.
#A faire : Proposer de vider le log tous les X
#A faire : Résultat graphique (webui)
#TODO : SNMP?
#Justine PELLETREAU
###########################################FUNCTIONS#######################
#####################
def timeNow():
'''This function returns current date and time formatted as a string.
no args
Returns : now : a str containing "XX month YEAR 12:00:00"
'''
now=datetime.datetime.now().strftime("%d %b %Y %H:%M:%S")
return now
def log(action):
'''
This function is used for logging "action" (preceeded by datetime) into a file called ./jumonitor.log. Also prints onscreen it if verbose is set.
Args:
-action : an str containing the contents to log.
GLOBAL VAR (optional):
-verbose : a bool defining if we print to screen or not.
No returns.
'''
args = getArgs() #Getting the args because we want to know verbosity
verbose = args.verbose
with open("jumonitor.log", "a") as mylog:
formatted_action="{} ====> {}".format(timeNow(), action)
mylog.write(formatted_action)
mylog.write("\n")
if verbose:
print(formatted_action)
def getClients():
'''
This function gets a list client machines as a couple name - ip, and returns it in a dict.
No args
Returns:
-clients : the dict containing our clients
'''
clients = {} #Dict of all clients to ping
name, ip = "", "" #Name and IP address of a client
while True: #Loop ends when the function returns
name = str(input("Enter the NAME of next client machine (END if you're finished) > "))
if name == 'END':
return clients #End the function when receiving END
ip = str(input("Enter IP Address of next client machine > "))
clients[name] = ip
return clients
def getMail():
'''
This function asks for info regarding email sending, stores it in a dict.
No args
Returns :
-mail_info : a dict containing info about the mail server and the user
'''
mail_info = {}
mail_info['server_address'] = str(input("Enter the address of SMTP with TLS server \n(For gmail, use smtp.gmail.com) : "))
mail_info['server_port'] = int(input("Port? (587 generally works) : "))
mail_info['server_username'] = str(input("Enter the email address the emails will be sent from: "))
mail_info['server_password'] = getpass("Password ? : ")
mail_info['server_recipient'] = str(input("Enter email address to send emails to (it can be the same address!): "))
return mail_info
def sendMail(mail_text, mail_info):
'''
This function sends an email.
Args :
-mail_text : the text of the mail to send
-mail_info : dict generated by the getMail() function
No returns
'''
log("Now trying to send an email. This process is optimized for gmail.") #Giving info...
server = smtplib.SMTP(mail_info['server_address'], mail_info['server_port']) #Creating the server object
try:
server.ehlo() # Connecting to the server
server.starttls() # Using TLS for obvious safety reasons, remove for unsecure connection at your own risk
server.login(mail_info['server_username'], mail_info['server_password']) # Loging into gmail
server.sendmail(mail_info['server_username'], mail_info['server_recipient'], mail_text) #Sending the mail
except:
log("Something went wrong trying to send the mail. Please check settings and retry.\n===>You may need to allow unsecure apps to send emails in your gmail account settings.\nmailinfo are : {}".format(mailinfo))
exit()
else:
log("Mail successfully sent!")
def pingTest(ipaddress):
'''
This function pings an IP address, returns True if address answers, returns False if address does not answer.
Args :
-ipaddress : a str containing an IP address
Returns:
-True : address answered
-False : address did not answer
'''
cmd = os.popen("ping -c 1 {}".format(ipaddress))
cmdresult = cmd.read()
if "1 received" in cmdresult:
return True
else:
return False
def makeAlert(ip, name, interval):
'''
This Function generates an alert to send via email, telling that a client machine does not answer ping.
args :
-ip : IP address of said client
-name : name of said client (FQDN or not)
-interval : interval in minutes (after which we will retry pinging the client)
returns:
-text : A string containing the raw text of the email, to send directly via smtp
'''
date_formatted = timeNow()
hostname = os.popen("hostname") #Getting hostname of local machine
hostname = hostname.read()
hostname = hostname[:2] #Getting rid of \n generated by hostname command
text = "Subject: Client {} not answering\n\nHello\n This mail informs you that at the time of {}, pinging the client {} (Name or IP address : {}) from machine {} resulted in a failure.\n We will retry pinging them in {} minutes.".format(name, date_formatted, name, ip, hostname, interval)
return text
def monitor(send_alerts, clients, dead_clients, interval, interval_dead_clients, mailinfo):
'''
This function is used to monitor clients by pinging them regularly. It displays info in real time.
Args:
-send_alerts : a bool that says if the client wants alerts by mail or not
-clients : dict of live clients
-dead_clients : dict of dead clients
-interval : an interval in seconds, the time we wait inbetween pings
-interval_dead_clients : an interval in minutes, the time we wait before retrying dead clients
-mailinfo : a dict containing info to send mails, generated by getMail()
No returns
'''
while True:
for i in list(clients):
if pingTest(clients[i]):
log("Client {} answered at {}.".format(i, timeNow()))
else:
log("Client {} did not answer or is unknown.".format(i, mailinfo['server_recipient']))
if send_alerts: #Only send a mail if the user wants it
sendMail(makeAlert(clients[i], i, interval_dead_clients), mailinfo)
log("\tSending an alert mail to {}".format(mail_info['server_recipient']))
dead_clients[i] = clients[i] #Poor client is dead...
del clients[i]
time.sleep(interval)
log("List of dead clients so far : {}".format(str(dead_clients)))
def raiseClient(clients, dead_clients, interval, mailinfo):
'''
This function waits a given time, and pings the dead clients We send a mail and put them back in the live queue if they answer. Made to use as a thread.
Args:
-clients : dict of live clients
-dead_clients : dict of dead clients
-interval : A time in minutes
-mailinfo : generated by getmail()
No returns
'''
while True:
time.sleep(interval)
for i in list(dead_clients):
if pingTest(dead_clients[i]):
clients[i] = dead_clients[i]
log(i, "is back ! Putting it back in the live queue and sending an email.")
sendMail("Subject : client {} active again\n\nThis is a mail from JuMonitor to inform you that the client {} ( {} ) is live again.".format(i, i, dead_clients[i]), mailinfo)
del dead_clients[i]
else:
log("{} still not answering".format(i))
def sendTestmail(mailinfo):
'''
Sends a test e-mail.
No args
No returns
'''
text = "Subject: Hi\n\nHi, this a test from JuMonitor. Hope you like this program :D"
try:
sendMail(text, mailinfo)
log('Test Mail sent. Please check inbox/spam.')
except exception as e:
log("Sending test mail failed. sendMail returned {}".format(e))
def sendLog(log: str, mailinfo: dict, waittime :int):
'''
This function is used to send the log file by mail every time minutes.
Args:
-log : name of log file (str)
-mailinfo : dict generated by getMail()
-time : an int indicating a number of minutes
No returns
'''
#Getting user's hostname
hostname = os.popen("hostname")
hostname = hostname.read()
hostname = hostname[:2] #Getting rid of \n generated by hostname command
while True:
time.sleep(waittime*60)
with open(log, "r") as logfile:
sendMail("Subject: logfile from JuMonitor running on{}\n\n{}".format(hostname, logfile.read()), mailinfo)
log("===>Log sent to {}".format(mailinfo['server_recipient']))
def doYouWantLog():
'''
This functions asks the client if they want to regularly receive the logfile by mail.
No args
-Returns:
log_send_interval : interval in minutes at wich the client wants to receive the logfile. if 0, don't send the log file!
'''
log_send_interval = 0
client_wants_log=False
answer = str(input("Do you want to regularly receive the logfile by mail? [y/n] > "))
if answer == "y":
client_wants_log = True
if client_wants_log:
log_send_interval = int(input("==> At wich interval (in minutes)?\n(An interval of 0 will not send anything) : "))
return log_send_interval
def doYouWantAlerts():
'''
Asks the user if if he wants to receive alerts by mail.
No args
Returns True / False
'''
answer=str(input("Do you want to be informed by mail when a client stops answering to our pings (becomes 'dead')? [y/n] > "))
if answer == "y":
return True
else:
return False
def loadConfig():
'''
Loads the configuration file jumonitor.conf and returns all the variables.
No args
Returns:
-Clients : A dict containing all the clients and their IPs
-log_send_interval = 0 or +
-send_alerts = True / False
-mailinfo = Dict like one generated by getMail()
-interval = an int
-interval_dead_clients = an int
'''
#Initializing the vars with default values just in case
clients={}
dead_clients={} #Will always start empty
log_send_interval = 0
send_alerts = False
mailinfo = {}
interval = 5
interval_dead_clients = 5
config=configparser.ConfigParser() #Creating parser object
config.read('jumonitor.conf') #Reading the file (it is loaded in the parser itself)
#Getting the clients
for key, value in config.items('Clients'):
clients[key]=value
#Getting the Alerts
log_send_intervals = int(config['Alerts']['log_send_interval']) #is an int
send_alerts = config['Alerts'].getboolean('send_alerts')
#Getting Mailinfo
for key, value in config.items('Mailinfo'):
mailinfo[key]=value
#Getting intervals
interval = int(config['Intervals']['interval'])
interval_dead_clients = int(config['Intervals']['interval_dead_clients'])
return clients, dead_clients, log_send_interval, send_alerts, mailinfo, interval, interval_dead_clients
def dynamicStart():
'''Is used to ask for all info when starting in dynamic mode (ie, not loading from the config but asking for info).
No args
Returns:
-Clients : A dict containing all the clients and their IPs
-log_send_interval = 0 or +
-send_alerts = True / False
-mailinfo = Dict like one generated by getMail()
-interval = an int
-interval_dead_clients = an int
'''
filename = "NOTHING" #The file where this will be saved
mode = 0
print("*" * 20, "Welcome to JuMonitor", "*" * 20)
print("This is a simple monitoring program, designed to quickly be informed when one of your servers goes down and does not answer.")
print("As your started in dynamic mode, that means you do not have anything configured yet. We will be asking for info.")
print("After that, you will have the possibility to save evrything in a configuration file.\n")
print("First, we need to know who you want to monitor.")
clients = getClients()
dead_clients = {} #Used to store clients who don't answer
#Does the user want to receive the logfile by mail?
log_send_interval = doYouWantLog()
#Does the client want to receive alerts by mail?
send_alerts=doYouWantAlerts()
#If any mails have to be sent, ask for mail info
if send_alerts or log_send_interval > 0:
print("Next, we need mail info to warn you about dead clients.")
mailinfo = getMail()
###Checking if email sending works
test_mail = ""
while test_mail != "y" and test_mail != "n":
test_mail = str(input("Sending a test mail is recommended. Try it? [y/n] : "))
if test_mail == "y":
sendTestmail(mailinfo)
else:
mailinfo={} #Just to ensure no function crashes, an empty mailfo is required
#Monitoring part
interval = int(input("At which interval must we ping the clients (in seconds)? : "))
interval_dead_clients = int(input("At which interval should we retry to ping dead clients?\n(In seconds) : "))
#Saving/Printing the config file
print("Now that we have everything we need, you might want to save it somewhere.")
print("Enter a number according to the following:\n\t1 : Save to a file\n\t2 : print everything on screen\n\t3 : both ")
while mode not in range(1, 4):
mode = int(input(" > "))
#Calling our conf-writing function
#dead_clients is not passed to it as it always starts as {}
saveConfigFile(clients, log_send_interval, send_alerts, mailinfo, interval, interval_dead_clients, filename, mode)
print("\nOk, configuration is over ! \nIf you saved your configuration in a file, be warned that you have to name it jumonitor.conf to get it to automatically load.\n\nStarting monitoring.")
return clients, dead_clients, log_send_interval, send_alerts, mailinfo, interval, interval_dead_clients
def saveConfigFile(clients, log_send_interval, send_alerts, mailinfo, interval, interval_dead_clients, filename, mode):
'''
This functions takes info given to it and writes to a configuration file, or prints it on screen, or both, depending on the mode (1, 2 or 3).
Args:
(JuMonitor Config info)
-Clients : A dict containing all the clients and their IPs
-log_send_interval = 0 or +
-send_alerts = True / False
-mailinfo = Dict like one generated by getMail(), OR an empty dict if no mailinfo was genereated previously
-interval = an int
-interval_dead_clients = an int
-mailinfo : a dict generated by getmail()
(Function vars)
-filename : the name given to the config file
-mode : an int equal to 1, 2 or 3 dictating the behaviour of this function:
1 : save to a file
2 : print everything on screen
3 : both
'''
#Taking into consideration that we might not want to save to a file
if mode == 3:
filename = "NOTHING"
#Used to store the config file as a str to log it
contents = ""
config=configparser.ConfigParser()
#We take every info and put it the config object
#Clients
config['DEFAULT']={}
config['Clients']=clients
#Alerts
config['Alerts']=\
{'log_send_interval' : log_send_interval,\
'send_alerts' : send_alerts}
if mailinfo != {}:
#Mail
config['Mailinfo']=\
{'server_address' : mailinfo['server_address'],\
'server_port' : mailinfo['server_port'],\
'server_username' : mailinfo['server_username'],\
'server_password' : mailinfo['server_password'],\
'server_recipient' : mailinfo['server_recipient']}
else:
config['Mailinfo']={}
#Intervals
config['Intervals']=\
{'interval': interval,\
'interval_dead_clients' : interval_dead_clients}
#Putting everything into a str for logging
for section in config.sections():
contents += str(dict(config[section]))
#We now print / write the file
if mode == 1 or mode == 3:
filename = str(input("What name do you want to give to your file? Watch out, any existing file will be overwritten. \nYou can include the extension, like .conf.\n Name it jumonitor.conf if you want it to automatically load. > "))
with open(filename, 'w') as configfile:
config.write(configfile)
if mode == 2 or mode == 3:
print(contents)
#Logging
log("Config Info given : {}".format(contents))
def getArgs():
'''Gets all the arguments passed to the script and returns them in a parse_args()-type object.
No args
Returns:
-args : an args object containing all the optional arguments passed to the script.
'''
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dynamic", help="Starts in dynamic mode.", action="store_true")
parser.add_argument("-t", "--testmail", help="Sends a test e-mail.", action="store_true")
parser.add_argument("-v", "--verbose", help="Print all debug info to screen as well as to logfile", action="store_true")
#Creating the args object
args=parser.parse_args()
return args
#########################################################MAIN PROGRAM############################
#Getting the args...
args=getArgs()
#Tell that we are starting in a clear way
log("#\n#\nSTARTING at {}".format(timeNow()))
#Is the launch dynamic or static?
if args.dynamic:
log("Getting info dynamically as -d has been used. ")
clients, dead_clients, log_send_interval, send_alerts, mailinfo, interval, interval_dead_clients = dynamicStart()
else:
log("Configuration information loading from jumonitor.conf")
clients, dead_clients, log_send_interval, send_alerts, mailinfo, interval, interval_dead_clients=loadConfig()
#Send a test mail?
if args.testmail:
if mailinfo != {}:
sendTestmail()
else:
log("Could not send test mail ! mailinfo are empty")
###THREADS
threadMonitor = threading.Thread(target=monitor, args=(send_alerts, clients, dead_clients, interval, interval_dead_clients, mailinfo))
threadRaise = threading.Thread(target=raiseClient, args=(clients, dead_clients, interval_dead_clients, mailinfo))
threadLogSend = threading.Thread(target=sendLog, args=("jumonitor.log", mailinfo, log_send_interval))
#These threads must run together, no RLocks here !
threadMonitor.start()
threadRaise.start()
#Only send logs if the client wants it
if log_send_interval > 0:
threadLogSend.start()

20
README.md Normal file
View File

@ -0,0 +1,20 @@
#JuMonitor : A simple monitoring script
This script is designed to monitor a list a clients by sending pings.
It can keep you informed by sending alerts, sending a logfile, or both, by mail.
##Contents:
* JuMonitor.py : The main program
* jumonitor.conf : the configuration file. See the comments inside of it for details.
* jumonitor.conf.orig : A sample configuration file, kept for backup.
* jumonitor.log : logfile generated by the program. Will be created if absent.
* juconfigen.py : generates a default config file. You should not need it to use this program.
##Options are:
* -h : prints the help
* -v : verbose (prints to screen as well as to logfile)
* -d : dynamic : instead of reading the config file, ask for info in a dynamic fashion
* -t : testmail : sends a test email
##Dynamic mode :
Dynamic mode is used when configuration has yet to be made. It is recommended if you don't know where to start. It asks for every information needed, and then allows you to save it to a file. It is quite slef-explanatory, however, using it with in verbose mode results in a VERY talkative manner.

29
juconfigen.py Normal file
View File

@ -0,0 +1,29 @@
import configparser
config=configparser.ConfigParser()
#Sections
config['DEFAULT']={}
config['Clients']={'CloudFlare' : '1.1.1.1'}
config['Alerts']=\
{'log_send_interval' : '0',\
'send_alerts' : 'False'}
config['Mailinfo']=\
{'server_address' : 'smtp.gmail.com',\
'server_port' : '587',\
'server_username' : 'jupythontest@gmail.com',\
'server_password' : 'Rataflup2503',\
'server_recipient' : 'justinepelletreau@gmail.com'}
config['Intervals']=\
{'interval': '5',\
'interval_dead_clients' : '5'}
#print({section: dict(config[section]) for section in config.sections()})
for section in config.sections():
print(dict(config[section]))
#with open('jumonitor.conf', 'w') as configfile:
# config.write(configfile)

46
jumonitor.conf Normal file
View File

@ -0,0 +1,46 @@
#The list of our clients.
#Stored as : name = hostname or IP
;Example: google = 8.8.8.8
[Clients]
cloudflare = 1.1.1.1
razian = 185.228.229.112
#log_send_interval = Interval in minutes
;We will send the logfile by mail every X minutes. Set it to 0 to avoid sending the logfile altogether.
#send_alerts : True or False.
;Dictates if we send an alert when a client dies or not.
[Alerts]
log_send_interval = 0
send_alerts = False
#This section can be left completely empty (with no key = value int!) but ONLY if you do not plan on sending emails.
#server_address : hostname
;hostname of the SMTP Server used to send mails. Only tested with Google ! We use TLS.
#server_port : port number
;port used to talk to the SMTP server
#server_username : an email address
;the email address that everything will be sent from
#server_password : a password
;used to connect to the server
#server_recipient : an email address
;the address everything will be sent to
;
[Mailinfo]
server_address = smtp.gmail.com
server_port = 587
server_username = jupythontest@gmail.com
server_password = Rataflup2503
server_recipient = justinepelletreau@gmail.com
#interval : an interval in seconds
;how often do we ping the clients
#interval_dead_clients : an interval in minutes
;how often do we retry pinging dead clients
;
[Intervals]
interval = 5
interval_dead_clients = 5

50
jumonitor.conf.orig Normal file
View File

@ -0,0 +1,50 @@
#This is a sample configuration file for JuMonitor.py, the simple monitoring script.
#Please keep this one as a backup and use a copy of it.
#in order to be loaded by the program, the configuration file has to be named jumonitor.conf
#The list of our clients.
#Stored as : name = hostname or IP
;Example: google = 8.8.8.8
;
[Clients]
cloudflare = 1.1.1.1
#log_send_interval = Interval in minutes
;We will send the logfile by mail every X minutes. Set it to 0 to avoid sending the logfile altogether.
#send_alerts : True or False.
;Dictates if we send an alert when a client dies or not.
;
[Alerts]
log_send_interval = 0
send_alerts = False
#This section can be left completely empty (with no key = value int!) but ONLY if you do not plan on sending emails.
#server_address : hostname
;hostname of the SMTP Server used to send mails. Only tested with Google ! We use TLS.
#server_port : port number
;port used to talk to the SMTP server
#server_username : an email address
;the email address that everything will be sent from
#server_password : a password
;used to connect to the server
#server_recipient : an email address
;the address everything will be sent to
;
[Mailinfo]
server_address = smtp.gmail.com
server_port = 587
server_username = mymailaddress@gmail.com
server_password = password
server_recipient = mymailaddress@gmail.com
#interval : an interval in seconds
;how often do we ping the clients
#interval_dead_clients : an interval in minutes
;how often do we retry pinging dead clients
;
[Intervals]
interval = 5
interval_dead_clients = 5

171
jumonitor.log Normal file
View File

@ -0,0 +1,171 @@
09 Jun 2019 13:39:34 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 13:39:34 ====>
STARTING at 09 Jun 2019 13:39:34
09 Jun 2019 13:39:34 ====> Client cloudflare answered at 09 Jun 2019 13:39:34.
09 Jun 2019 13:39:39 ====> List of dead clients so far : {}
09 Jun 2019 13:39:39 ====> Client cloudflare answered at 09 Jun 2019 13:39:39.
09 Jun 2019 13:40:23 ====>
STARTING at 09 Jun 2019 13:40:23
09 Jun 2019 13:40:23 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 13:40:23 ====> Client cloudflare answered at 09 Jun 2019 13:40:23.
09 Jun 2019 13:40:28 ====> List of dead clients so far : {}
09 Jun 2019 13:40:28 ====> Client cloudflare answered at 09 Jun 2019 13:40:28.
09 Jun 2019 13:45:36 ====> STARTING at 09 Jun 2019 13:45:36
09 Jun 2019 13:45:36 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 13:45:36 ====> Client cloudflare answered at 09 Jun 2019 13:45:36.
09 Jun 2019 13:45:41 ====> List of dead clients so far : {}
09 Jun 2019 13:45:41 ====> Client cloudflare answered at 09 Jun 2019 13:45:41.
09 Jun 2019 13:49:18 ====> STARTING at 09 Jun 2019 13:49:18
09 Jun 2019 13:49:18 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 13:49:18 ====> Client cloudflare answered at 09 Jun 2019 13:49:18.
09 Jun 2019 13:49:23 ====> List of dead clients so far : {}
09 Jun 2019 13:49:23 ====> Client cloudflare answered at 09 Jun 2019 13:49:23.
09 Jun 2019 13:51:19 ====> STARTING at 09 Jun 2019 13:51:19
09 Jun 2019 13:51:19 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 13:51:19 ====> Client cloudflare answered at 09 Jun 2019 13:51:19.
09 Jun 2019 13:55:11 ====> STARTING at 09 Jun 2019 13:55:11
09 Jun 2019 13:55:11 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 14:06:18 ====> STARTING at 09 Jun 2019 14:06:18
09 Jun 2019 14:06:18 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 14:06:18 ====> Client cloudflare answered at 09 Jun 2019 14:06:18.
09 Jun 2019 14:08:06 ====> #
#
STARTING at 09 Jun 2019 14:08:06
09 Jun 2019 14:08:06 ====> Configuration information loading from jumonitor.conf
09 Jun 2019 14:08:06 ====> Client cloudflare answered at 09 Jun 2019 14:08:06.
09 Jun 2019 14:08:11 ====> List of dead clients so far : {}
09 Jun 2019 14:08:11 ====> Client cloudflare answered at 09 Jun 2019 14:08:11.
09 Jun 2019 14:08:16 ====> List of dead clients so far : {}
09 Jun 2019 14:08:16 ====> Client cloudflare answered at 09 Jun 2019 14:08:16.
14 Jun 2019 21:48:32 ====> #
#
STARTING at 14 Jun 2019 21:48:32
14 Jun 2019 21:48:32 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 21:48:32 ====> Client cloudflare answered at 14 Jun 2019 21:48:32.
14 Jun 2019 21:56:47 ====> #
#
STARTING at 14 Jun 2019 21:56:47
14 Jun 2019 21:56:47 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 21:56:47 ====> Client cloudflare answered at 14 Jun 2019 21:56:47.
14 Jun 2019 21:56:50 ====> #
#
STARTING at 14 Jun 2019 21:56:50
14 Jun 2019 21:56:50 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 21:56:50 ====> Client cloudflare answered at 14 Jun 2019 21:56:50.
14 Jun 2019 21:56:55 ====> List of dead clients so far : {}
14 Jun 2019 21:56:56 ====> Client cloudflare answered at 14 Jun 2019 21:56:56.
14 Jun 2019 21:58:07 ====> #
#
STARTING at 14 Jun 2019 21:58:07
14 Jun 2019 21:58:07 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 21:58:07 ====> Client cloudflare answered at 14 Jun 2019 21:58:07.
14 Jun 2019 21:58:17 ====> Client bad did not answer or is unknown.
14 Jun 2019 21:58:22 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 21:58:22 ====> Client cloudflare answered at 14 Jun 2019 21:58:22.
14 Jun 2019 21:58:27 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 21:58:27 ====> Client cloudflare answered at 14 Jun 2019 21:58:27.
14 Jun 2019 22:01:21 ====> #
#
STARTING at 14 Jun 2019 22:01:21
14 Jun 2019 22:01:21 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:01:21 ====> Client cloudflare answered at 14 Jun 2019 22:01:21.
14 Jun 2019 22:01:31 ====> Client bad did not answer or is unknown.
14 Jun 2019 22:01:36 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:01:36 ====> Client cloudflare answered at 14 Jun 2019 22:01:36.
14 Jun 2019 22:01:41 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:01:41 ====> Client cloudflare answered at 14 Jun 2019 22:01:41.
14 Jun 2019 22:01:46 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:01:46 ====> Client cloudflare answered at 14 Jun 2019 22:01:46.
14 Jun 2019 22:01:51 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:01:51 ====> Client cloudflare answered at 14 Jun 2019 22:01:51.
14 Jun 2019 22:01:56 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:01:56 ====> Client cloudflare answered at 14 Jun 2019 22:01:56.
14 Jun 2019 22:02:01 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:02:01 ====> Client cloudflare answered at 14 Jun 2019 22:02:01.
14 Jun 2019 22:02:23 ====> #
#
STARTING at 14 Jun 2019 22:02:23
14 Jun 2019 22:02:23 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:02:23 ====> Client cloudflare answered at 14 Jun 2019 22:02:23.
14 Jun 2019 22:02:33 ====> Client bad did not answer or is unknown.
14 Jun 2019 22:02:38 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:02:38 ====> Client cloudflare answered at 14 Jun 2019 22:02:38.
14 Jun 2019 22:02:43 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:02:43 ====> Client cloudflare answered at 14 Jun 2019 22:02:43.
14 Jun 2019 22:02:48 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:02:48 ====> Client cloudflare answered at 14 Jun 2019 22:02:48.
14 Jun 2019 22:02:53 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:02:53 ====> Client cloudflare answered at 14 Jun 2019 22:02:53.
14 Jun 2019 22:05:35 ====> #
#
STARTING at 14 Jun 2019 22:05:35
14 Jun 2019 22:05:35 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:05:35 ====> Client cloudflare answered at 14 Jun 2019 22:05:35.
14 Jun 2019 22:05:45 ====> Client bad did not answer or is unknown.
14 Jun 2019 22:05:50 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:05:50 ====> Client cloudflare answered at 14 Jun 2019 22:05:50.
14 Jun 2019 22:06:45 ====> #
#
STARTING at 14 Jun 2019 22:06:45
14 Jun 2019 22:06:45 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:06:46 ====> Client cloudflare answered at 14 Jun 2019 22:06:46.
14 Jun 2019 22:06:56 ====> Client bad did not answer or is unknown.
14 Jun 2019 22:07:01 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:07:01 ====> Client cloudflare answered at 14 Jun 2019 22:07:01.
14 Jun 2019 22:07:06 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:07:06 ====> Client cloudflare answered at 14 Jun 2019 22:07:06.
14 Jun 2019 22:07:11 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:07:11 ====> Client cloudflare answered at 14 Jun 2019 22:07:11.
14 Jun 2019 22:13:24 ====> #
#
STARTING at 14 Jun 2019 22:13:24
14 Jun 2019 22:13:24 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:13:24 ====> Client cloudflare answered at 14 Jun 2019 22:13:24.
14 Jun 2019 22:13:34 ====> Client bad did not answer or is unknown.
14 Jun 2019 22:13:39 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:13:39 ====> Client cloudflare answered at 14 Jun 2019 22:13:39.
14 Jun 2019 22:13:44 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:13:44 ====> Client cloudflare answered at 14 Jun 2019 22:13:44.
14 Jun 2019 22:13:49 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:13:49 ====> Client cloudflare answered at 14 Jun 2019 22:13:49.
14 Jun 2019 22:13:54 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:13:54 ====> Client cloudflare answered at 14 Jun 2019 22:13:54.
14 Jun 2019 22:14:17 ====> #
#
STARTING at 14 Jun 2019 22:14:17
14 Jun 2019 22:14:17 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:14:17 ====> Client cloudflare answered at 14 Jun 2019 22:14:17.
14 Jun 2019 22:14:27 ====> Client bad did not answer or is unknown.
14 Jun 2019 22:14:32 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:14:32 ====> Client cloudflare answered at 14 Jun 2019 22:14:32.
14 Jun 2019 22:14:37 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:14:37 ====> Client cloudflare answered at 14 Jun 2019 22:14:37.
14 Jun 2019 22:14:42 ====> bad still not answering
14 Jun 2019 22:14:42 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:14:42 ====> Client cloudflare answered at 14 Jun 2019 22:14:42.
14 Jun 2019 22:14:47 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:14:47 ====> Client cloudflare answered at 14 Jun 2019 22:14:47.
14 Jun 2019 22:14:52 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:14:52 ====> Client cloudflare answered at 14 Jun 2019 22:14:52.
14 Jun 2019 22:14:57 ====> bad still not answering
14 Jun 2019 22:14:57 ====> List of dead clients so far : {'bad': '1.2.3.4'}
14 Jun 2019 22:14:57 ====> Client cloudflare answered at 14 Jun 2019 22:14:57.
14 Jun 2019 22:20:17 ====> #
#
STARTING at 14 Jun 2019 22:20:17
14 Jun 2019 22:20:17 ====> Configuration information loading from jumonitor.conf
14 Jun 2019 22:20:17 ====> Client cloudflare answered at 14 Jun 2019 22:20:17.
14 Jun 2019 22:20:27 ====> Client razian did not answer or is unknown.
14 Jun 2019 22:20:32 ====> List of dead clients so far : {'razian': '185.228.229.112'}
14 Jun 2019 22:20:32 ====> Client cloudflare answered at 14 Jun 2019 22:20:32.
14 Jun 2019 22:20:37 ====> List of dead clients so far : {'razian': '185.228.229.112'}
14 Jun 2019 22:20:37 ====> Client cloudflare answered at 14 Jun 2019 22:20:37.
14 Jun 2019 22:20:42 ====> razian still not answering
14 Jun 2019 22:20:42 ====> List of dead clients so far : {'razian': '185.228.229.112'}
14 Jun 2019 22:20:42 ====> Client cloudflare answered at 14 Jun 2019 22:20:42.
14 Jun 2019 22:20:47 ====> List of dead clients so far : {'razian': '185.228.229.112'}
14 Jun 2019 22:20:47 ====> Client cloudflare answered at 14 Jun 2019 22:20:47.
14 Jun 2019 22:20:52 ====> List of dead clients so far : {'razian': '185.228.229.112'}
14 Jun 2019 22:20:52 ====> Client cloudflare answered at 14 Jun 2019 22:20:52.