Skip to content
This repository has been archived by the owner on Jun 12, 2021. It is now read-only.

Commit

Permalink
Merge pull request #14 from MarvinMenzerath/develop
Browse files Browse the repository at this point in the history
v2.0.2
  • Loading branch information
Marvin Menzerath authored and Marvin Menzerath committed Dec 22, 2015
2 parents 4daa779 + 4676375 commit ba491de
Show file tree
Hide file tree
Showing 15 changed files with 254 additions and 93 deletions.
6 changes: 4 additions & 2 deletions README.md
Expand Up @@ -6,6 +6,7 @@ UpAndRunning2 is a lightweight Go application which **monitors all of your websi
* Checks all of your websites regularly
* Use `HEAD` or `GET` requests
* Set an interval of 10 seconds up to 10 minutes
* Set a maximum amount of redirects to follow
* Detects nearly all HTTP-status-codes, timeouts and unknown hosts
* Simple, but powerful [JSON-REST-API](#api)
* Build your own client or use the fully-featured web-interface
Expand Down Expand Up @@ -75,10 +76,12 @@ Notice: Everyone is able to access those APIs.
},
"lastCheckResult": {
"status": "200 - OK",
"responseTime": "150.0001ms",
"time": "2015-01-01T00:00:00.000Z"
},
"lastFailedCheckResult": {
"status": "500 - Internal Server Error",
"responseTime": "unmeasured",
"time": "2014-12-31T20:15:00.000Z"
}
}
Expand Down Expand Up @@ -120,8 +123,7 @@ Notice: You have to login before you are able to use those APIs.
"url": "website.com",
"checkMethod": "HEAD",
"status": "200 - OK",
"time": "2015-01-01T00:00:00.000Z",
"avgAvail": "99.00%"
"time": "2015-01-01T00:00:00.000Z"
}
]
}
Expand Down
37 changes: 20 additions & 17 deletions lib/configuration.go
Expand Up @@ -34,6 +34,7 @@ type databaseConfiguration struct {
type dynamicConfiguration struct {
Title string
Interval int
Redirects int
PushbulletKey string
CheckNow bool
}
Expand Down Expand Up @@ -63,18 +64,17 @@ func ReadConfigurationFromFile(filePath string) {
func ReadConfigurationFromDatabase(db *sql.DB) {
logging.MustGetLogger("logger").Info("Reading Configuration from Database...")

var title string
var interval int
var pushbulletKey string
var (
title string
interval int
redirects int
pushbulletKey string
)

// Title
err := db.QueryRow("SELECT value FROM settings where name = 'title';").Scan(&title)
if err != nil {
stmt, err := db.Prepare("INSERT INTO settings (name, value) VALUES ('title', 'UpAndRunning2');")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to insert 'title'-setting: ", err)
}
_, err = stmt.Exec()
_, err = db.Exec("INSERT INTO settings (name, value) VALUES ('title', 'UpAndRunning2');")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to insert 'title'-setting: ", err)
}
Expand All @@ -84,25 +84,27 @@ func ReadConfigurationFromDatabase(db *sql.DB) {
// Interval
err = db.QueryRow("SELECT value FROM settings where name = 'interval';").Scan(&interval)
if err != nil {
stmt, err := db.Prepare("INSERT INTO settings (name, value) VALUES ('interval', 30);")
_, err = db.Exec("INSERT INTO settings (name, value) VALUES ('interval', 30);")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to insert 'interval'-setting: ", err)
}
_, err = stmt.Exec()
interval = 5
}

// Redirects
err = db.QueryRow("SELECT value FROM settings where name = 'redirects';").Scan(&redirects)
if err != nil {
_, err = db.Exec("INSERT INTO settings (name, value) VALUES ('redirects', 0);")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to insert 'interval'-setting: ", err)
logging.MustGetLogger("logger").Fatal("Unable to insert 'redirects'-setting: ", err)
}
interval = 5
redirects = 0
}

// Pushbullet-Key
err = db.QueryRow("SELECT value FROM settings where name = 'pushbullet_key';").Scan(&pushbulletKey)
if err != nil {
stmt, err := db.Prepare("INSERT INTO settings (name, value) VALUES ('pushbullet_key', '');")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to insert 'pushbullet_key'-setting: ", err)
}
_, err = stmt.Exec()
_, err = db.Exec("INSERT INTO settings (name, value) VALUES ('pushbullet_key', '');")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to insert 'pushbullet_key'-setting: ", err)
}
Expand All @@ -111,6 +113,7 @@ func ReadConfigurationFromDatabase(db *sql.DB) {

config.Dynamic.Title = title
config.Dynamic.Interval = interval
config.Dynamic.Redirects = redirects
config.Dynamic.PushbulletKey = pushbulletKey

config.Dynamic.CheckNow = true
Expand Down
24 changes: 20 additions & 4 deletions lib/database.go
Expand Up @@ -35,15 +35,31 @@ func OpenDatabase(config databaseConfiguration) {
func prepareDatabase() {
logging.MustGetLogger("logger").Debug("Preparing Database...")

_, err := db.Exec("CREATE TABLE IF NOT EXISTS `website` (`id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `enabled` int(1) NOT NULL DEFAULT '1', `visible` int(1) NOT NULL DEFAULT '1', `protocol` varchar(8) NOT NULL DEFAULT 'https', `url` varchar(100) NOT NULL, `checkMethod` VARCHAR(10) NOT NULL DEFAULT 'HEAD', `status` varchar(50) NOT NULL DEFAULT 'unknown', `time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `lastFailStatus` varchar(50) NOT NULL DEFAULT 'unknown', `lastFailTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `ups` int(11) NOT NULL DEFAULT '0', `downs` int(11) NOT NULL DEFAULT '0', `totalChecks` int(11) NOT NULL DEFAULT '0', `avgAvail` float NOT NULL DEFAULT '100', PRIMARY KEY (`id`), UNIQUE KEY `url` (`url`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;")
// v2.0.2
_, err := db.Exec("ALTER TABLE `website` RENAME `websites`;")
if mysqlError, ok := err.(*mysql.MySQLError); ok {
if mysqlError.Number != 1051 && mysqlError.Number != 1146 && mysqlError.Number != 1050 { // Table does not exist: no need to change it
logging.MustGetLogger("logger").Fatal("Unable to rename 'website'-table to 'websites': ", err)
}
}

// v2.0.2
_, err = db.Exec("ALTER TABLE `websites` ADD `responseTime` VARCHAR(50) NOT NULL DEFAULT 'unknown' AFTER `status`;")
if mysqlError, ok := err.(*mysql.MySQLError); ok {
if mysqlError.Number != 1060 { // Column exists: no need to add it
logging.MustGetLogger("logger").Fatal("Unable to add 'responseTime'-column: ", err)
}
}

_, err = db.Exec("CREATE TABLE IF NOT EXISTS `websites` (`id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `enabled` int(1) NOT NULL DEFAULT '1', `visible` int(1) NOT NULL DEFAULT '1', `protocol` varchar(8) NOT NULL DEFAULT 'https', `url` varchar(100) NOT NULL, `checkMethod` VARCHAR(10) NOT NULL DEFAULT 'HEAD', `status` varchar(50) NOT NULL DEFAULT 'unknown', `time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `lastFailStatus` varchar(50) NOT NULL DEFAULT 'unknown', `lastFailTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `ups` int(11) NOT NULL DEFAULT '0', `downs` int(11) NOT NULL DEFAULT '0', `totalChecks` int(11) NOT NULL DEFAULT '0', `avgAvail` float NOT NULL DEFAULT '100', PRIMARY KEY (`id`), UNIQUE KEY `url` (`url`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;")
if err != nil {
logging.MustGetLogger("logger").Fatal("Unable to create table 'website': ", err)
logging.MustGetLogger("logger").Fatal("Unable to create table 'websites': ", err)
}

// v2.0.0
_, err = db.Exec("ALTER TABLE `website` ADD `checkMethod` VARCHAR(10) NOT NULL DEFAULT 'HEAD' AFTER `url`;")
_, err = db.Exec("ALTER TABLE `websites` ADD `checkMethod` VARCHAR(10) NOT NULL DEFAULT 'HEAD' AFTER `url`;")
if mysqlError, ok := err.(*mysql.MySQLError); ok {
if mysqlError.Number != 1060 {
if mysqlError.Number != 1060 { // Column exists: no need to add it
logging.MustGetLogger("logger").Fatal("Unable to add 'checkMethod'-column: ", err)
}
}
Expand Down
34 changes: 18 additions & 16 deletions lib/website.go
Expand Up @@ -21,26 +21,28 @@ type Website struct {
// Runs a check and saves the result inside the database.
func (w *Website) RunCheck(secondTry bool) {
// Request new Status
res, err := goreq.Request{Uri: w.Protocol + "://" + w.Url, Method: w.CheckMethod, UserAgent: "UpAndRunning2 (https://github.com/MarvinMenzerath/UpAndRunning2)", MaxRedirects: 10, Timeout: 10 * time.Second}.Do()
var requestStartTime = time.Now()
res, err := goreq.Request{Uri: w.Protocol + "://" + w.Url, Method: w.CheckMethod, UserAgent: "UpAndRunning2 (https://github.com/MarvinMenzerath/UpAndRunning2)", MaxRedirects: GetConfiguration().Dynamic.Redirects, Timeout: 5 * time.Second}.Do()
var requestDuration = time.Now().Sub(requestStartTime).String()

var newStatus string
var newStatusCode int
if err != nil {
newStatus = "Server not found"
newStatusCode = 0
if secondTry {
newStatus = "Host not found"
newStatusCode = 0

// On Timeout: allow second try
if serr, ok := err.(*goreq.Error); ok {
if serr.Timeout() {
if secondTry {
// On Timeout: allow second try
if serr, ok := err.(*goreq.Error); ok {
if serr.Timeout() {
newStatus = "Timeout"
newStatusCode = 0
} else {
time.Sleep(time.Millisecond * 500)
w.RunCheck(true)
return
}
}
} else {
time.Sleep(time.Millisecond * 1000)
w.RunCheck(true)
return
}
} else {
newStatus = strconv.Itoa(res.StatusCode) + " - " + GetHttpStatus(res.StatusCode)
Expand All @@ -56,7 +58,7 @@ func (w *Website) RunCheck(secondTry bool) {
)

db := GetDatabase()
err = db.QueryRow("SELECT name, status FROM website WHERE id = ?", w.Id).Scan(&name, &status)
err = db.QueryRow("SELECT name, status FROM websites WHERE id = ?", w.Id).Scan(&name, &status)
if err != nil {
logging.MustGetLogger("logger").Error("Unable to get Website's data: ", err)
return
Expand All @@ -72,14 +74,14 @@ func (w *Website) RunCheck(secondTry bool) {
// Save the new Result
if strings.HasPrefix(newStatusCodeString, "2") || strings.HasPrefix(newStatusCodeString, "3") {
// Success
_, err = db.Exec("UPDATE website SET status = ?, time = NOW(), ups = ups + 1, totalChecks = totalChecks + 1 WHERE id = ?;", newStatus, w.Id)
_, err = db.Exec("UPDATE websites SET status = ?, responseTime = ?, time = NOW(), ups = ups + 1, totalChecks = totalChecks + 1 WHERE id = ?;", newStatus, requestDuration, w.Id)
if err != nil {
logging.MustGetLogger("logger").Error("Unable to save the new Website-status: ", err)
return
}
} else {
// Failure
_, err = db.Exec("UPDATE website SET status = ?, time = NOW(), lastFailStatus = ?, lastFailTime = NOW(), downs = downs + 1, totalChecks = totalChecks + 1 WHERE id = ?;", newStatus, newStatus, w.Id)
_, err = db.Exec("UPDATE websites SET status = ?, responseTime = ?, time = NOW(), lastFailStatus = ?, lastFailTime = NOW(), downs = downs + 1, totalChecks = totalChecks + 1 WHERE id = ?;", newStatus, requestDuration, newStatus, w.Id)
if err != nil {
logging.MustGetLogger("logger").Error("Unable to save the new Website-status: ", err)
return
Expand All @@ -94,15 +96,15 @@ func (w *Website) calcAvgAvailability() {
// Query the Database and format the returned value
db := GetDatabase()
var avg float64
err := db.QueryRow("SELECT ((SELECT ups FROM website WHERE id = ?) / (SELECT totalChecks FROM website WHERE id = ?))*100 AS avg", w.Id, w.Id).Scan(&avg)
err := db.QueryRow("SELECT ((SELECT ups FROM websites WHERE id = ?) / (SELECT totalChecks FROM websites WHERE id = ?))*100 AS avg", w.Id, w.Id).Scan(&avg)
if err != nil {
logging.MustGetLogger("logger").Error("Unable to calculate Website-Availability: ", err)
return
}
strconv.FormatFloat(avg, 'f', 2, 64)

// Save the new value
_, err = db.Exec("UPDATE website SET avgAvail = ? WHERE id = ?;", avg, w.Id)
_, err = db.Exec("UPDATE websites SET avgAvail = ? WHERE id = ?;", avg, w.Id)
if err != nil {
logging.MustGetLogger("logger").Error("Unable to save Website-Availability: ", err)
return
Expand Down
5 changes: 3 additions & 2 deletions main.go
Expand Up @@ -11,7 +11,7 @@ import (
"time"
)

const VERSION = "2.0.1"
const VERSION = "2.0.2"

var goVersion = runtime.Version()
var goArch = runtime.GOOS + "_" + runtime.GOARCH
Expand Down Expand Up @@ -75,6 +75,7 @@ func serveRequests() {
router.POST("/api/admin/settings/title", routes.ApiAdminSettingTitle)
router.POST("/api/admin/settings/password", routes.ApiAdminSettingPassword)
router.POST("/api/admin/settings/interval", routes.ApiAdminSettingInterval)
router.POST("/api/admin/settings/redirects", routes.ApiAdminSettingRedirects)
router.POST("/api/admin/settings/pbkey", routes.ApiAdminSettingPushbulletKey)

router.GET("/api/admin/websites", routes.ApiAdminWebsites)
Expand Down Expand Up @@ -129,7 +130,7 @@ func startCheckNowTimer() {
func checkAllSites() {
// Query the Database
db := lib.GetDatabase()
rows, err := db.Query("SELECT id, protocol, url, checkMethod FROM website WHERE enabled = 1;")
rows, err := db.Query("SELECT id, protocol, url, checkMethod FROM websites WHERE enabled = 1;")
if err != nil {
logging.MustGetLogger("logger").Error("Unable to fetch Websites: ", err)
return
Expand Down
8 changes: 6 additions & 2 deletions public/css/style.css
Expand Up @@ -37,7 +37,11 @@ body > .container {
display: none;
}

#form-edit-website {
#row-details {
display: none;
}

#row-edit-website {
display: none;
}

Expand Down Expand Up @@ -92,7 +96,7 @@ body > .container {
margin: 5px 0;
}

@media (min-width: 1280px) {
@media (min-width: 1260px) {
.container {
width: 1250px;
}
Expand Down

0 comments on commit ba491de

Please sign in to comment.