mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 09:37:02 +00:00
ui: Display server uptime, scan completion time
This commit is contained in:
@@ -40,10 +40,8 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Server uptime for status page.
|
// Server uptime for status page.
|
||||||
startTime := time.Now()
|
startTime := expvar.NewInt("startMillis")
|
||||||
expvar.Publish("uptime", expvar.Func(func() interface{} {
|
startTime.Set(time.Now().UnixNano() / 1000000)
|
||||||
return time.Since(startTime) / time.Second
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Goroutine count for status page.
|
// Goroutine count for status page.
|
||||||
expvar.Publish("goroutines", expvar.Func(func() interface{} {
|
expvar.Publish("goroutines", expvar.Func(func() interface{} {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package storage
|
|||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"expvar"
|
"expvar"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhillyerd/inbucket/pkg/config"
|
"github.com/jhillyerd/inbucket/pkg/config"
|
||||||
@@ -12,8 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
retentionScanCompleted = time.Now()
|
scanCompletedMillis = new(expvar.Int)
|
||||||
retentionScanCompletedMu sync.RWMutex
|
|
||||||
|
|
||||||
// History counters
|
// History counters
|
||||||
expRetentionDeletesTotal = new(expvar.Int)
|
expRetentionDeletesTotal = new(expvar.Int)
|
||||||
@@ -34,7 +32,7 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rm := expvar.NewMap("retention")
|
rm := expvar.NewMap("retention")
|
||||||
rm.Set("SecondsSinceScanCompleted", expvar.Func(secondsSinceRetentionScanCompleted))
|
rm.Set("ScanCompletedMillis", scanCompletedMillis)
|
||||||
rm.Set("DeletesHist", expRetentionDeletesHist)
|
rm.Set("DeletesHist", expRetentionDeletesHist)
|
||||||
rm.Set("DeletesTotal", expRetentionDeletesTotal)
|
rm.Set("DeletesTotal", expRetentionDeletesTotal)
|
||||||
rm.Set("Period", expRetentionPeriod)
|
rm.Set("Period", expRetentionPeriod)
|
||||||
@@ -159,7 +157,7 @@ func (rs *RetentionScanner) DoScan() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Update metrics
|
// Update metrics
|
||||||
setRetentionScanCompleted(time.Now())
|
scanCompletedMillis.Set(time.Now().UnixNano() / 1000000)
|
||||||
expRetainedCurrent.Set(int64(retained))
|
expRetainedCurrent.Set(int64(retained))
|
||||||
expRetainedSize.Set(storeSize)
|
expRetainedSize.Set(storeSize)
|
||||||
return nil
|
return nil
|
||||||
@@ -171,19 +169,3 @@ func (rs *RetentionScanner) Join() {
|
|||||||
<-rs.retentionShutdown
|
<-rs.retentionShutdown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRetentionScanCompleted(t time.Time) {
|
|
||||||
retentionScanCompletedMu.Lock()
|
|
||||||
defer retentionScanCompletedMu.Unlock()
|
|
||||||
retentionScanCompleted = t
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRetentionScanCompleted() time.Time {
|
|
||||||
retentionScanCompletedMu.RLock()
|
|
||||||
defer retentionScanCompletedMu.RUnlock()
|
|
||||||
return retentionScanCompleted
|
|
||||||
}
|
|
||||||
|
|
||||||
func secondsSinceRetentionScanCompleted() interface{} {
|
|
||||||
return time.Since(getRetentionScanCompleted()) / time.Second
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
module Data.Metrics exposing (Metrics, decodeIntList, decoder)
|
module Data.Metrics exposing (Metrics, decodeIntList, decoder)
|
||||||
|
|
||||||
|
import Data.Date exposing (date)
|
||||||
import Json.Decode as Decode exposing (..)
|
import Json.Decode as Decode exposing (..)
|
||||||
import Json.Decode.Pipeline exposing (..)
|
import Json.Decode.Pipeline exposing (..)
|
||||||
|
import Time exposing (Posix)
|
||||||
|
|
||||||
|
|
||||||
type alias Metrics =
|
type alias Metrics =
|
||||||
{ sysMem : Int
|
{ startTime : Posix
|
||||||
|
, sysMem : Int
|
||||||
, heapSize : Int
|
, heapSize : Int
|
||||||
, heapUsed : Int
|
, heapUsed : Int
|
||||||
, heapObjects : Int
|
, heapObjects : Int
|
||||||
@@ -26,12 +29,14 @@ type alias Metrics =
|
|||||||
, retainedCountHist : List Int
|
, retainedCountHist : List Int
|
||||||
, retainedSize : Int
|
, retainedSize : Int
|
||||||
, retainedSizeHist : List Int
|
, retainedSizeHist : List Int
|
||||||
|
, scanCompleted : Posix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
decoder : Decoder Metrics
|
decoder : Decoder Metrics
|
||||||
decoder =
|
decoder =
|
||||||
succeed Metrics
|
succeed Metrics
|
||||||
|
|> requiredAt [ "startMillis" ] date
|
||||||
|> requiredAt [ "memstats", "Sys" ] int
|
|> requiredAt [ "memstats", "Sys" ] int
|
||||||
|> requiredAt [ "memstats", "HeapSys" ] int
|
|> requiredAt [ "memstats", "HeapSys" ] int
|
||||||
|> requiredAt [ "memstats", "HeapAlloc" ] int
|
|> requiredAt [ "memstats", "HeapAlloc" ] int
|
||||||
@@ -53,6 +58,7 @@ decoder =
|
|||||||
|> requiredAt [ "retention", "RetainedHist" ] decodeIntList
|
|> requiredAt [ "retention", "RetainedHist" ] decodeIntList
|
||||||
|> requiredAt [ "retention", "RetainedSize" ] int
|
|> requiredAt [ "retention", "RetainedSize" ] int
|
||||||
|> requiredAt [ "retention", "SizeHist" ] decodeIntList
|
|> requiredAt [ "retention", "SizeHist" ] decodeIntList
|
||||||
|
|> requiredAt [ "retention", "ScanCompletedMillis" ] date
|
||||||
|
|
||||||
|
|
||||||
{-| Decodes Inbuckets hacky comma-separated-int JSON strings.
|
{-| Decodes Inbuckets hacky comma-separated-int JSON strings.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module Page.Status exposing (Model, Msg, init, subscriptions, update, view)
|
|||||||
import Data.Metrics as Metrics exposing (Metrics)
|
import Data.Metrics as Metrics exposing (Metrics)
|
||||||
import Data.ServerConfig as ServerConfig exposing (ServerConfig)
|
import Data.ServerConfig as ServerConfig exposing (ServerConfig)
|
||||||
import Data.Session as Session exposing (Session)
|
import Data.Session as Session exposing (Session)
|
||||||
|
import DateFormat.Relative as Relative
|
||||||
import Filesize
|
import Filesize
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
@@ -10,6 +11,7 @@ import Http exposing (Error)
|
|||||||
import HttpUtil
|
import HttpUtil
|
||||||
import Sparkline as Spark
|
import Sparkline as Spark
|
||||||
import Svg.Attributes as SvgAttrib
|
import Svg.Attributes as SvgAttrib
|
||||||
|
import Task
|
||||||
import Time exposing (Posix)
|
import Time exposing (Posix)
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +20,8 @@ import Time exposing (Posix)
|
|||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ config : Maybe ServerConfig
|
{ now : Posix
|
||||||
|
, config : Maybe ServerConfig
|
||||||
, metrics : Maybe Metrics
|
, metrics : Maybe Metrics
|
||||||
, xCounter : Float
|
, xCounter : Float
|
||||||
, sysMem : Metric
|
, sysMem : Metric
|
||||||
@@ -50,7 +53,8 @@ type alias Metric =
|
|||||||
|
|
||||||
init : ( Model, Cmd Msg, Session.Msg )
|
init : ( Model, Cmd Msg, Session.Msg )
|
||||||
init =
|
init =
|
||||||
( { config = Nothing
|
( { now = Time.millisToPosix 0
|
||||||
|
, config = Nothing
|
||||||
, metrics = Nothing
|
, metrics = Nothing
|
||||||
, xCounter = 60
|
, xCounter = 60
|
||||||
, sysMem = Metric "System Memory" 0 Filesize.format graphZero initDataSet 10
|
, sysMem = Metric "System Memory" 0 Filesize.format graphZero initDataSet 10
|
||||||
@@ -62,13 +66,16 @@ init =
|
|||||||
, smtpConnOpen = Metric "Open Connections" 0 fmtInt graphZero initDataSet 10
|
, smtpConnOpen = Metric "Open Connections" 0 fmtInt graphZero initDataSet 10
|
||||||
, smtpConnTotal = Metric "Total Connections" 0 fmtInt graphChange initDataSet 60
|
, smtpConnTotal = Metric "Total Connections" 0 fmtInt graphChange initDataSet 60
|
||||||
, smtpReceivedTotal = Metric "Messages Received" 0 fmtInt graphChange initDataSet 60
|
, smtpReceivedTotal = Metric "Messages Received" 0 fmtInt graphChange initDataSet 60
|
||||||
, smtpErrorsTotal = Metric "Messages Errors" 0 fmtInt graphChange initDataSet 60
|
, smtpErrorsTotal = Metric "Message Errors" 0 fmtInt graphChange initDataSet 60
|
||||||
, smtpWarnsTotal = Metric "Messages Warns" 0 fmtInt graphChange initDataSet 60
|
, smtpWarnsTotal = Metric "Message Warnings" 0 fmtInt graphChange initDataSet 60
|
||||||
, retentionDeletesTotal = Metric "Retention Deletes" 0 fmtInt graphChange initDataSet 60
|
, retentionDeletesTotal = Metric "Retention Deletes" 0 fmtInt graphChange initDataSet 60
|
||||||
, retainedCount = Metric "Stored Messages" 0 fmtInt graphZero initDataSet 60
|
, retainedCount = Metric "Stored Messages" 0 fmtInt graphZero initDataSet 60
|
||||||
, retainedSize = Metric "Store Size" 0 Filesize.format graphZero initDataSet 60
|
, retainedSize = Metric "Store Size" 0 Filesize.format graphZero initDataSet 60
|
||||||
}
|
}
|
||||||
, Cmd.batch [ loadServerConfig, loadMetrics ]
|
, Cmd.batch
|
||||||
|
[ Task.perform Tick Time.now
|
||||||
|
, loadServerConfig
|
||||||
|
]
|
||||||
, Session.none
|
, Session.none
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -114,7 +121,7 @@ update session msg model =
|
|||||||
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
||||||
|
|
||||||
Tick time ->
|
Tick time ->
|
||||||
( model, loadMetrics, Session.none )
|
( { model | now = time }, loadMetrics, Session.none )
|
||||||
|
|
||||||
|
|
||||||
{-| Update all metrics in Model; increment xCounter.
|
{-| Update all metrics in Model; increment xCounter.
|
||||||
@@ -343,9 +350,12 @@ metricPanels model =
|
|||||||
Nothing ->
|
Nothing ->
|
||||||
[ text "Loading metrics..." ]
|
[ text "Loading metrics..." ]
|
||||||
|
|
||||||
Just _ ->
|
Just metrics ->
|
||||||
[ framePanel "General Metrics"
|
[ framePanel "General Metrics"
|
||||||
[ viewMetric model.sysMem
|
[ textEntry "Uptime" <|
|
||||||
|
"Started "
|
||||||
|
++ Relative.relativeTime model.now metrics.startTime
|
||||||
|
, viewMetric model.sysMem
|
||||||
, viewMetric model.heapSize
|
, viewMetric model.heapSize
|
||||||
, viewMetric model.heapUsed
|
, viewMetric model.heapUsed
|
||||||
, viewMetric model.heapObjects
|
, viewMetric model.heapObjects
|
||||||
@@ -360,13 +370,34 @@ metricPanels model =
|
|||||||
, viewMetric model.smtpWarnsTotal
|
, viewMetric model.smtpWarnsTotal
|
||||||
]
|
]
|
||||||
, framePanel "Storage Metrics"
|
, framePanel "Storage Metrics"
|
||||||
[ viewMetric model.retentionDeletesTotal
|
[ textEntry "Retention Scan" (retentionScan model)
|
||||||
|
, viewMetric model.retentionDeletesTotal
|
||||||
, viewMetric model.retainedCount
|
, viewMetric model.retainedCount
|
||||||
, viewMetric model.retainedSize
|
, viewMetric model.retainedSize
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
retentionScan : Model -> String
|
||||||
|
retentionScan model =
|
||||||
|
case ( model.config, model.metrics ) of
|
||||||
|
( Just config, Just metrics ) ->
|
||||||
|
case config.storageConfig.retentionPeriod of
|
||||||
|
"" ->
|
||||||
|
"Disabled"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
case Time.posixToMillis metrics.scanCompleted of
|
||||||
|
0 ->
|
||||||
|
"Not completed"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
"Completed " ++ Relative.relativeTime model.now metrics.scanCompleted
|
||||||
|
|
||||||
|
( _, _ ) ->
|
||||||
|
"No data"
|
||||||
|
|
||||||
|
|
||||||
textEntry : String -> String -> Html Msg
|
textEntry : String -> String -> Html Msg
|
||||||
textEntry name value =
|
textEntry name value =
|
||||||
div [ class "metric" ]
|
div [ class "metric" ]
|
||||||
|
|||||||
Reference in New Issue
Block a user