2020-03-11 13:20:26 +08:00
|
|
|
// Copyright 2019 fatedier, fatedier@gmail.com
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package mem
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2020-09-23 13:49:14 +08:00
|
|
|
"github.com/fatedier/frp/pkg/util/log"
|
|
|
|
"github.com/fatedier/frp/pkg/util/metric"
|
2020-03-11 13:20:26 +08:00
|
|
|
server "github.com/fatedier/frp/server/metrics"
|
|
|
|
)
|
|
|
|
|
2022-08-29 01:02:53 +08:00
|
|
|
var (
|
|
|
|
sm = newServerMetrics()
|
|
|
|
|
|
|
|
ServerMetrics server.ServerMetrics
|
|
|
|
StatsCollector Collector
|
|
|
|
)
|
2020-03-11 13:20:26 +08:00
|
|
|
|
|
|
|
func init() {
|
|
|
|
ServerMetrics = sm
|
|
|
|
StatsCollector = sm
|
|
|
|
sm.run()
|
|
|
|
}
|
|
|
|
|
|
|
|
type serverMetrics struct {
|
|
|
|
info *ServerStatistics
|
|
|
|
mu sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func newServerMetrics() *serverMetrics {
|
|
|
|
return &serverMetrics{
|
|
|
|
info: &ServerStatistics{
|
|
|
|
TotalTrafficIn: metric.NewDateCounter(ReserveDays),
|
|
|
|
TotalTrafficOut: metric.NewDateCounter(ReserveDays),
|
|
|
|
CurConns: metric.NewCounter(),
|
|
|
|
|
|
|
|
ClientCounts: metric.NewCounter(),
|
|
|
|
ProxyTypeCounts: make(map[string]metric.Counter),
|
|
|
|
|
|
|
|
ProxyStatistics: make(map[string]*ProxyStatistics),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) run() {
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
time.Sleep(12 * time.Hour)
|
2023-05-28 16:50:43 +08:00
|
|
|
start := time.Now()
|
|
|
|
count, total := m.clearUselessInfo()
|
|
|
|
log.Debug("clear useless proxy statistics data count %d/%d, cost %v", count, total, time.Since(start))
|
2020-03-11 13:20:26 +08:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2023-05-28 16:50:43 +08:00
|
|
|
func (m *serverMetrics) clearUselessInfo() (int, int) {
|
|
|
|
count := 0
|
|
|
|
total := 0
|
2020-03-11 13:20:26 +08:00
|
|
|
// To check if there are proxies that closed than 7 days and drop them.
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
2023-05-28 16:50:43 +08:00
|
|
|
total = len(m.info.ProxyStatistics)
|
2020-03-11 13:20:26 +08:00
|
|
|
for name, data := range m.info.ProxyStatistics {
|
2020-09-25 16:10:20 +08:00
|
|
|
if !data.LastCloseTime.IsZero() &&
|
|
|
|
data.LastStartTime.Before(data.LastCloseTime) &&
|
|
|
|
time.Since(data.LastCloseTime) > time.Duration(7*24)*time.Hour {
|
2020-03-11 13:20:26 +08:00
|
|
|
delete(m.info.ProxyStatistics, name)
|
2023-05-28 16:50:43 +08:00
|
|
|
count++
|
2020-03-11 13:20:26 +08:00
|
|
|
log.Trace("clear proxy [%s]'s statistics data, lastCloseTime: [%s]", name, data.LastCloseTime.String())
|
|
|
|
}
|
|
|
|
}
|
2023-05-28 16:50:43 +08:00
|
|
|
return count, total
|
2020-03-11 13:20:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) NewClient() {
|
|
|
|
m.info.ClientCounts.Inc(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) CloseClient() {
|
|
|
|
m.info.ClientCounts.Dec(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) NewProxy(name string, proxyType string) {
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
counter, ok := m.info.ProxyTypeCounts[proxyType]
|
|
|
|
if !ok {
|
|
|
|
counter = metric.NewCounter()
|
|
|
|
}
|
|
|
|
counter.Inc(1)
|
|
|
|
m.info.ProxyTypeCounts[proxyType] = counter
|
|
|
|
|
|
|
|
proxyStats, ok := m.info.ProxyStatistics[name]
|
|
|
|
if !(ok && proxyStats.ProxyType == proxyType) {
|
|
|
|
proxyStats = &ProxyStatistics{
|
|
|
|
Name: name,
|
|
|
|
ProxyType: proxyType,
|
|
|
|
CurConns: metric.NewCounter(),
|
|
|
|
TrafficIn: metric.NewDateCounter(ReserveDays),
|
|
|
|
TrafficOut: metric.NewDateCounter(ReserveDays),
|
|
|
|
}
|
|
|
|
m.info.ProxyStatistics[name] = proxyStats
|
|
|
|
}
|
|
|
|
proxyStats.LastStartTime = time.Now()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) CloseProxy(name string, proxyType string) {
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
if counter, ok := m.info.ProxyTypeCounts[proxyType]; ok {
|
|
|
|
counter.Dec(1)
|
|
|
|
}
|
|
|
|
if proxyStats, ok := m.info.ProxyStatistics[name]; ok {
|
|
|
|
proxyStats.LastCloseTime = time.Now()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) OpenConnection(name string, proxyType string) {
|
|
|
|
m.info.CurConns.Inc(1)
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
proxyStats, ok := m.info.ProxyStatistics[name]
|
|
|
|
if ok {
|
|
|
|
proxyStats.CurConns.Inc(1)
|
|
|
|
m.info.ProxyStatistics[name] = proxyStats
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) CloseConnection(name string, proxyType string) {
|
|
|
|
m.info.CurConns.Dec(1)
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
proxyStats, ok := m.info.ProxyStatistics[name]
|
|
|
|
if ok {
|
|
|
|
proxyStats.CurConns.Dec(1)
|
|
|
|
m.info.ProxyStatistics[name] = proxyStats
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) AddTrafficIn(name string, proxyType string, trafficBytes int64) {
|
|
|
|
m.info.TotalTrafficIn.Inc(trafficBytes)
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
proxyStats, ok := m.info.ProxyStatistics[name]
|
|
|
|
if ok {
|
|
|
|
proxyStats.TrafficIn.Inc(trafficBytes)
|
|
|
|
m.info.ProxyStatistics[name] = proxyStats
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) AddTrafficOut(name string, proxyType string, trafficBytes int64) {
|
|
|
|
m.info.TotalTrafficOut.Inc(trafficBytes)
|
|
|
|
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
proxyStats, ok := m.info.ProxyStatistics[name]
|
|
|
|
if ok {
|
|
|
|
proxyStats.TrafficOut.Inc(trafficBytes)
|
|
|
|
m.info.ProxyStatistics[name] = proxyStats
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get stats data api.
|
|
|
|
|
|
|
|
func (m *serverMetrics) GetServer() *ServerStats {
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
s := &ServerStats{
|
|
|
|
TotalTrafficIn: m.info.TotalTrafficIn.TodayCount(),
|
|
|
|
TotalTrafficOut: m.info.TotalTrafficOut.TodayCount(),
|
2020-05-12 22:09:16 +08:00
|
|
|
CurConns: int64(m.info.CurConns.Count()),
|
|
|
|
ClientCounts: int64(m.info.ClientCounts.Count()),
|
2020-03-11 13:20:26 +08:00
|
|
|
ProxyTypeCounts: make(map[string]int64),
|
|
|
|
}
|
|
|
|
for k, v := range m.info.ProxyTypeCounts {
|
2020-05-12 22:09:16 +08:00
|
|
|
s.ProxyTypeCounts[k] = int64(v.Count())
|
2020-03-11 13:20:26 +08:00
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) GetProxiesByType(proxyType string) []*ProxyStats {
|
|
|
|
res := make([]*ProxyStats, 0)
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
for name, proxyStats := range m.info.ProxyStatistics {
|
|
|
|
if proxyStats.ProxyType != proxyType {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
ps := &ProxyStats{
|
|
|
|
Name: name,
|
|
|
|
Type: proxyStats.ProxyType,
|
|
|
|
TodayTrafficIn: proxyStats.TrafficIn.TodayCount(),
|
|
|
|
TodayTrafficOut: proxyStats.TrafficOut.TodayCount(),
|
2020-05-12 22:09:16 +08:00
|
|
|
CurConns: int64(proxyStats.CurConns.Count()),
|
2020-03-11 13:20:26 +08:00
|
|
|
}
|
|
|
|
if !proxyStats.LastStartTime.IsZero() {
|
|
|
|
ps.LastStartTime = proxyStats.LastStartTime.Format("01-02 15:04:05")
|
|
|
|
}
|
|
|
|
if !proxyStats.LastCloseTime.IsZero() {
|
|
|
|
ps.LastCloseTime = proxyStats.LastCloseTime.Format("01-02 15:04:05")
|
|
|
|
}
|
|
|
|
res = append(res, ps)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) GetProxiesByTypeAndName(proxyType string, proxyName string) (res *ProxyStats) {
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
for name, proxyStats := range m.info.ProxyStatistics {
|
|
|
|
if proxyStats.ProxyType != proxyType {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if name != proxyName {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &ProxyStats{
|
|
|
|
Name: name,
|
|
|
|
Type: proxyStats.ProxyType,
|
|
|
|
TodayTrafficIn: proxyStats.TrafficIn.TodayCount(),
|
|
|
|
TodayTrafficOut: proxyStats.TrafficOut.TodayCount(),
|
2020-05-12 22:09:16 +08:00
|
|
|
CurConns: int64(proxyStats.CurConns.Count()),
|
2020-03-11 13:20:26 +08:00
|
|
|
}
|
|
|
|
if !proxyStats.LastStartTime.IsZero() {
|
|
|
|
res.LastStartTime = proxyStats.LastStartTime.Format("01-02 15:04:05")
|
|
|
|
}
|
|
|
|
if !proxyStats.LastCloseTime.IsZero() {
|
|
|
|
res.LastCloseTime = proxyStats.LastCloseTime.Format("01-02 15:04:05")
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *serverMetrics) GetProxyTraffic(name string) (res *ProxyTrafficInfo) {
|
|
|
|
m.mu.Lock()
|
|
|
|
defer m.mu.Unlock()
|
|
|
|
|
|
|
|
proxyStats, ok := m.info.ProxyStatistics[name]
|
|
|
|
if ok {
|
|
|
|
res = &ProxyTrafficInfo{
|
|
|
|
Name: name,
|
|
|
|
}
|
|
|
|
res.TrafficIn = proxyStats.TrafficIn.GetLastDaysCount(ReserveDays)
|
|
|
|
res.TrafficOut = proxyStats.TrafficOut.GetLastDaysCount(ReserveDays)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|