logs tab - database config optimized - log file fixed

pull/44/merge
Hunter Long 2018-07-19 22:26:41 -07:00
parent cec7521074
commit aa8aacc634
16 changed files with 181 additions and 85 deletions

View File

@ -18,7 +18,7 @@ services:
env: env:
global: global:
- VERSION=0.32 - VERSION=0.33
- DB_HOST=localhost - DB_HOST=localhost
- DB_USER=travis - DB_USER=travis
- DB_PASS= - DB_PASS=

View File

@ -1,6 +1,6 @@
FROM alpine:latest FROM alpine:latest
ENV VERSION=v0.32 ENV VERSION=v0.33
RUN apk --no-cache add libstdc++ ca-certificates RUN apk --no-cache add libstdc++ ca-certificates
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \ RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \

2
cli.go
View File

@ -93,7 +93,7 @@ func RunOnce() {
if err != nil { if err != nil {
utils.Log(4, "config.yml file not found") utils.Log(4, "config.yml file not found")
} }
err = core.DbConnection(core.Configs.Connection) err = core.DbConnection(core.Configs.Connection, false)
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
} }

View File

@ -13,8 +13,7 @@ import (
func LoadConfig() (*types.Config, error) { func LoadConfig() (*types.Config, error) {
if os.Getenv("DB_CONN") != "" { if os.Getenv("DB_CONN") != "" {
utils.Log(1, "DB_CONN environment variable was found, sleeping for 30 seconds") utils.Log(1, "DB_CONN environment variable was found, waiting for database...")
time.Sleep(30 * time.Second)
return LoadUsingEnv() return LoadUsingEnv()
} }
Configs = new(types.Config) Configs = new(types.Config)
@ -72,7 +71,7 @@ func LoadUsingEnv() (*types.Config, error) {
Email: "info@localhost.com", Email: "info@localhost.com",
} }
err := DbConnection(dbConfig.DbConn) err := DbConnection(dbConfig.DbConn, true)
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
return nil, err return nil, err

View File

@ -25,7 +25,7 @@ var (
type DbConfig types.DbConfig type DbConfig types.DbConfig
func DbConnection(dbType string) error { func DbConnection(dbType string, retry bool) error {
var err error var err error
if dbType == "sqlite" { if dbType == "sqlite" {
sqliteSettings = sqlite.ConnectionURL{ sqliteSettings = sqlite.ConnectionURL{
@ -39,17 +39,22 @@ func DbConnection(dbType string) error {
if Configs.Port == "" { if Configs.Port == "" {
Configs.Port = "3306" Configs.Port = "3306"
} }
host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
mysqlSettings = mysql.ConnectionURL{ mysqlSettings = mysql.ConnectionURL{
Database: Configs.Database, Database: Configs.Database,
Host: Configs.Host, Host: host,
User: Configs.User, User: Configs.User,
Password: Configs.Password, Password: Configs.Password,
Options: map[string]string{"parseTime": "true", "charset": "utf8"}, Options: map[string]string{"parseTime": "true", "charset": "utf8"},
} }
DbSession, err = mysql.Open(mysqlSettings) DbSession, err = mysql.Open(mysqlSettings)
if err != nil { if err != nil {
return err if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType)
} else {
return err
}
} }
} else { } else {
if Configs.Port == "" { if Configs.Port == "" {
@ -64,7 +69,12 @@ func DbConnection(dbType string) error {
} }
DbSession, err = postgresql.Open(postgresSettings) DbSession, err = postgresql.Open(postgresSettings)
if err != nil { if err != nil {
return err if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType)
} else {
return err
}
} }
} }
err = DbSession.Ping() err = DbSession.Ping()
@ -74,6 +84,11 @@ func DbConnection(dbType string) error {
return err return err
} }
func waitForDb(dbType string) error {
time.Sleep(5 * time.Second)
return DbConnection(dbType, true)
}
func DatabaseMaintence() { func DatabaseMaintence() {
defer DatabaseMaintence() defer DatabaseMaintence()
utils.Log(1, "Checking for database records older than 7 days...") utils.Log(1, "Checking for database records older than 7 days...")
@ -111,7 +126,7 @@ func (c *DbConfig) Save() error {
utils.Log(3, err) utils.Log(3, err)
return err return err
} }
err = DbConnection(Configs.Connection) err = DbConnection(Configs.Connection, false)
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
return err return err

View File

@ -1,8 +1,13 @@
package handlers package handlers
import ( import (
"encoding/json"
"fmt"
"github.com/hunterlong/statup/core" "github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"net/http" "net/http"
"os"
) )
type dashboard struct { type dashboard struct {
@ -55,3 +60,60 @@ func HelpHandler(w http.ResponseWriter, r *http.Request) {
} }
ExecuteResponse(w, r, "help.html", nil) ExecuteResponse(w, r, "help.html", nil)
} }
func LogsHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
file, err := os.Open("./statup.log")
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, 62)
stat, err := os.Stat("./statup.log")
start := stat.Size() - 62
_, err = file.ReadAt(buf, start)
if err == nil {
fmt.Printf("%s\n", buf)
}
ExecuteResponse(w, r, "logs.html", nil)
}
func LogsLineHandler(w http.ResponseWriter, r *http.Request) {
if !IsAuthenticated(r) {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Write([]byte(utils.LastLine))
}
type backups struct {
Core types.Core `json:"core"`
}
func BackupCreateHandler(w http.ResponseWriter, r *http.Request) {
//if !IsAuthenticated(r) {
// http.Redirect(w, r, "/", http.StatusSeeOther)
// return
//}
backup := backups{
Core: *core.CoreApp.ToCore(),
}
out, err := json.Marshal(backup)
if err != nil {
panic(err)
}
fmt.Println(out)
json.NewEncoder(w).Encode(backup)
}

View File

@ -17,6 +17,7 @@ func Router() *mux.Router {
r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET") r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET")
r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST") r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST")
r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET") r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET")
//r.Handle("/backups/create", http.HandlerFunc(BackupCreateHandler)).Methods("GET")
r.Handle("/dashboard", http.HandlerFunc(LoginHandler)).Methods("POST") r.Handle("/dashboard", http.HandlerFunc(LoginHandler)).Methods("POST")
r.Handle("/logout", http.HandlerFunc(LogoutHandler)) r.Handle("/logout", http.HandlerFunc(LogoutHandler))
r.Handle("/services", http.HandlerFunc(ServicesHandler)).Methods("GET") r.Handle("/services", http.HandlerFunc(ServicesHandler)).Methods("GET")
@ -41,6 +42,8 @@ func Router() *mux.Router {
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler)) r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST") r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
r.Handle("/help", http.HandlerFunc(HelpHandler)) r.Handle("/help", http.HandlerFunc(HelpHandler))
r.Handle("/logs", http.HandlerFunc(LogsHandler))
r.Handle("/logs/line", http.HandlerFunc(LogsLineHandler))
r.Handle("/api", http.HandlerFunc(ApiIndexHandler)) r.Handle("/api", http.HandlerFunc(ApiIndexHandler))
r.Handle("/api/renew", http.HandlerFunc(ApiRenewHandler)) r.Handle("/api/renew", http.HandlerFunc(ApiRenewHandler))
r.Handle("/api/checkin/{api}", http.HandlerFunc(ApiCheckinHandler)) r.Handle("/api/checkin/{api}", http.HandlerFunc(ApiCheckinHandler))

