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:
global:
- VERSION=0.32
- VERSION=0.33
- DB_HOST=localhost
- DB_USER=travis
- DB_PASS=

View File

@ -1,6 +1,6 @@
FROM alpine:latest
ENV VERSION=v0.32
ENV VERSION=v0.33
RUN apk --no-cache add libstdc++ ca-certificates
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 {
utils.Log(4, "config.yml file not found")
}
err = core.DbConnection(core.Configs.Connection)
err = core.DbConnection(core.Configs.Connection, false)
if err != nil {
utils.Log(4, err)
}

View File

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

View File

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

View File

@ -1,8 +1,13 @@
package handlers
import (
"encoding/json"
"fmt"
"github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"net/http"
"os"
)
type dashboard struct {
@ -55,3 +60,60 @@ func HelpHandler(w http.ResponseWriter, r *http.Request) {
}
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(ProcessSetupHandler)).Methods("POST")
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("/logout", http.HandlerFunc(LogoutHandler))
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/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
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/renew", http.HandlerFunc(ApiRenewHandler))
r.Handle("/api/checkin/{api}", http.HandlerFunc(ApiCheckinHandler))

View File

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

View File

@ -21,6 +21,7 @@ var (
)
func init() {
utils.InitLogs()
LoadDotEnvs()
core.VERSION = VERSION
}
@ -62,7 +63,7 @@ func LoadDotEnvs() {
func mainProcess() {
var err error
err = core.DbConnection(core.Configs.Connection)
err = core.DbConnection(core.Configs.Connection, false)
if err != nil {
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 {
fmt.Println("sending dailsend to emailer")
m := gomail.NewMessage()
m.SetHeader("From", email.From)
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() {
var r = confirm("Are you sure you want to delete?");
if (r == true) {

View File

@ -18,6 +18,9 @@
<li class="nav-item">
<a class="nav-link" href="/settings">Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/logs">Logs</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/help">Help</a>
</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>
{{ 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 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 }}
<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}}
@ -180,6 +181,13 @@
{{ end }}
</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 }}
<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 {
Name string `db:"name" json:"name"`
Description string `db:"description" json:"name"`
Description string `db:"description" json:"description"`
Config string `db:"config" json:"-"`
ApiKey string `db:"api_key" json:"-"`
ApiSecret string `db:"api_secret" json:"-"`
ApiKey string `db:"api_key" json:"api_key"`
ApiSecret string `db:"api_secret" json:"api_secret"`
Style string `db:"style" json:"-"`
Footer string `db:"footer" json:"-"`
Domain string `db:"domain" json:"domain,omitempty"`
@ -68,28 +68,28 @@ type Core struct {
}
type Service struct {
Id int64 `db:"id,omitempty" json:"id"`
Name string `db:"name" json:"name"`
Domain string `db:"domain" json:"domain"`
Expected string `db:"expected" json:"expected"`
ExpectedStatus int `db:"expected_status" json:"expected_status"`
Interval int `db:"check_interval" json:"check_interval"`
Type string `db:"check_type" json:"type"`
Method string `db:"method" json:"method"`
PostData string `db:"post_data" json:"post_data"`
Port int `db:"port" json:"port"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
Timeout int `db:"timeout" json:"timeout"`
Order int `db:"order_id" json:"order_id"`
Online bool `json:"online"`
Latency float64 `json:"latency"`
Online24Hours float32 `json:"24_hours_online"`
AvgResponse string `json:"avg_response"`
TotalUptime string `json:"uptime"`
OrderId int64 `json:"order_id"`
Failures []*Failure `json:"failures"`
Checkins []*Checkin `json:"checkins"`
StopRoutine chan struct{}
Id int64 `db:"id,omitempty" json:"id"`
Name string `db:"name" json:"name"`
Domain string `db:"domain" json:"domain"`
Expected string `db:"expected" json:"expected"`
ExpectedStatus int `db:"expected_status" json:"expected_status"`
Interval int `db:"check_interval" json:"check_interval"`
Type string `db:"check_type" json:"type"`
Method string `db:"method" json:"method"`
PostData string `db:"post_data" json:"post_data"`
Port int `db:"port" json:"port"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
Timeout int `db:"timeout" json:"timeout"`
Order int `db:"order_id" json:"order_id"`
Online bool `json:"online"`
Latency float64 `json:"latency"`
Online24Hours float32 `json:"24_hours_online"`
AvgResponse string `json:"avg_response"`
TotalUptime string `json:"uptime"`
OrderId int64 `json:"order_id"`
Failures []*Failure `json:"failures"`
Checkins []*Checkin `json:"checkins"`
StopRoutine chan struct{} `json:"-"`
LastResponse string
LastStatusCode int
LastOnline time.Time

View File

@ -4,7 +4,7 @@ import (
"fmt"
"github.com/fatih/color"
"gopkg.in/natefinch/lumberjack.v2"
lg "log"
"log"
"net/http"
"os"
"os/signal"
@ -14,24 +14,26 @@ import (
var (
logFile *os.File
logLevel int
fmtLogs *lg.Logger
fmtLogs *log.Logger
ljLogger *lumberjack.Logger
LastLine string
)
func init() {
func InitLogs() {
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 {
lg.Printf("ERROR opening file: %v", err)
log.Printf("ERROR opening file: %v", err)
}
ljLogger = &lumberjack.Logger{
Filename: "./statup.log",
Filename: "statup.log",
MaxSize: 16,
MaxBackups: 3,
MaxAge: 28,
}
fmtLogs = lg.New(logFile, "", lg.Ldate|lg.Ltime)
fmtLogs.SetOutput(ljLogger)
fmtLogs = log.New(logFile, "", log.Ldate|log.Ltime)
log.SetOutput(ljLogger)
logEnv := os.Getenv("LOG")
@ -60,36 +62,45 @@ func rotate() {
}
func Panic(err interface{}) {
lg.Printf("PANIC: %v\n", err)
log.Printf("PANIC: %v\n", err)
panic(err)
}
func Log(level int, err interface{}) {
LastLine = err.(string)
switch level {
case 5:
lg.Fatalf("PANIC: %v\n", err)
fmt.Printf("PANIC: %v\n", err)
fmtLogs.Fatalf("PANIC: %v\n", err)
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)
//os.Exit(2)
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)
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)
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)
case 0:
lg.Printf("%v\n", err)
fmt.Printf("%v\n", err)
fmtLogs.Printf("%v\n", err)
color.White("%v\n", err)
}
}
func Http(r *http.Request) {
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() {