mirror of
https://github.com/fatedier/frp.git
synced 2025-07-27 07:35:07 +00:00
api: add server web api for statistics
This commit is contained in:
@@ -1,3 +1,17 @@
|
||||
// Copyright 2017 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 server
|
||||
|
||||
import (
|
||||
@@ -253,10 +267,13 @@ func (ctl *Control) stoper() {
|
||||
for _, pxy := range ctl.proxies {
|
||||
pxy.Close()
|
||||
ctl.svr.DelProxy(pxy.GetName())
|
||||
StatsCloseProxy(pxy.GetConf().GetBaseInfo().ProxyType)
|
||||
}
|
||||
|
||||
ctl.allShutdown.Done()
|
||||
ctl.conn.Info("client exit success")
|
||||
|
||||
StatsCloseClient()
|
||||
}
|
||||
|
||||
func (ctl *Control) manager() {
|
||||
@@ -296,6 +313,7 @@ func (ctl *Control) manager() {
|
||||
ctl.conn.Warn("new proxy [%s] error: %v", m.ProxyName, err)
|
||||
} else {
|
||||
ctl.conn.Info("new proxy [%s] success", m.ProxyName)
|
||||
StatsNewProxy(m.ProxyName, m.ProxyType)
|
||||
}
|
||||
ctl.sendCh <- resp
|
||||
case *msg.Ping:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016 fatedier, fatedier@gmail.com
|
||||
// Copyright 2017 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.
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
|
||||
"github.com/fatedier/frp/assets"
|
||||
"github.com/fatedier/frp/models/config"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -31,20 +33,27 @@ var (
|
||||
|
||||
func RunDashboardServer(addr string, port int64) (err error) {
|
||||
// url router
|
||||
mux := http.NewServeMux()
|
||||
router := httprouter.New()
|
||||
|
||||
// api, see dashboard_api.go
|
||||
//mux.HandleFunc("/api/reload", use(apiReload, basicAuth))
|
||||
//mux.HandleFunc("/api/proxies", apiProxies)
|
||||
router.GET("/api/serverinfo", apiServerInfo)
|
||||
router.GET("/api/proxy/tcp", apiProxyTcp)
|
||||
router.GET("/api/proxy/udp", apiProxyUdp)
|
||||
router.GET("/api/proxy/http", apiProxyHttp)
|
||||
router.GET("/api/proxy/https", apiProxyHttps)
|
||||
router.GET("/api/proxy/flow/:name", apiProxyFlow)
|
||||
|
||||
// view, see dashboard_view.go
|
||||
mux.Handle("/favicon.ico", http.FileServer(assets.FileSystem))
|
||||
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(assets.FileSystem)))
|
||||
//mux.HandleFunc("/", use(viewDashboard, basicAuth))
|
||||
//router.GET("/favicon.ico", http.FileServer(assets.FileSystem))
|
||||
router.Handler("GET", "/favicon.ico", http.FileServer(assets.FileSystem))
|
||||
router.Handler("GET", "/static", http.StripPrefix("/static/", http.FileServer(assets.FileSystem)))
|
||||
//router.GET("/", use(viewDashboard, basicAuth))
|
||||
|
||||
address := fmt.Sprintf("%s:%d", addr, port)
|
||||
server := &http.Server{
|
||||
Addr: address,
|
||||
Handler: mux,
|
||||
Handler: router,
|
||||
ReadTimeout: httpServerReadTimeout,
|
||||
WriteTimeout: httpServerWriteTimeout,
|
||||
}
|
||||
@@ -64,7 +73,6 @@ func use(h http.HandlerFunc, middleware ...func(http.HandlerFunc) http.HandlerFu
|
||||
for _, m := range middleware {
|
||||
h = m(h)
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016 fatedier, fatedier@gmail.com
|
||||
// Copyright 2017 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.
|
||||
@@ -14,14 +14,15 @@
|
||||
|
||||
package server
|
||||
|
||||
/*
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/fatedier/frp/src/models/metric"
|
||||
"github.com/fatedier/frp/src/utils/log"
|
||||
"github.com/fatedier/frp/models/config"
|
||||
"github.com/fatedier/frp/models/consts"
|
||||
"github.com/fatedier/frp/utils/log"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
type GeneralResponse struct {
|
||||
@@ -29,41 +30,187 @@ type GeneralResponse struct {
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func apiReload(w http.ResponseWriter, r *http.Request) {
|
||||
var buf []byte
|
||||
res := &GeneralResponse{}
|
||||
// api/serverinfo
|
||||
type ServerInfoResp struct {
|
||||
GeneralResponse
|
||||
|
||||
VhostHttpPort int64 `json:"vhost_http_port"`
|
||||
VhostHttpsPort int64 `json:"vhost_https_port"`
|
||||
AuthTimeout int64 `json:"auth_timeout"`
|
||||
SubdomainHost string `json:"subdomain_host"`
|
||||
MaxPoolCount int64 `json:"max_pool_count"`
|
||||
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
|
||||
|
||||
TotalFlowIn int64 `json:"total_flow_in"`
|
||||
TotalFlowOut int64 `json:"total_flow_out"`
|
||||
CurConns int64 `json:"cur_conns"`
|
||||
ClientCounts int64 `json:"client_counts"`
|
||||
ProxyTypeCounts map[string]int64 `json:"proxy_type_count"`
|
||||
}
|
||||
|
||||
func apiServerInfo(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
var (
|
||||
buf []byte
|
||||
res ServerInfoResp
|
||||
)
|
||||
defer func() {
|
||||
log.Info("Http response [/api/reload]: %s", string(buf))
|
||||
log.Info("Http response [/api/serverinfo]: code [%d]", res.Code)
|
||||
}()
|
||||
|
||||
log.Info("Http request: [/api/reload]")
|
||||
err := ReloadConf(ConfigFile)
|
||||
if err != nil {
|
||||
res.Code = 2
|
||||
res.Msg = fmt.Sprintf("%v", err)
|
||||
log.Error("frps reload error: %v", err)
|
||||
log.Info("Http request: [/api/serverinfo]")
|
||||
cfg := config.ServerCommonCfg
|
||||
serverStats := StatsGetServer()
|
||||
res = ServerInfoResp{
|
||||
VhostHttpPort: cfg.VhostHttpPort,
|
||||
VhostHttpsPort: cfg.VhostHttpsPort,
|
||||
AuthTimeout: cfg.AuthTimeout,
|
||||
SubdomainHost: cfg.SubDomainHost,
|
||||
MaxPoolCount: cfg.MaxPoolCount,
|
||||
HeartBeatTimeout: cfg.HeartBeatTimeout,
|
||||
|
||||
TotalFlowIn: serverStats.TotalFlowIn,
|
||||
TotalFlowOut: serverStats.TotalFlowOut,
|
||||
CurConns: serverStats.CurConns,
|
||||
ClientCounts: serverStats.ClientCounts,
|
||||
ProxyTypeCounts: serverStats.ProxyTypeCounts,
|
||||
}
|
||||
|
||||
buf, _ = json.Marshal(res)
|
||||
buf, _ = json.Marshal(&res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
type ProxiesResponse struct {
|
||||
Code int64 `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Proxies []*metric.ServerMetric `json:"proxies"`
|
||||
// Get proxy info.
|
||||
type ProxyStatsInfo struct {
|
||||
Conf config.ProxyConf `json:"conf"`
|
||||
TodayFlowIn int64 `json:"today_flow_in"`
|
||||
TodayFlowOut int64 `json:"today_flow_out"`
|
||||
CurConns int64 `json:"cur_conns"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func apiProxies(w http.ResponseWriter, r *http.Request) {
|
||||
var buf []byte
|
||||
res := &ProxiesResponse{}
|
||||
type GetProxyInfoResp struct {
|
||||
GeneralResponse
|
||||
Proxies []*ProxyStatsInfo `json:"proxies"`
|
||||
}
|
||||
|
||||
// api/proxy/tcp
|
||||
func apiProxyTcp(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
var (
|
||||
buf []byte
|
||||
res GetProxyInfoResp
|
||||
)
|
||||
defer func() {
|
||||
log.Info("Http response [/api/proxies]: code [%d]", res.Code)
|
||||
log.Info("Http response [/api/proxy/tcp]: code [%d]", res.Code)
|
||||
}()
|
||||
log.Info("Http request: [/api/proxy/tcp]")
|
||||
|
||||
log.Info("Http request: [/api/proxies]")
|
||||
res.Proxies = metric.GetAllProxyMetrics()
|
||||
buf, _ = json.Marshal(res)
|
||||
res.Proxies = getProxyStatsByType(consts.TcpProxy)
|
||||
|
||||
buf, _ = json.Marshal(&res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
// api/proxy/udp
|
||||
func apiProxyUdp(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
var (
|
||||
buf []byte
|
||||
res GetProxyInfoResp
|
||||
)
|
||||
defer func() {
|
||||
log.Info("Http response [/api/proxy/udp]: code [%d]", res.Code)
|
||||
}()
|
||||
log.Info("Http request: [/api/proxy/udp]")
|
||||
|
||||
res.Proxies = getProxyStatsByType(consts.UdpProxy)
|
||||
|
||||
buf, _ = json.Marshal(&res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
// api/proxy/http
|
||||
func apiProxyHttp(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
var (
|
||||
buf []byte
|
||||
res GetProxyInfoResp
|
||||
)
|
||||
defer func() {
|
||||
log.Info("Http response [/api/proxy/http]: code [%d]", res.Code)
|
||||
}()
|
||||
log.Info("Http request: [/api/proxy/http]")
|
||||
|
||||
res.Proxies = getProxyStatsByType(consts.HttpProxy)
|
||||
|
||||
buf, _ = json.Marshal(&res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
// api/proxy/https
|
||||
func apiProxyHttps(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
var (
|
||||
buf []byte
|
||||
res GetProxyInfoResp
|
||||
)
|
||||
defer func() {
|
||||
log.Info("Http response [/api/proxy/https]: code [%d]", res.Code)
|
||||
}()
|
||||
log.Info("Http request: [/api/proxy/https]")
|
||||
|
||||
res.Proxies = getProxyStatsByType(consts.HttpsProxy)
|
||||
|
||||
buf, _ = json.Marshal(&res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
func getProxyStatsByType(proxyType string) (proxyInfos []*ProxyStatsInfo) {
|
||||
proxyStats := StatsGetProxiesByType(proxyType)
|
||||
proxyInfos = make([]*ProxyStatsInfo, 0, len(proxyStats))
|
||||
for _, ps := range proxyStats {
|
||||
proxyInfo := &ProxyStatsInfo{}
|
||||
if pxy, ok := ServerService.pxyManager.GetByName(ps.Name); ok {
|
||||
proxyInfo.Conf = pxy.GetConf()
|
||||
proxyInfo.Status = consts.Online
|
||||
} else {
|
||||
proxyInfo.Status = consts.Offline
|
||||
}
|
||||
proxyInfo.TodayFlowIn = ps.TodayFlowIn
|
||||
proxyInfo.TodayFlowOut = ps.TodayFlowOut
|
||||
proxyInfo.CurConns = ps.CurConns
|
||||
proxyInfos = append(proxyInfos, proxyInfo)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// api/proxy/:name/flow
|
||||
type GetProxyFlowResp struct {
|
||||
GeneralResponse
|
||||
|
||||
Name string `json:"name"`
|
||||
FlowIn []int64 `json:"flow_in"`
|
||||
FlowOut []int64 `json:"flow_out"`
|
||||
}
|
||||
|
||||
func apiProxyFlow(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||
var (
|
||||
buf []byte
|
||||
res GetProxyFlowResp
|
||||
)
|
||||
name := params.ByName("name")
|
||||
|
||||
defer func() {
|
||||
log.Info("Http response [/api/proxy/flow/:name]: code [%d]", res.Code)
|
||||
}()
|
||||
log.Info("Http request: [/api/proxy/flow/:name]")
|
||||
|
||||
res.Name = name
|
||||
proxyFlowInfo := StatsGetProxyFlow(name)
|
||||
if proxyFlowInfo == nil {
|
||||
res.Code = 1
|
||||
res.Msg = "no proxy info found"
|
||||
} else {
|
||||
res.FlowIn = proxyFlowInfo.FlowIn
|
||||
res.FlowOut = proxyFlowInfo.FlowOut
|
||||
}
|
||||
|
||||
buf, _ = json.Marshal(&res)
|
||||
w.Write(buf)
|
||||
}
|
||||
*/
|
||||
|
@@ -1,3 +1,17 @@
|
||||
// Copyright 2017 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 server
|
||||
|
||||
import (
|
||||
|
241
server/metric.go
Normal file
241
server/metric.go
Normal file
@@ -0,0 +1,241 @@
|
||||
// Copyright 2017 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 server
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/fatedier/frp/models/config"
|
||||
"github.com/fatedier/frp/utils/metric"
|
||||
)
|
||||
|
||||
const (
|
||||
ReserveDays = 7
|
||||
)
|
||||
|
||||
var globalStats *ServerStatistics
|
||||
|
||||
type ServerStatistics struct {
|
||||
TotalFlowIn metric.DateCounter
|
||||
TotalFlowOut metric.DateCounter
|
||||
CurConns metric.Counter
|
||||
|
||||
ClientCounts metric.Counter
|
||||
ProxyTypeCounts map[string]metric.Counter
|
||||
|
||||
ProxyStatistics map[string]*ProxyStatistics
|
||||
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
type ProxyStatistics struct {
|
||||
ProxyType string
|
||||
FlowIn metric.DateCounter
|
||||
FlowOut metric.DateCounter
|
||||
CurConns metric.Counter
|
||||
}
|
||||
|
||||
func init() {
|
||||
globalStats = &ServerStatistics{
|
||||
TotalFlowIn: metric.NewDateCounter(ReserveDays),
|
||||
TotalFlowOut: metric.NewDateCounter(ReserveDays),
|
||||
CurConns: metric.NewCounter(),
|
||||
|
||||
ClientCounts: metric.NewCounter(),
|
||||
ProxyTypeCounts: make(map[string]metric.Counter),
|
||||
|
||||
ProxyStatistics: make(map[string]*ProxyStatistics),
|
||||
}
|
||||
}
|
||||
|
||||
func StatsNewClient() {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.ClientCounts.Inc(1)
|
||||
}
|
||||
}
|
||||
|
||||
func StatsCloseClient() {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.ClientCounts.Dec(1)
|
||||
}
|
||||
}
|
||||
|
||||
func StatsNewProxy(name string, proxyType string) {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
counter, ok := globalStats.ProxyTypeCounts[proxyType]
|
||||
if !ok {
|
||||
counter = metric.NewCounter()
|
||||
}
|
||||
counter.Inc(1)
|
||||
globalStats.ProxyTypeCounts[proxyType] = counter
|
||||
|
||||
proxyStats, ok := globalStats.ProxyStatistics[name]
|
||||
if !ok {
|
||||
proxyStats = &ProxyStatistics{
|
||||
ProxyType: proxyType,
|
||||
CurConns: metric.NewCounter(),
|
||||
FlowIn: metric.NewDateCounter(ReserveDays),
|
||||
FlowOut: metric.NewDateCounter(ReserveDays),
|
||||
}
|
||||
globalStats.ProxyStatistics[name] = proxyStats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StatsCloseProxy(proxyType string) {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
if counter, ok := globalStats.ProxyTypeCounts[proxyType]; ok {
|
||||
counter.Dec(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StatsOpenConnection(name string) {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.CurConns.Inc(1)
|
||||
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
proxyStats, ok := globalStats.ProxyStatistics[name]
|
||||
if ok {
|
||||
proxyStats.CurConns.Inc(1)
|
||||
globalStats.ProxyStatistics[name] = proxyStats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StatsCloseConnection(name string) {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.CurConns.Dec(1)
|
||||
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
proxyStats, ok := globalStats.ProxyStatistics[name]
|
||||
if ok {
|
||||
proxyStats.CurConns.Dec(1)
|
||||
globalStats.ProxyStatistics[name] = proxyStats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StatsAddFlowIn(name string, flowIn int64) {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.TotalFlowIn.Inc(flowIn)
|
||||
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
|
||||
proxyStats, ok := globalStats.ProxyStatistics[name]
|
||||
if ok {
|
||||
proxyStats.FlowIn.Inc(flowIn)
|
||||
globalStats.ProxyStatistics[name] = proxyStats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StatsAddFlowOut(name string, flowOut int64) {
|
||||
if config.ServerCommonCfg.DashboardPort != 0 {
|
||||
globalStats.TotalFlowOut.Inc(flowOut)
|
||||
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
|
||||
proxyStats, ok := globalStats.ProxyStatistics[name]
|
||||
if ok {
|
||||
proxyStats.FlowOut.Inc(flowOut)
|
||||
globalStats.ProxyStatistics[name] = proxyStats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for getting server stats.
|
||||
type ServerStats struct {
|
||||
TotalFlowIn int64
|
||||
TotalFlowOut int64
|
||||
CurConns int64
|
||||
ClientCounts int64
|
||||
ProxyTypeCounts map[string]int64
|
||||
}
|
||||
|
||||
func StatsGetServer() *ServerStats {
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
s := &ServerStats{
|
||||
TotalFlowIn: globalStats.TotalFlowIn.TodayCount(),
|
||||
TotalFlowOut: globalStats.TotalFlowOut.TodayCount(),
|
||||
CurConns: globalStats.CurConns.Count(),
|
||||
ClientCounts: globalStats.ClientCounts.Count(),
|
||||
ProxyTypeCounts: make(map[string]int64),
|
||||
}
|
||||
for k, v := range globalStats.ProxyTypeCounts {
|
||||
s.ProxyTypeCounts[k] = v.Count()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type ProxyStats struct {
|
||||
Name string
|
||||
Type string
|
||||
TodayFlowIn int64
|
||||
TodayFlowOut int64
|
||||
CurConns int64
|
||||
}
|
||||
|
||||
func StatsGetProxiesByType(proxyType string) []*ProxyStats {
|
||||
res := make([]*ProxyStats, 0)
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
|
||||
for name, proxyStats := range globalStats.ProxyStatistics {
|
||||
if proxyStats.ProxyType != proxyType {
|
||||
continue
|
||||
}
|
||||
|
||||
ps := &ProxyStats{
|
||||
Name: name,
|
||||
Type: proxyStats.ProxyType,
|
||||
TodayFlowIn: proxyStats.FlowIn.TodayCount(),
|
||||
TodayFlowOut: proxyStats.FlowOut.TodayCount(),
|
||||
CurConns: proxyStats.CurConns.Count(),
|
||||
}
|
||||
res = append(res, ps)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type ProxyFlowInfo struct {
|
||||
Name string
|
||||
FlowIn []int64
|
||||
FlowOut []int64
|
||||
}
|
||||
|
||||
func StatsGetProxyFlow(name string) (res *ProxyFlowInfo) {
|
||||
globalStats.mu.Lock()
|
||||
defer globalStats.mu.Unlock()
|
||||
|
||||
proxyStats, ok := globalStats.ProxyStatistics[name]
|
||||
if ok {
|
||||
res = &ProxyFlowInfo{
|
||||
Name: name,
|
||||
}
|
||||
res.FlowIn = proxyStats.FlowIn.GetLastDaysCount(ReserveDays)
|
||||
res.FlowOut = proxyStats.FlowOut.GetLastDaysCount(ReserveDays)
|
||||
}
|
||||
return
|
||||
}
|
@@ -1,3 +1,17 @@
|
||||
// Copyright 2017 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 server
|
||||
|
||||
import (
|
||||
@@ -402,6 +416,11 @@ func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn) {
|
||||
}
|
||||
pxy.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
|
||||
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
|
||||
tcp.Join(local, userConn)
|
||||
|
||||
StatsOpenConnection(pxy.GetName())
|
||||
inCount, outCount := tcp.Join(local, userConn)
|
||||
StatsCloseConnection(pxy.GetName())
|
||||
StatsAddFlowIn(pxy.GetName(), inCount)
|
||||
StatsAddFlowOut(pxy.GetName(), outCount)
|
||||
pxy.Debug("join connections closed")
|
||||
}
|
||||
|
@@ -1,3 +1,17 @@
|
||||
// Copyright 2017 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 server
|
||||
|
||||
import (
|
||||
@@ -14,6 +28,8 @@ import (
|
||||
"github.com/fatedier/frp/utils/vhost"
|
||||
)
|
||||
|
||||
var ServerService *Service
|
||||
|
||||
// Server service.
|
||||
type Service struct {
|
||||
// Accept connections from client.
|
||||
@@ -172,6 +188,9 @@ func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login) (err
|
||||
|
||||
ctlConn.AddLogPrefix(loginMsg.RunId)
|
||||
ctl.Start()
|
||||
|
||||
// for statistics
|
||||
StatsNewClient()
|
||||
return
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user