View File

@ -95,7 +95,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
err = core.DbConnection(core.Configs.Connection) err = core.DbConnection(core.Configs.Connection, false)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
core.DeleteConfig() core.DeleteConfig()

View File

@ -21,6 +21,7 @@ var (
) )
func init() { func init() {
utils.InitLogs()
LoadDotEnvs() LoadDotEnvs()
core.VERSION = VERSION core.VERSION = VERSION
} }
@ -62,7 +63,7 @@ func LoadDotEnvs() {
func mainProcess() { func mainProcess() {
var err error var err error
err = core.DbConnection(core.Configs.Connection) err = core.DbConnection(core.Configs.Connection, false)
if err != nil { if err != nil {
utils.Log(4, fmt.Sprintf("could not connect to database: %v", err)) utils.Log(4, fmt.Sprintf("could not connect to database: %v", err))
} }

View File

@ -1,29 +0,0 @@
###########################
## Database Information #
###########################
DB_CONNECTION=postgres
DB_HOST=0.0.0.0
DB_PORT=5432
DB_USER=root
DB_PASS=password123
DB_DATABASE=root
###########################
## STATUP PAGE SETTINGS #
###########################
NAME=Demo
DESCRIPTION=This is an awesome page
DOMAIN=https://domain.com
ADMIN_USER=admin
ADMIN_PASS=admin
ADMIN_EMAIL=info@admin.com
USE_CDN=true
###########################
## System Values ##
###########################
IS_DOCKER=true
IS_AWS=true
SASS=/usr/local/bin/sass
BASH_ENV=/bin/bash

View File

@ -213,7 +213,6 @@ func (u *Email) Install() error {
} }
func (u *Email) dialSend(email *EmailOutgoing) error { func (u *Email) dialSend(email *EmailOutgoing) error {
fmt.Println("sending dailsend to emailer")
m := gomail.NewMessage() m := gomail.NewMessage()
m.SetHeader("From", email.From) m.SetHeader("From", email.From)
m.SetHeader("To", email.To) m.SetHeader("To", email.To)

View File

@ -33,6 +33,30 @@ $('select#service_type').on('change', function() {
}); });
$(function() {
var pathname = window.location.pathname;
if (pathname=="/logs") {
var lastline;
setInterval(function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/logs/line');
xhr.onload = function () {
if (xhr.status === 200) {
if (lastline != xhr.responseText) {
var curr = $.trim($("#live_logs").text());
var line = xhr.responseText.replace(/(\r\n|\n|\r)/gm," ");
line = line+"\n";
$("#live_logs").text(line+curr);
lastline = xhr.responseText;
}
}
};
xhr.send();
}, 200);
}
});
$(".confirm-btn").on('click', function() { $(".confirm-btn").on('click', function() {
var r = confirm("Are you sure you want to delete?"); var r = confirm("Are you sure you want to delete?");
if (r == true) { if (r == true) {

View File

@ -18,6 +18,9 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/settings">Settings</a> <a class="nav-link" href="/settings">Settings</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" href="/logs">Logs</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/help">Help</a> <a class="nav-link" href="/help">Help</a>
</li> </li>

View File

@ -35,6 +35,7 @@
<a class="nav-link text-capitalize" id="v-pills-{{underscore .Method}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Method}}" role="tab" aria-controls="v-pills-{{underscore .Method}}" aria-selected="false">{{.Method}}</a> <a class="nav-link text-capitalize" id="v-pills-{{underscore .Method}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Method}}" role="tab" aria-controls="v-pills-{{underscore .Method}}" aria-selected="false">{{.Method}}</a>
{{ end }} {{ end }}
<a class="nav-link" id="v-pills-browse-tab" data-toggle="pill" href="#v-pills-browse" role="tab" aria-controls="v-pills-home" aria-selected="false">Browse Plugins</a> <a class="nav-link" id="v-pills-browse-tab" data-toggle="pill" href="#v-pills-browse" role="tab" aria-controls="v-pills-home" aria-selected="false">Browse Plugins</a>
<a class="nav-link d-none" id="v-pills-backups-tab" data-toggle="pill" href="#v-pills-backups" role="tab" aria-controls="v-pills-backups" aria-selected="false">Backups</a>
{{ range .Plugins }} {{ range .Plugins }}
<a class="nav-link text-capitalize" id="v-pills-{{underscore .Name}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Name}}" role="tab" aria-controls="v-pills-profile" aria-selected="false">{{.Name}}</a> <a class="nav-link text-capitalize" id="v-pills-{{underscore .Name}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Name}}" role="tab" aria-controls="v-pills-profile" aria-selected="false">{{.Name}}</a>
{{end}} {{end}}
@ -180,6 +181,13 @@
{{ end }} {{ end }}
</div> </div>
<div class="tab-pane fade" id="v-pills-backups" role="tabpanel" aria-labelledby="v-pills-backups-tab">
<a href="/backups/create" class="btn btn-primary btn-block">Backup Database</a>
</div>
{{ range .Plugins }} {{ range .Plugins }}
<div class="tab-pane fade" id="v-pills-{{underscore .Name}}" role="tabpanel" aria-labelledby="v-pills-{{underscore .Name}}-tab"> <div class="tab-pane fade" id="v-pills-{{underscore .Name}}" role="tabpanel" aria-labelledby="v-pills-{{underscore .Name}}-tab">

View File

@ -48,10 +48,10 @@ type AllNotifiers interface{}
type Core struct { type Core struct {
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Description string `db:"description" json:"name"` Description string `db:"description" json:"description"`
Config string `db:"config" json:"-"` Config string `db:"config" json:"-"`
ApiKey string `db:"api_key" json:"-"` ApiKey string `db:"api_key" json:"api_key"`
ApiSecret string `db:"api_secret" json:"-"` ApiSecret string `db:"api_secret" json:"api_secret"`
Style string `db:"style" json:"-"` Style string `db:"style" json:"-"`
Footer string `db:"footer" json:"-"` Footer string `db:"footer" json:"-"`
Domain string `db:"domain" json:"domain,omitempty"` Domain string `db:"domain" json:"domain,omitempty"`
@ -68,28 +68,28 @@ type Core struct {
} }
type Service struct { type Service struct {
Id int64 `db:"id,omitempty" json:"id"` Id int64 `db:"id,omitempty" json:"id"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
Domain string `db:"domain" json:"domain"` Domain string `db:"domain" json:"domain"`
Expected string `db:"expected" json:"expected"` Expected string `db:"expected" json:"expected"`
ExpectedStatus int `db:"expected_status" json:"expected_status"` ExpectedStatus int `db:"expected_status" json:"expected_status"`
Interval int `db:"check_interval" json:"check_interval"` Interval int `db:"check_interval" json:"check_interval"`
Type string `db:"check_type" json:"type"` Type string `db:"check_type" json:"type"`
Method string `db:"method" json:"method"` Method string `db:"method" json:"method"`
PostData string `db:"post_data" json:"post_data"` PostData string `db:"post_data" json:"post_data"`
Port int `db:"port" json:"port"` Port int `db:"port" json:"port"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `db:"created_at" json:"created_at"`
Timeout int `db:"timeout" json:"timeout"` Timeout int `db:"timeout" json:"timeout"`
Order int `db:"order_id" json:"order_id"` Order int `db:"order_id" json:"order_id"`
Online bool `json:"online"` Online bool `json:"online"`
Latency float64 `json:"latency"` Latency float64 `json:"latency"`
Online24Hours float32 `json:"24_hours_online"` Online24Hours float32 `json:"24_hours_online"`
AvgResponse string `json:"avg_response"` AvgResponse string `json:"avg_response"`
TotalUptime string `json:"uptime"` TotalUptime string `json:"uptime"`
OrderId int64 `json:"order_id"` OrderId int64 `json:"order_id"`
Failures []*Failure `json:"failures"` Failures []*Failure `json:"failures"`
Checkins []*Checkin `json:"checkins"` Checkins []*Checkin `json:"checkins"`
StopRoutine chan struct{} StopRoutine chan struct{} `json:"-"`
LastResponse string LastResponse string
LastStatusCode int LastStatusCode int
LastOnline time.Time LastOnline time.Time

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/fatih/color" "github.com/fatih/color"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
lg "log" "log"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
@ -14,24 +14,26 @@ import (
var ( var (
logFile *os.File logFile *os.File
logLevel int logLevel int
fmtLogs *lg.Logger fmtLogs *log.Logger
ljLogger *lumberjack.Logger ljLogger *lumberjack.Logger
LastLine string
) )
func init() { func InitLogs() {
var err error var err error
logFile, err = os.OpenFile("./statup.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) logFile, err = os.OpenFile("statup.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil { if err != nil {
lg.Printf("ERROR opening file: %v", err) log.Printf("ERROR opening file: %v", err)
} }
ljLogger = &lumberjack.Logger{ ljLogger = &lumberjack.Logger{
Filename: "./statup.log", Filename: "statup.log",
MaxSize: 16, MaxSize: 16,
MaxBackups: 3, MaxBackups: 3,
MaxAge: 28, MaxAge: 28,
} }
fmtLogs = lg.New(logFile, "", lg.Ldate|lg.Ltime) fmtLogs = log.New(logFile, "", log.Ldate|log.Ltime)
fmtLogs.SetOutput(ljLogger)
log.SetOutput(ljLogger)
logEnv := os.Getenv("LOG") logEnv := os.Getenv("LOG")
@ -60,36 +62,45 @@ func rotate() {
} }
func Panic(err interface{}) { func Panic(err interface{}) {
lg.Printf("PANIC: %v\n", err) log.Printf("PANIC: %v\n", err)
panic(err) panic(err)
} }
func Log(level int, err interface{}) { func Log(level int, err interface{}) {
LastLine = err.(string)
switch level { switch level {
case 5: case 5:
lg.Fatalf("PANIC: %v\n", err) fmt.Printf("PANIC: %v\n", err)
fmtLogs.Fatalf("PANIC: %v\n", err)
case 4: case 4:
lg.Printf("FATAL: %v\n", err) fmt.Printf("FATAL: %v\n", err)
fmtLogs.Printf("FATAL: %v\n", err)
//color.Red("ERROR: %v\n", err) //color.Red("ERROR: %v\n", err)
//os.Exit(2) //os.Exit(2)
case 3: case 3:
lg.Printf("ERROR: %v\n", err) fmt.Printf("ERROR: %v\n", err)
fmtLogs.Printf("ERROR: %v\n", err)
//color.Red("ERROR: %v\n", err) //color.Red("ERROR: %v\n", err)
case 2: case 2:
lg.Printf("WARNING: %v\n", err) fmt.Printf("WARNING: %v\n", err)
fmtLogs.Printf("WARNING: %v\n", err)
//color.Yellow("WARNING: %v\n", err) //color.Yellow("WARNING: %v\n", err)
case 1: case 1:
lg.Printf("INFO: %v\n", err) fmt.Printf("INFO: %v\n", err)
fmtLogs.Printf("INFO: %v\n", err)
//color.Blue("INFO: %v\n", err) //color.Blue("INFO: %v\n", err)
case 0: case 0:
lg.Printf("%v\n", err) fmt.Printf("%v\n", err)
fmtLogs.Printf("%v\n", err)
color.White("%v\n", err) color.White("%v\n", err)
} }
} }
func Http(r *http.Request) { func Http(r *http.Request) {
msg := fmt.Sprintf("%v (%v) | IP: %v", r.RequestURI, r.Method, r.Host) msg := fmt.Sprintf("%v (%v) | IP: %v", r.RequestURI, r.Method, r.Host)
lg.Printf("WEB: %v\n", msg) fmtLogs.Printf("WEB: %v\n", msg)
fmt.Printf("WEB: %v\n", msg)
LastLine = msg
} }
func ReportLog() { func ReportLog() {