mirror of
https://github.com/datarhei/core.git
synced 2025-10-06 00:17:07 +08:00
Expose resource usage in report history
This commit is contained in:
@@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/datarhei/core/v16/monitor"
|
"github.com/datarhei/core/v16/monitor"
|
||||||
"github.com/datarhei/core/v16/net"
|
"github.com/datarhei/core/v16/net"
|
||||||
"github.com/datarhei/core/v16/prometheus"
|
"github.com/datarhei/core/v16/prometheus"
|
||||||
|
"github.com/datarhei/core/v16/psutil"
|
||||||
"github.com/datarhei/core/v16/restream"
|
"github.com/datarhei/core/v16/restream"
|
||||||
restreamapp "github.com/datarhei/core/v16/restream/app"
|
restreamapp "github.com/datarhei/core/v16/restream/app"
|
||||||
"github.com/datarhei/core/v16/restream/replace"
|
"github.com/datarhei/core/v16/restream/replace"
|
||||||
@@ -116,6 +117,8 @@ type api struct {
|
|||||||
state string
|
state string
|
||||||
|
|
||||||
undoMaxprocs func()
|
undoMaxprocs func()
|
||||||
|
|
||||||
|
process psutil.Process
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrConfigReload is an error returned to indicate that a reload of
|
// ErrConfigReload is an error returned to indicate that a reload of
|
||||||
@@ -1322,6 +1325,9 @@ func (a *api) start() error {
|
|||||||
debug.SetMemoryLimit(math.MaxInt64)
|
debug.SetMemoryLimit(math.MaxInt64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//p, _ := psutil.NewProcess(int32(os.Getpid()), false)
|
||||||
|
//a.process = p
|
||||||
|
|
||||||
// Start the restream processes
|
// Start the restream processes
|
||||||
restream.Start()
|
restream.Start()
|
||||||
|
|
||||||
@@ -1385,6 +1391,11 @@ func (a *api) stop() {
|
|||||||
a.restream = nil
|
a.restream = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.process != nil {
|
||||||
|
a.process.Stop()
|
||||||
|
a.process = nil
|
||||||
|
}
|
||||||
|
|
||||||
// Stop the session tracker
|
// Stop the session tracker
|
||||||
if a.sessions != nil {
|
if a.sessions != nil {
|
||||||
a.sessions.UnregisterAll()
|
a.sessions.UnregisterAll()
|
||||||
|
@@ -570,9 +570,20 @@ func (p *parser) parseAVstreamProgress(line string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) Stop(state string) {
|
func (p *parser) Stop(state string, pusage process.Usage) {
|
||||||
|
fmt.Printf("%+v\n", pusage)
|
||||||
|
usage := Usage{}
|
||||||
|
|
||||||
|
usage.CPU.Average = pusage.CPU.Average
|
||||||
|
usage.CPU.Max = pusage.CPU.Max
|
||||||
|
usage.CPU.Limit = pusage.CPU.Limit
|
||||||
|
|
||||||
|
usage.Memory.Average = pusage.Memory.Average
|
||||||
|
usage.Memory.Max = pusage.Memory.Max
|
||||||
|
usage.Memory.Limit = pusage.Memory.Limit
|
||||||
|
|
||||||
// The process stopped. The right moment to store the current state to the log history
|
// The process stopped. The right moment to store the current state to the log history
|
||||||
p.storeReportHistory(state)
|
p.storeReportHistory(state, usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) Progress() Progress {
|
func (p *parser) Progress() Progress {
|
||||||
@@ -806,6 +817,7 @@ type ReportHistoryEntry struct {
|
|||||||
ExitedAt time.Time
|
ExitedAt time.Time
|
||||||
ExitState string
|
ExitState string
|
||||||
Progress Progress
|
Progress Progress
|
||||||
|
Usage Usage
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReportHistorySearchResult struct {
|
type ReportHistorySearchResult struct {
|
||||||
@@ -850,7 +862,7 @@ func (p *parser) SearchReportHistory(state string, from, to *time.Time) []Report
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) storeReportHistory(state string) {
|
func (p *parser) storeReportHistory(state string, usage Usage) {
|
||||||
if p.logHistory == nil {
|
if p.logHistory == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -868,6 +880,7 @@ func (p *parser) storeReportHistory(state string) {
|
|||||||
ExitedAt: time.Now(),
|
ExitedAt: time.Now(),
|
||||||
ExitState: state,
|
ExitState: state,
|
||||||
Progress: p.Progress(),
|
Progress: p.Progress(),
|
||||||
|
Usage: usage,
|
||||||
}
|
}
|
||||||
|
|
||||||
p.logHistory.Value = h
|
p.logHistory.Value = h
|
||||||
|
@@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/datarhei/core/v16/process"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -165,7 +166,7 @@ func TestParserLogHistory(t *testing.T) {
|
|||||||
history := parser.ReportHistory()
|
history := parser.ReportHistory()
|
||||||
require.Equal(t, 0, len(history))
|
require.Equal(t, 0, len(history))
|
||||||
|
|
||||||
parser.Stop("finished")
|
parser.Stop("finished", process.Usage{})
|
||||||
|
|
||||||
history = parser.ReportHistory()
|
history = parser.ReportHistory()
|
||||||
require.Equal(t, 1, len(history))
|
require.Equal(t, 1, len(history))
|
||||||
@@ -203,7 +204,7 @@ func TestParserLogHistoryLength(t *testing.T) {
|
|||||||
parser.prelude.done = true
|
parser.prelude.done = true
|
||||||
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
||||||
|
|
||||||
parser.Stop("finished")
|
parser.Stop("finished", process.Usage{})
|
||||||
}
|
}
|
||||||
|
|
||||||
history = parser.ReportHistory()
|
history = parser.ReportHistory()
|
||||||
@@ -226,7 +227,7 @@ func TestParserLogMinimalHistoryLength(t *testing.T) {
|
|||||||
parser.prelude.done = true
|
parser.prelude.done = true
|
||||||
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
||||||
|
|
||||||
parser.Stop("finished")
|
parser.Stop("finished", process.Usage{})
|
||||||
}
|
}
|
||||||
|
|
||||||
history = parser.ReportHistory()
|
history = parser.ReportHistory()
|
||||||
@@ -257,7 +258,7 @@ func TestParserLogMinimalHistoryLengthWithoutFullHistory(t *testing.T) {
|
|||||||
parser.prelude.done = true
|
parser.prelude.done = true
|
||||||
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
||||||
|
|
||||||
parser.Stop("finished")
|
parser.Stop("finished", process.Usage{})
|
||||||
}
|
}
|
||||||
|
|
||||||
history = parser.ReportHistory()
|
history = parser.ReportHistory()
|
||||||
@@ -279,7 +280,7 @@ func TestParserLogHistorySearch(t *testing.T) {
|
|||||||
parser.prelude.done = true
|
parser.prelude.done = true
|
||||||
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
||||||
|
|
||||||
parser.Stop("finished")
|
parser.Stop("finished", process.Usage{})
|
||||||
|
|
||||||
parser.ResetStats()
|
parser.ResetStats()
|
||||||
|
|
||||||
@@ -292,7 +293,7 @@ func TestParserLogHistorySearch(t *testing.T) {
|
|||||||
parser.prelude.done = true
|
parser.prelude.done = true
|
||||||
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
||||||
|
|
||||||
parser.Stop("finished")
|
parser.Stop("finished", process.Usage{})
|
||||||
|
|
||||||
parser.ResetStats()
|
parser.ResetStats()
|
||||||
|
|
||||||
@@ -305,7 +306,7 @@ func TestParserLogHistorySearch(t *testing.T) {
|
|||||||
parser.prelude.done = true
|
parser.prelude.done = true
|
||||||
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
parser.Parse("frame= 5968 fps= 25 q=19.4 size=443kB time=00:03:58.44 bitrate=5632kbits/s speed=0.999x skip=9733 drop=3522 dup=87463")
|
||||||
|
|
||||||
parser.Stop("failed")
|
parser.Stop("failed", process.Usage{})
|
||||||
|
|
||||||
res := parser.SearchReportHistory("", nil, nil)
|
res := parser.SearchReportHistory("", nil, nil)
|
||||||
require.Equal(t, 3, len(res))
|
require.Equal(t, 3, len(res))
|
||||||
@@ -905,7 +906,7 @@ func TestParserPatterns(t *testing.T) {
|
|||||||
pp, ok := p.(*parser)
|
pp, ok := p.(*parser)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
pp.storeReportHistory("something")
|
pp.storeReportHistory("something", Usage{})
|
||||||
|
|
||||||
report := p.ReportHistory()
|
report := p.ReportHistory()
|
||||||
require.Equal(t, 1, len(report))
|
require.Equal(t, 1, len(report))
|
||||||
|
@@ -321,3 +321,16 @@ type AVstream struct {
|
|||||||
Duplicating bool
|
Duplicating bool
|
||||||
GOP string
|
GOP string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Usage struct {
|
||||||
|
CPU struct {
|
||||||
|
Average float64
|
||||||
|
Max float64
|
||||||
|
Limit float64
|
||||||
|
}
|
||||||
|
Memory struct {
|
||||||
|
Average float64
|
||||||
|
Max uint64
|
||||||
|
Limit uint64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -111,7 +111,7 @@ func (p *prober) parseDefault() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prober) Stop(state string) {}
|
func (p *prober) Stop(state string, usage process.Usage) {}
|
||||||
|
|
||||||
func (p *prober) Log() []process.Line {
|
func (p *prober) Log() []process.Line {
|
||||||
return p.data
|
return p.data
|
||||||
|
@@ -231,3 +231,18 @@ func (s *ProcessState) Unmarshal(state *app.State) {
|
|||||||
|
|
||||||
s.Progress.Unmarshal(&state.Progress)
|
s.Progress.Unmarshal(&state.Progress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProcessUsageCPU struct {
|
||||||
|
Average json.Number `json:"avg" swaggertype:"number" jsonschema:"type=number"`
|
||||||
|
Max json.Number `json:"max" swaggertype:"number" jsonschema:"type=number"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessUsageMemory struct {
|
||||||
|
Average json.Number `json:"avg" swaggertype:"number" jsonschema:"type=number"`
|
||||||
|
Max uint64 `json:"max" format:"uint64"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessUsage struct {
|
||||||
|
CPU ProcessUsageCPU `json:"cpu_usage"`
|
||||||
|
Memory ProcessUsageMemory `json:"memory_bytes"`
|
||||||
|
}
|
||||||
|
@@ -8,13 +8,14 @@ import (
|
|||||||
|
|
||||||
// ProcessReportEntry represents the logs of a run of a restream process
|
// ProcessReportEntry represents the logs of a run of a restream process
|
||||||
type ProcessReportEntry struct {
|
type ProcessReportEntry struct {
|
||||||
CreatedAt int64 `json:"created_at" format:"int64"`
|
CreatedAt int64 `json:"created_at" format:"int64"`
|
||||||
Prelude []string `json:"prelude,omitempty"`
|
Prelude []string `json:"prelude,omitempty"`
|
||||||
Log [][2]string `json:"log,omitempty"`
|
Log [][2]string `json:"log,omitempty"`
|
||||||
Matches []string `json:"matches,omitempty"`
|
Matches []string `json:"matches,omitempty"`
|
||||||
ExitedAt int64 `json:"exited_at,omitempty" format:"int64"`
|
ExitedAt int64 `json:"exited_at,omitempty" format:"int64"`
|
||||||
ExitState string `json:"exit_state,omitempty"`
|
ExitState string `json:"exit_state,omitempty"`
|
||||||
Progress *Progress `json:"progress,omitempty"`
|
Progress *Progress `json:"progress,omitempty"`
|
||||||
|
Resources *ProcessUsage `json:"resources,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessReportHistoryEntry struct {
|
type ProcessReportHistoryEntry struct {
|
||||||
@@ -52,6 +53,16 @@ func (report *ProcessReport) Unmarshal(l *app.Log) {
|
|||||||
Matches: h.Matches,
|
Matches: h.Matches,
|
||||||
ExitedAt: h.ExitedAt.Unix(),
|
ExitedAt: h.ExitedAt.Unix(),
|
||||||
ExitState: h.ExitState,
|
ExitState: h.ExitState,
|
||||||
|
Resources: &ProcessUsage{
|
||||||
|
CPU: ProcessUsageCPU{
|
||||||
|
Average: toNumber(h.Usage.CPU.Average),
|
||||||
|
Max: toNumber(h.Usage.CPU.Max),
|
||||||
|
},
|
||||||
|
Memory: ProcessUsageMemory{
|
||||||
|
Average: toNumber(h.Usage.Memory.Average),
|
||||||
|
Max: h.Usage.Memory.Max,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
he.Progress = &Progress{}
|
he.Progress = &Progress{}
|
||||||
|
@@ -9,6 +9,21 @@ import (
|
|||||||
"github.com/datarhei/core/v16/psutil"
|
"github.com/datarhei/core/v16/psutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Usage struct {
|
||||||
|
CPU struct {
|
||||||
|
Current float64 // percent 0-100
|
||||||
|
Average float64 // percent 0-100
|
||||||
|
Max float64 // percent 0-100
|
||||||
|
Limit float64 // percent 0-100
|
||||||
|
}
|
||||||
|
Memory struct {
|
||||||
|
Current uint64 // bytes
|
||||||
|
Average float64 // bytes
|
||||||
|
Max uint64 // bytes
|
||||||
|
Limit uint64 // bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type LimitFunc func(cpu float64, memory uint64)
|
type LimitFunc func(cpu float64, memory uint64)
|
||||||
|
|
||||||
type LimiterConfig struct {
|
type LimiterConfig struct {
|
||||||
@@ -28,8 +43,12 @@ type Limiter interface {
|
|||||||
// Current returns the current CPU and memory values
|
// Current returns the current CPU and memory values
|
||||||
Current() (cpu float64, memory uint64)
|
Current() (cpu float64, memory uint64)
|
||||||
|
|
||||||
// Limits returns the defined CPU and memory limits. Values < 0 means no limit
|
// Limits returns the defined CPU and memory limits. Values <= 0 means no limit
|
||||||
Limits() (cpu float64, memory uint64)
|
Limits() (cpu float64, memory uint64)
|
||||||
|
|
||||||
|
// Usage returns the current state of the limiter, such as current, average, max, and
|
||||||
|
// limit values for CPU and memory.
|
||||||
|
Usage() Usage
|
||||||
}
|
}
|
||||||
|
|
||||||
type limiter struct {
|
type limiter struct {
|
||||||
@@ -38,15 +57,23 @@ type limiter struct {
|
|||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
onLimit LimitFunc
|
onLimit LimitFunc
|
||||||
|
|
||||||
cpu float64
|
cpu float64
|
||||||
cpuCurrent float64
|
cpuCurrent float64
|
||||||
cpuLast float64
|
cpuMax float64
|
||||||
cpuLimitSince time.Time
|
cpuAvg float64
|
||||||
|
cpuAvgCounter uint64
|
||||||
|
cpuLast float64
|
||||||
|
cpuLimitSince time.Time
|
||||||
|
|
||||||
memory uint64
|
memory uint64
|
||||||
memoryCurrent uint64
|
memoryCurrent uint64
|
||||||
|
memoryMax uint64
|
||||||
|
memoryAvg float64
|
||||||
|
memoryAvgCounter uint64
|
||||||
memoryLast uint64
|
memoryLast uint64
|
||||||
memoryLimitSince time.Time
|
memoryLimitSince time.Time
|
||||||
waitFor time.Duration
|
|
||||||
|
waitFor time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLimiter returns a new Limiter
|
// NewLimiter returns a new Limiter
|
||||||
@@ -68,8 +95,15 @@ func NewLimiter(config LimiterConfig) Limiter {
|
|||||||
func (l *limiter) reset() {
|
func (l *limiter) reset() {
|
||||||
l.cpuCurrent = 0
|
l.cpuCurrent = 0
|
||||||
l.cpuLast = 0
|
l.cpuLast = 0
|
||||||
|
l.cpuAvg = 0
|
||||||
|
l.cpuAvgCounter = 0
|
||||||
|
l.cpuMax = 0
|
||||||
|
|
||||||
l.memoryCurrent = 0
|
l.memoryCurrent = 0
|
||||||
l.memoryLast = 0
|
l.memoryLast = 0
|
||||||
|
l.memoryAvg = 0
|
||||||
|
l.memoryAvgCounter = 0
|
||||||
|
l.memoryMax = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *limiter) Start(process psutil.Process) error {
|
func (l *limiter) Start(process psutil.Process) error {
|
||||||
@@ -87,7 +121,7 @@ func (l *limiter) Start(process psutil.Process) error {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
l.cancel = cancel
|
l.cancel = cancel
|
||||||
|
|
||||||
go l.ticker(ctx)
|
go l.ticker(ctx, 500*time.Millisecond)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -108,8 +142,8 @@ func (l *limiter) Stop() {
|
|||||||
l.reset()
|
l.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *limiter) ticker(ctx context.Context) {
|
func (l *limiter) ticker(ctx context.Context, interval time.Duration) {
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -132,10 +166,26 @@ func (l *limiter) collect(t time.Time) {
|
|||||||
|
|
||||||
if mstat, err := l.proc.VirtualMemory(); err == nil {
|
if mstat, err := l.proc.VirtualMemory(); err == nil {
|
||||||
l.memoryLast, l.memoryCurrent = l.memoryCurrent, mstat
|
l.memoryLast, l.memoryCurrent = l.memoryCurrent, mstat
|
||||||
|
|
||||||
|
if l.memoryCurrent > l.memoryMax {
|
||||||
|
l.memoryMax = l.memoryCurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
l.memoryAvgCounter++
|
||||||
|
|
||||||
|
l.memoryAvg = ((l.memoryAvg * float64(l.memoryAvgCounter-1)) + float64(l.memoryCurrent)) / float64(l.memoryAvgCounter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cpustat, err := l.proc.CPUPercent(); err == nil {
|
if cpustat, err := l.proc.CPUPercent(); err == nil {
|
||||||
l.cpuLast, l.cpuCurrent = l.cpuCurrent, cpustat.System+cpustat.User+cpustat.Other
|
l.cpuLast, l.cpuCurrent = l.cpuCurrent, cpustat.System+cpustat.User+cpustat.Other
|
||||||
|
|
||||||
|
if l.cpuCurrent > l.cpuMax {
|
||||||
|
l.cpuMax = l.cpuCurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
l.cpuAvgCounter++
|
||||||
|
|
||||||
|
l.cpuAvg = ((l.cpuAvg * float64(l.cpuAvgCounter-1)) + l.cpuCurrent) / float64(l.cpuAvgCounter)
|
||||||
}
|
}
|
||||||
|
|
||||||
isLimitExceeded := false
|
isLimitExceeded := false
|
||||||
@@ -185,6 +235,25 @@ func (l *limiter) Current() (cpu float64, memory uint64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *limiter) Usage() Usage {
|
||||||
|
l.lock.Lock()
|
||||||
|
defer l.lock.Unlock()
|
||||||
|
|
||||||
|
usage := Usage{}
|
||||||
|
|
||||||
|
usage.CPU.Limit = l.cpu
|
||||||
|
usage.CPU.Current = l.cpuCurrent
|
||||||
|
usage.CPU.Average = l.cpuAvg
|
||||||
|
usage.CPU.Max = l.cpuMax
|
||||||
|
|
||||||
|
usage.Memory.Limit = l.memory
|
||||||
|
usage.Memory.Current = l.memoryCurrent
|
||||||
|
usage.Memory.Average = l.memoryAvg
|
||||||
|
usage.Memory.Max = l.memoryMax
|
||||||
|
|
||||||
|
return usage
|
||||||
|
}
|
||||||
|
|
||||||
func (l *limiter) Limits() (cpu float64, memory uint64) {
|
func (l *limiter) Limits() (cpu float64, memory uint64) {
|
||||||
return l.cpu, l.memory
|
return l.cpu, l.memory
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ type Parser interface {
|
|||||||
|
|
||||||
// Stop tells the parser that the process stopped and provides
|
// Stop tells the parser that the process stopped and provides
|
||||||
// its exit state.
|
// its exit state.
|
||||||
Stop(state string)
|
Stop(state string, usage Usage)
|
||||||
|
|
||||||
// Reset resets any collected statistics or temporary data.
|
// Reset resets any collected statistics or temporary data.
|
||||||
// This is called before the process starts and after the
|
// This is called before the process starts and after the
|
||||||
@@ -48,7 +48,7 @@ func NewNullParser() Parser {
|
|||||||
var _ Parser = &nullParser{}
|
var _ Parser = &nullParser{}
|
||||||
|
|
||||||
func (p *nullParser) Parse(string) uint64 { return 1 }
|
func (p *nullParser) Parse(string) uint64 { return 1 }
|
||||||
func (p *nullParser) Stop(string) {}
|
func (p *nullParser) Stop(string, Usage) {}
|
||||||
func (p *nullParser) ResetStats() {}
|
func (p *nullParser) ResetStats() {}
|
||||||
func (p *nullParser) ResetLog() {}
|
func (p *nullParser) ResetLog() {}
|
||||||
func (p *nullParser) Log() []Line { return []Line{} }
|
func (p *nullParser) Log() []Line { return []Line{} }
|
||||||
|
@@ -72,9 +72,19 @@ type Status struct {
|
|||||||
Reconnect time.Duration // Reconnect is the time until the next reconnect, negative if no reconnect is scheduled.
|
Reconnect time.Duration // Reconnect is the time until the next reconnect, negative if no reconnect is scheduled.
|
||||||
Duration time.Duration // Duration is the time since the last change of the state
|
Duration time.Duration // Duration is the time since the last change of the state
|
||||||
Time time.Time // Time is the time of the last change of the state
|
Time time.Time // Time is the time of the last change of the state
|
||||||
CPU float64 // Used CPU in percent
|
|
||||||
Memory uint64 // Used memory in bytes
|
|
||||||
CommandArgs []string // Currently running command arguments
|
CommandArgs []string // Currently running command arguments
|
||||||
|
CPU struct {
|
||||||
|
Current float64
|
||||||
|
Average float64
|
||||||
|
Max float64
|
||||||
|
Limit float64
|
||||||
|
} // Used CPU in percent
|
||||||
|
Memory struct {
|
||||||
|
Current uint64
|
||||||
|
Average float64
|
||||||
|
Max uint64
|
||||||
|
Limit uint64
|
||||||
|
} // Used memory in bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// States
|
// States
|
||||||
@@ -275,8 +285,9 @@ func (p *process) initState(state stateType) {
|
|||||||
|
|
||||||
// setState sets a new state. It also checks if the transition
|
// setState sets a new state. It also checks if the transition
|
||||||
// of the current state to the new state is allowed. If not,
|
// of the current state to the new state is allowed. If not,
|
||||||
// the current state will not be changed.
|
// the current state will not be changed. It returns the previous
|
||||||
func (p *process) setState(state stateType) error {
|
// state or an error
|
||||||
|
func (p *process) setState(state stateType) (stateType, error) {
|
||||||
p.state.lock.Lock()
|
p.state.lock.Lock()
|
||||||
defer p.state.lock.Unlock()
|
defer p.state.lock.Unlock()
|
||||||
|
|
||||||
@@ -353,11 +364,11 @@ func (p *process) setState(state stateType) error {
|
|||||||
failed = true
|
failed = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("current state is unhandled: %s", p.state.state)
|
return "", fmt.Errorf("current state is unhandled: %s", p.state.state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if failed {
|
if failed {
|
||||||
return fmt.Errorf("can't change from state %s to %s", p.state.state, state)
|
return "", fmt.Errorf("can't change from state %s to %s", p.state.state, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.state.time = time.Now()
|
p.state.time = time.Now()
|
||||||
@@ -368,7 +379,7 @@ func (p *process) setState(state stateType) error {
|
|||||||
}
|
}
|
||||||
p.callbacks.lock.Unlock()
|
p.callbacks.lock.Unlock()
|
||||||
|
|
||||||
return nil
|
return prevState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) getState() stateType {
|
func (p *process) getState() stateType {
|
||||||
@@ -394,7 +405,7 @@ func (p *process) getStateString() string {
|
|||||||
|
|
||||||
// Status returns the current status of the process
|
// Status returns the current status of the process
|
||||||
func (p *process) Status() Status {
|
func (p *process) Status() Status {
|
||||||
cpu, memory := p.limits.Current()
|
usage := p.limits.Usage()
|
||||||
|
|
||||||
p.state.lock.Lock()
|
p.state.lock.Lock()
|
||||||
stateTime := p.state.time
|
stateTime := p.state.time
|
||||||
@@ -413,8 +424,8 @@ func (p *process) Status() Status {
|
|||||||
Reconnect: time.Duration(-1),
|
Reconnect: time.Duration(-1),
|
||||||
Duration: time.Since(stateTime),
|
Duration: time.Since(stateTime),
|
||||||
Time: stateTime,
|
Time: stateTime,
|
||||||
CPU: cpu,
|
CPU: usage.CPU,
|
||||||
Memory: memory,
|
Memory: usage.Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.CommandArgs = make([]string, len(p.args))
|
s.CommandArgs = make([]string, len(p.args))
|
||||||
@@ -489,8 +500,12 @@ func (p *process) start() error {
|
|||||||
// Stop any restart timer in order to start the process immediately
|
// Stop any restart timer in order to start the process immediately
|
||||||
p.unreconnect()
|
p.unreconnect()
|
||||||
|
|
||||||
|
fmt.Printf("q\n")
|
||||||
|
|
||||||
p.setState(stateStarting)
|
p.setState(stateStarting)
|
||||||
|
|
||||||
|
fmt.Printf("w\n")
|
||||||
|
|
||||||
args := p.args
|
args := p.args
|
||||||
|
|
||||||
p.callbacks.lock.Lock()
|
p.callbacks.lock.Lock()
|
||||||
@@ -502,6 +517,8 @@ func (p *process) start() error {
|
|||||||
}
|
}
|
||||||
p.callbacks.lock.Unlock()
|
p.callbacks.lock.Unlock()
|
||||||
|
|
||||||
|
fmt.Printf("e\n")
|
||||||
|
|
||||||
// Start the stop timeout if enabled
|
// Start the stop timeout if enabled
|
||||||
if p.timeout > time.Duration(0) {
|
if p.timeout > time.Duration(0) {
|
||||||
p.stopTimerLock.Lock()
|
p.stopTimerLock.Lock()
|
||||||
@@ -519,6 +536,8 @@ func (p *process) start() error {
|
|||||||
p.stopTimerLock.Unlock()
|
p.stopTimerLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("r\n")
|
||||||
|
|
||||||
p.cmd = exec.Command(p.binary, args...)
|
p.cmd = exec.Command(p.binary, args...)
|
||||||
p.cmd.Env = []string{}
|
p.cmd.Env = []string{}
|
||||||
|
|
||||||
@@ -545,7 +564,8 @@ func (p *process) start() error {
|
|||||||
|
|
||||||
p.pid = int32(p.cmd.Process.Pid)
|
p.pid = int32(p.cmd.Process.Pid)
|
||||||
|
|
||||||
if proc, err := psutil.NewProcess(p.pid); err == nil {
|
if proc, err := psutil.NewProcess(p.pid, false); err == nil {
|
||||||
|
fmt.Printf("starting limiter\n")
|
||||||
p.limits.Start(proc)
|
p.limits.Start(proc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,9 +671,6 @@ func (p *process) stop(wait bool) error {
|
|||||||
p.callbacks.onExit = func(string) {
|
p.callbacks.onExit = func(string) {
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
|
||||||
p.callbacks.lock.Lock()
|
|
||||||
defer p.callbacks.lock.Unlock()
|
|
||||||
|
|
||||||
p.callbacks.onExit = nil
|
p.callbacks.onExit = nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -662,9 +679,6 @@ func (p *process) stop(wait bool) error {
|
|||||||
cb(state)
|
cb(state)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
|
||||||
p.callbacks.lock.Lock()
|
|
||||||
defer p.callbacks.lock.Unlock()
|
|
||||||
|
|
||||||
p.callbacks.onExit = cb
|
p.callbacks.onExit = cb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -878,6 +892,7 @@ func (p *process) waiter() {
|
|||||||
p.logger.Info().Log("Stopped")
|
p.logger.Info().Log("Stopped")
|
||||||
p.debuglogger.WithField("log", p.parser.Log()).Debug().Log("Stopped")
|
p.debuglogger.WithField("log", p.parser.Log()).Debug().Log("Stopped")
|
||||||
|
|
||||||
|
pusage := p.limits.Usage()
|
||||||
p.limits.Stop()
|
p.limits.Stop()
|
||||||
|
|
||||||
// Stop the stop timer
|
// Stop the stop timer
|
||||||
@@ -908,7 +923,7 @@ func (p *process) waiter() {
|
|||||||
p.stale.lock.Unlock()
|
p.stale.lock.Unlock()
|
||||||
|
|
||||||
// Send exit state to the parser
|
// Send exit state to the parser
|
||||||
p.parser.Stop(state.String())
|
p.parser.Stop(state.String(), pusage)
|
||||||
|
|
||||||
// Reset the parser stats
|
// Reset the parser stats
|
||||||
p.parser.ResetStats()
|
p.parser.ResetStats()
|
||||||
|
@@ -2,6 +2,8 @@ package psutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -9,8 +11,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Process interface {
|
type Process interface {
|
||||||
|
// CPUPercent returns the current CPU load for this process only. The values
|
||||||
|
// are normed to the range of 0 to 100.
|
||||||
CPUPercent() (*CPUInfoStat, error)
|
CPUPercent() (*CPUInfoStat, error)
|
||||||
|
|
||||||
|
// VirtualMemory returns the current memory usage in bytes of this process only.
|
||||||
VirtualMemory() (uint64, error)
|
VirtualMemory() (uint64, error)
|
||||||
|
|
||||||
|
// Stop will stop collecting CPU and memory data for this process.
|
||||||
Stop()
|
Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,14 +36,17 @@ type process struct {
|
|||||||
statCurrentTime time.Time
|
statCurrentTime time.Time
|
||||||
statPrevious cpuTimesStat
|
statPrevious cpuTimesStat
|
||||||
statPreviousTime time.Time
|
statPreviousTime time.Time
|
||||||
|
|
||||||
|
imposeLimit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *util) Process(pid int32) (Process, error) {
|
func (u *util) Process(pid int32, limit bool) (Process, error) {
|
||||||
p := &process{
|
p := &process{
|
||||||
pid: pid,
|
pid: pid,
|
||||||
hasCgroup: u.hasCgroup,
|
hasCgroup: u.hasCgroup,
|
||||||
cpuLimit: u.cpuLimit,
|
cpuLimit: u.cpuLimit,
|
||||||
ncpu: u.ncpu,
|
ncpu: u.ncpu,
|
||||||
|
imposeLimit: limit,
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := psprocess.NewProcess(pid)
|
proc, err := psprocess.NewProcess(pid)
|
||||||
@@ -47,19 +58,23 @@ func (u *util) Process(pid int32) (Process, error) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
p.stopTicker = cancel
|
p.stopTicker = cancel
|
||||||
go p.tick(ctx)
|
go p.tick(ctx, 1000*time.Millisecond)
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProcess(pid int32) (Process, error) {
|
func NewProcess(pid int32, limit bool) (Process, error) {
|
||||||
return DefaultUtil.Process(pid)
|
return DefaultUtil.Process(pid, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process) tick(ctx context.Context) {
|
func (p *process) tick(ctx context.Context, interval time.Duration) {
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
if p.imposeLimit {
|
||||||
|
go p.limit(ctx, interval)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -71,6 +86,65 @@ func (p *process) tick(ctx context.Context) {
|
|||||||
p.statPrevious, p.statCurrent = p.statCurrent, stat
|
p.statPrevious, p.statCurrent = p.statCurrent, stat
|
||||||
p.statPreviousTime, p.statCurrentTime = p.statCurrentTime, t
|
p.statPreviousTime, p.statCurrentTime = p.statCurrentTime, t
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
|
|
||||||
|
pct, _ := p.CPUPercent()
|
||||||
|
pcpu := (pct.System + pct.User + pct.Other) / 100
|
||||||
|
|
||||||
|
fmt.Printf("%d\t%0.2f%%\n", p.pid, pcpu*100*p.ncpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *process) limit(ctx context.Context, interval time.Duration) {
|
||||||
|
var limit float64 = 50.0 / 100.0 / p.ncpu
|
||||||
|
var workingrate float64 = -1
|
||||||
|
|
||||||
|
counter := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
pct, _ := p.CPUPercent()
|
||||||
|
/*
|
||||||
|
pct.System *= p.ncpu
|
||||||
|
pct.Idle *= p.ncpu
|
||||||
|
pct.User *= p.ncpu
|
||||||
|
pct.Other *= p.ncpu
|
||||||
|
*/
|
||||||
|
|
||||||
|
pcpu := (pct.System + pct.User + pct.Other) / 100
|
||||||
|
|
||||||
|
if workingrate < 0 {
|
||||||
|
workingrate = limit
|
||||||
|
} else {
|
||||||
|
workingrate = math.Min(workingrate/pcpu*limit, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
worktime := float64(interval.Nanoseconds()) * workingrate
|
||||||
|
sleeptime := float64(interval.Nanoseconds()) - worktime
|
||||||
|
/*
|
||||||
|
if counter%20 == 0 {
|
||||||
|
fmt.Printf("\nPID\t%%CPU\twork quantum\tsleep quantum\tactive rate\n")
|
||||||
|
counter = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%d\t%0.2f%%\t%.2f us\t%.2f us\t%0.2f%%\n", p.pid, pcpu*100*p.ncpu, worktime/1000, sleeptime/1000, workingrate*100)
|
||||||
|
*/
|
||||||
|
if p.imposeLimit {
|
||||||
|
p.proc.Resume()
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(worktime) * time.Nanosecond)
|
||||||
|
|
||||||
|
if sleeptime > 0 {
|
||||||
|
if p.imposeLimit {
|
||||||
|
p.proc.Suspend()
|
||||||
|
}
|
||||||
|
time.Sleep(time.Duration(sleeptime) * time.Nanosecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,6 +178,9 @@ func (p *process) cpuTimes() (*cpuTimesStat, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.other = s.total - s.system - s.user
|
s.other = s.total - s.system - s.user
|
||||||
|
if s.other < 0.0001 {
|
||||||
|
s.other = 0
|
||||||
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
@@ -46,35 +46,42 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MemoryInfoStat struct {
|
type MemoryInfoStat struct {
|
||||||
Total uint64
|
Total uint64 // bytes
|
||||||
Available uint64
|
Available uint64 // bytes
|
||||||
Used uint64
|
Used uint64 // bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
type CPUInfoStat struct {
|
type CPUInfoStat struct {
|
||||||
System float64
|
System float64 // percent 0-100
|
||||||
User float64
|
User float64 // percent 0-100
|
||||||
Idle float64
|
Idle float64 // percent 0-100
|
||||||
Other float64
|
Other float64 // percent 0-100
|
||||||
}
|
}
|
||||||
|
|
||||||
type cpuTimesStat struct {
|
type cpuTimesStat struct {
|
||||||
total float64
|
total float64 // seconds
|
||||||
system float64
|
system float64 // seconds
|
||||||
user float64
|
user float64 // seconds
|
||||||
idle float64
|
idle float64 // seconds
|
||||||
other float64
|
other float64 // seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
type Util interface {
|
type Util interface {
|
||||||
Start()
|
Start()
|
||||||
Stop()
|
Stop()
|
||||||
|
|
||||||
|
// CPUCounts returns the number of cores, either logical or physical.
|
||||||
CPUCounts(logical bool) (float64, error)
|
CPUCounts(logical bool) (float64, error)
|
||||||
|
|
||||||
|
// CPUPercent returns the current CPU load in percent. The values range
|
||||||
|
// from 0 to 100, independently of the number of logical cores.
|
||||||
CPUPercent() (*CPUInfoStat, error)
|
CPUPercent() (*CPUInfoStat, error)
|
||||||
DiskUsage(path string) (*disk.UsageStat, error)
|
DiskUsage(path string) (*disk.UsageStat, error)
|
||||||
VirtualMemory() (*MemoryInfoStat, error)
|
VirtualMemory() (*MemoryInfoStat, error)
|
||||||
NetIOCounters(pernic bool) ([]net.IOCountersStat, error)
|
NetIOCounters(pernic bool) ([]net.IOCountersStat, error)
|
||||||
Process(pid int32) (Process, error)
|
|
||||||
|
// Process returns a process observer for a process with the given pid.
|
||||||
|
Process(pid int32, limit bool) (Process, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type util struct {
|
type util struct {
|
||||||
@@ -131,7 +138,7 @@ func (u *util) Start() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
u.stopTicker = cancel
|
u.stopTicker = cancel
|
||||||
|
|
||||||
go u.tick(ctx, time.Second)
|
go u.tick(ctx, 100*time.Millisecond)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +247,9 @@ func (u *util) tick(ctx context.Context, interval time.Duration) {
|
|||||||
u.statPrevious, u.statCurrent = u.statCurrent, stat
|
u.statPrevious, u.statCurrent = u.statCurrent, stat
|
||||||
u.statPreviousTime, u.statCurrentTime = u.statCurrentTime, t
|
u.statPreviousTime, u.statCurrentTime = u.statCurrentTime, t
|
||||||
u.lock.Unlock()
|
u.lock.Unlock()
|
||||||
|
|
||||||
|
//p, _ := u.CPUPercent()
|
||||||
|
//fmt.Printf("%+v\n", p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,6 +283,7 @@ func CPUCounts(logical bool) (float64, error) {
|
|||||||
return DefaultUtil.CPUCounts(logical)
|
return DefaultUtil.CPUCounts(logical)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cpuTimes returns the current cpu usage times in seconds.
|
||||||
func (u *util) cpuTimes() (*cpuTimesStat, error) {
|
func (u *util) cpuTimes() (*cpuTimesStat, error) {
|
||||||
if u.hasCgroup && u.cpuLimit > 0 {
|
if u.hasCgroup && u.cpuLimit > 0 {
|
||||||
if stat, err := u.cgroupCPUTimes(u.cgroupType); err == nil {
|
if stat, err := u.cgroupCPUTimes(u.cgroupType); err == nil {
|
||||||
@@ -280,7 +291,7 @@ func (u *util) cpuTimes() (*cpuTimesStat, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
times, err := cpu.Times(false)
|
times, err := cpu.Times(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -289,14 +300,19 @@ func (u *util) cpuTimes() (*cpuTimesStat, error) {
|
|||||||
return nil, errors.New("cpu.Times() returned an empty slice")
|
return nil, errors.New("cpu.Times() returned an empty slice")
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &cpuTimesStat{
|
s := &cpuTimesStat{}
|
||||||
total: cpuTotal(×[0]),
|
|
||||||
system: times[0].System,
|
|
||||||
user: times[0].User,
|
|
||||||
idle: times[0].Idle,
|
|
||||||
}
|
|
||||||
|
|
||||||
s.other = s.total - s.system - s.user - s.idle
|
for _, t := range times {
|
||||||
|
s.total += cpuTotal(&t)
|
||||||
|
s.system += t.System
|
||||||
|
s.user += t.User
|
||||||
|
s.idle += t.Idle
|
||||||
|
|
||||||
|
s.other = s.total - s.system - s.user - s.idle
|
||||||
|
if s.other < 0.0001 {
|
||||||
|
s.other = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ type LogHistoryEntry struct {
|
|||||||
ExitedAt time.Time
|
ExitedAt time.Time
|
||||||
ExitState string
|
ExitState string
|
||||||
Progress Progress
|
Progress Progress
|
||||||
|
Usage ProcessUsage
|
||||||
}
|
}
|
||||||
|
|
||||||
type Log struct {
|
type Log struct {
|
||||||
|
@@ -162,3 +162,20 @@ type State struct {
|
|||||||
CPU float64 // Current CPU consumption in percent
|
CPU float64 // Current CPU consumption in percent
|
||||||
Command []string // ffmpeg command line parameters
|
Command []string // ffmpeg command line parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProcessUsageCPU struct {
|
||||||
|
Average float64
|
||||||
|
Max float64
|
||||||
|
Limit float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessUsageMemory struct {
|
||||||
|
Average float64
|
||||||
|
Max uint64
|
||||||
|
Limit uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessUsage struct {
|
||||||
|
CPU ProcessUsageCPU
|
||||||
|
Memory ProcessUsageMemory
|
||||||
|
}
|
||||||
|
@@ -1281,8 +1281,8 @@ func (r *restream) GetProcessState(id string) (*app.State, error) {
|
|||||||
state.State = status.State
|
state.State = status.State
|
||||||
state.States.Marshal(status.States)
|
state.States.Marshal(status.States)
|
||||||
state.Time = status.Time.Unix()
|
state.Time = status.Time.Unix()
|
||||||
state.Memory = status.Memory
|
state.Memory = status.Memory.Current
|
||||||
state.CPU = status.CPU
|
state.CPU = status.CPU.Current
|
||||||
state.Duration = status.Duration.Round(10 * time.Millisecond).Seconds()
|
state.Duration = status.Duration.Round(10 * time.Millisecond).Seconds()
|
||||||
state.Reconnect = -1
|
state.Reconnect = -1
|
||||||
state.Command = status.CommandArgs
|
state.Command = status.CommandArgs
|
||||||
@@ -1456,6 +1456,18 @@ func (r *restream) GetProcessLog(id string) (*app.Log, error) {
|
|||||||
},
|
},
|
||||||
ExitedAt: h.ExitedAt,
|
ExitedAt: h.ExitedAt,
|
||||||
ExitState: h.ExitState,
|
ExitState: h.ExitState,
|
||||||
|
Usage: app.ProcessUsage{
|
||||||
|
CPU: app.ProcessUsageCPU{
|
||||||
|
Average: h.Usage.CPU.Average,
|
||||||
|
Max: h.Usage.CPU.Max,
|
||||||
|
Limit: h.Usage.CPU.Limit,
|
||||||
|
},
|
||||||
|
Memory: app.ProcessUsageMemory{
|
||||||
|
Average: h.Usage.Memory.Average,
|
||||||
|
Max: h.Usage.Memory.Max,
|
||||||
|
Limit: h.Usage.Memory.Limit,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
convertProgressFromParser(&e.Progress, h.Progress)
|
convertProgressFromParser(&e.Progress, h.Progress)
|
||||||
|
Reference in New Issue
Block a user