Add GET /api/about
that returns useful system info. Closes #1354.
This commit is contained in:
parent
5b404615fc
commit
c581fe2f3a
7 changed files with 105 additions and 0 deletions
|
@ -86,6 +86,7 @@ func initHTTPHandlers(e *echo.Echo, app *App) {
|
|||
g.POST("/api/settings/smtp/test", handleTestSMTPSettings)
|
||||
g.POST("/api/admin/reload", handleReloadApp)
|
||||
g.GET("/api/logs", handleGetLogs)
|
||||
g.GET("/api/about", handleGetAboutInfo)
|
||||
|
||||
g.GET("/api/subscribers/:id", handleGetSubscriber)
|
||||
g.GET("/api/subscribers/:id/export", handleExportSubscriberData)
|
||||
|
|
40
cmd/init.go
40
cmd/init.go
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
@ -697,6 +698,45 @@ func initBounceManager(app *App) *bounce.Manager {
|
|||
return b
|
||||
}
|
||||
|
||||
func initAbout(q *models.Queries, db *sqlx.DB) about {
|
||||
var (
|
||||
mem runtime.MemStats
|
||||
utsname syscall.Utsname
|
||||
)
|
||||
|
||||
// Memory / alloc stats.
|
||||
runtime.ReadMemStats(&mem)
|
||||
|
||||
// OS info.
|
||||
if err := syscall.Uname(&utsname); err != nil {
|
||||
lo.Printf("WARNING: error getting system info: %v", err)
|
||||
}
|
||||
|
||||
// DB dbv.
|
||||
info := types.JSONText(`{}`)
|
||||
if err := db.QueryRow(q.GetDBInfo).Scan(&info); err != nil {
|
||||
lo.Printf("WARNING: error getting database version: %v", err)
|
||||
}
|
||||
|
||||
return about{
|
||||
Version: versionString,
|
||||
Build: buildString,
|
||||
GoArch: runtime.GOARCH,
|
||||
GoVersion: runtime.Version(),
|
||||
Database: info,
|
||||
System: aboutSystem{
|
||||
NumCPU: runtime.NumCPU(),
|
||||
},
|
||||
Host: aboutHost{
|
||||
OS: int8ToStr(utsname.Sysname[:]),
|
||||
OSRelease: int8ToStr(utsname.Release[:]),
|
||||
Machine: int8ToStr(utsname.Machine[:]),
|
||||
Hostname: int8ToStr(utsname.Nodename[:]),
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// initHTTPServer sets up and runs the app's main HTTP server and blocks forever.
|
||||
func initHTTPServer(app *App) *echo.Echo {
|
||||
// Initialize the HTTP server.
|
||||
|
|
|
@ -51,6 +51,7 @@ type App struct {
|
|||
captcha *captcha.Captcha
|
||||
events *events.Events
|
||||
notifTpls *notifTpls
|
||||
about about
|
||||
log *log.Logger
|
||||
bufLog *buflog.BufLog
|
||||
|
||||
|
@ -229,6 +230,9 @@ func main() {
|
|||
app.manager.AddMessenger(m)
|
||||
}
|
||||
|
||||
// Load system information.
|
||||
app.about = initAbout(queries, db)
|
||||
|
||||
// Start the campaign workers. The campaign batches (fetch from DB, push out
|
||||
// messages) get processed at the specified interval.
|
||||
go app.manager.Run()
|
||||
|
|
|
@ -2,14 +2,17 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/jmoiron/sqlx/types"
|
||||
"github.com/knadh/koanf/parsers/json"
|
||||
"github.com/knadh/koanf/providers/rawbytes"
|
||||
"github.com/knadh/koanf/v2"
|
||||
|
@ -18,6 +21,27 @@ import (
|
|||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type aboutHost struct {
|
||||
OS string `json:"os"`
|
||||
OSRelease string `json:"os_release"`
|
||||
Machine string `json:"arch"`
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
type aboutSystem struct {
|
||||
NumCPU int `json:"num_cpu"`
|
||||
AllocMB uint64 `json:"memory_alloc_mb"`
|
||||
OSMB uint64 `json:"memory_from_os_mb"`
|
||||
}
|
||||
type about struct {
|
||||
Version string `json:"version"`
|
||||
Build string `json:"build"`
|
||||
GoVersion string `json:"go_version"`
|
||||
GoArch string `json:"go_arch"`
|
||||
Database types.JSONText `json:"database"`
|
||||
System aboutSystem `json:"system"`
|
||||
Host aboutHost `json:"host"`
|
||||
}
|
||||
|
||||
var (
|
||||
reAlphaNum = regexp.MustCompile(`[^a-z0-9\-]`)
|
||||
)
|
||||
|
@ -266,3 +290,24 @@ func handleTestSMTPSettings(c echo.Context) error {
|
|||
|
||||
return c.JSON(http.StatusOK, okResp{app.bufLog.Lines()})
|
||||
}
|
||||
|
||||
func handleGetAboutInfo(c echo.Context) error {
|
||||
app := c.Get("app").(*App)
|
||||
|
||||
var (
|
||||
mem runtime.MemStats
|
||||
utsname syscall.Utsname
|
||||
)
|
||||
|
||||
runtime.ReadMemStats(&mem)
|
||||
|
||||
if err := syscall.Uname(&utsname); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("error getting system info: %v", err))
|
||||
}
|
||||
|
||||
out := app.about
|
||||
out.System.AllocMB = mem.Alloc / 1024 / 1024
|
||||
out.System.OSMB = mem.Sys / 1024 / 1024
|
||||
|
||||
return c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
|
10
cmd/utils.go
10
cmd/utils.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
@ -99,3 +100,12 @@ func strSliceContains(str string, sl []string) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
func int8ToStr(bs []int8) string {
|
||||
b := make([]byte, len(bs))
|
||||
for i, v := range bs {
|
||||
b[i] = byte(v)
|
||||
}
|
||||
|
||||
return string(bytes.Trim(b, "\x00"))
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ type Queries struct {
|
|||
QueryBounces string `query:"query-bounces"`
|
||||
DeleteBounces *sqlx.Stmt `query:"delete-bounces"`
|
||||
DeleteBouncesBySubscriber *sqlx.Stmt `query:"delete-bounces-by-subscriber"`
|
||||
GetDBInfo string `query:"get-db-info"`
|
||||
}
|
||||
|
||||
// CompileSubscriberQueryTpl takes an arbitrary WHERE expressions
|
||||
|
|
|
@ -1067,3 +1067,7 @@ WITH sub AS (
|
|||
)
|
||||
DELETE FROM bounces WHERE subscriber_id = (SELECT id FROM sub);
|
||||
|
||||
|
||||
-- name: get-db-info
|
||||
SELECT JSON_BUILD_OBJECT('version', (SELECT VERSION()),
|
||||
'size_mb', (SELECT ROUND(pg_database_size('listmonk')/(1024^2)))) AS info;
|
||||
|
|
Loading…
Reference in a new issue