mirror of https://github.com/statping/statping
logs tab - database config optimized - log file fixed
parent
cec7521074
commit
aa8aacc634
|
@ -18,7 +18,7 @@ services:
|
|||
|
||||
env:
|
||||
global:
|
||||
- VERSION=0.32
|
||||
- VERSION=0.33
|
||||
- DB_HOST=localhost
|
||||
- DB_USER=travis
|
||||
- DB_PASS=
|
||||
|
|
|
@ -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
2
cli.go
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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()
|
||||
|
|
3
main.go
3
main.go
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
43
utils/log.go
43
utils/log.go
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue