diff --git a/cmd/frps/root.go b/cmd/frps/root.go index 955c90fb..274f3fb8 100644 --- a/cmd/frps/root.go +++ b/cmd/frps/root.go @@ -53,6 +53,7 @@ var ( logFile string logLevel string logMaxDays int64 + logDurationTypes string disableLogColor bool token string subDomainHost string @@ -84,6 +85,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file") rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level") rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days") + rootCmd.PersistentFlags().StringVarP(&logDurationTypes, "log_duration_types", "", "ssh,rdp", "log duration types") rootCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console") rootCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token") @@ -176,6 +178,7 @@ func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) { cfg.LogFile = logFile cfg.LogLevel = logLevel cfg.LogMaxDays = logMaxDays + cfg.LogDurationTypes = logDurationTypes cfg.SubDomainHost = subDomainHost cfg.TLSOnly = tlsOnly diff --git a/conf/frps_full.ini b/conf/frps_full.ini index 2d5e08e1..28081d16 100644 --- a/conf/frps_full.ini +++ b/conf/frps_full.ini @@ -70,6 +70,12 @@ log_level = info log_max_days = 3 +# log the duration of each connection for the connection type identified by its name +# examples, +# 'log_duration_types = ssh,rdp', it will log the duration for connection name has string 'ssh' or 'rdp'. +# 'log_duration_types = all', it will log the duration for all connections. +log_duration_types = ssh,rdp + # disable log colors when log_file is console, default is false disable_log_color = false diff --git a/pkg/config/server.go b/pkg/config/server.go index 040eaf65..bd3c4ddb 100644 --- a/pkg/config/server.go +++ b/pkg/config/server.go @@ -122,6 +122,11 @@ type ServerCommonConf struct { // before deletion. This is only used if LogWay == "file". By default, this // value is 0. LogMaxDays int64 `ini:"log_max_days" json:"log_max_days"` + // LogDurationTypes specifies the type of connection name, which will log + // the duration of those connections. if it is setting as 'ssh,rdp', it + // will log the duration of the name as 'ssh', 'ssh_1', 'sshname', 'rdp', + // 'rdp_test1' or 'web_my_rdp' . By default, this value is "ssh,rdp". + LogDurationTypes string `ini:"log_duration_types" json:"log_duration_types"` // DisableLogColor disables log colors when LogWay == "console" when set to // true. By default, this value is false. DisableLogColor bool `ini:"disable_log_color" json:"disable_log_color"` @@ -212,6 +217,7 @@ func GetDefaultServerConf() ServerCommonConf { LogWay: "console", LogLevel: "info", LogMaxDays: 3, + LogDurationTypes: "ssh,rdp", DetailedErrorsToClient: true, TCPMux: true, TCPMuxKeepaliveInterval: 60, diff --git a/pkg/config/server_test.go b/pkg/config/server_test.go index 475a86b6..84cbcbab 100644 --- a/pkg/config/server_test.go +++ b/pkg/config/server_test.go @@ -53,6 +53,7 @@ func Test_LoadServerCommonConf(t *testing.T) { log_way = file log_level = info9 log_max_days = 39 + log_duration_types = ssh9,rdp9 disable_log_color = false detailed_errors_to_client authentication_method = token @@ -124,6 +125,7 @@ func Test_LoadServerCommonConf(t *testing.T) { LogWay: "file", LogLevel: "info9", LogMaxDays: 39, + LogDurationTypes: "ssh9,rdp9", DisableLogColor: false, DetailedErrorsToClient: true, HeartbeatTimeout: 99, @@ -195,6 +197,7 @@ func Test_LoadServerCommonConf(t *testing.T) { LogWay: "console", LogLevel: "info", LogMaxDays: 3, + LogDurationTypes: "ssh,rdp", DetailedErrorsToClient: true, TCPMux: true, TCPMuxKeepaliveInterval: 60, diff --git a/server/proxy/proxy.go b/server/proxy/proxy.go index 808d9316..bc57face 100644 --- a/server/proxy/proxy.go +++ b/server/proxy/proxy.go @@ -20,6 +20,7 @@ import ( "io" "net" "strconv" + "strings" "sync" "time" @@ -287,6 +288,7 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv if cfg.UseCompression { local = frpIo.WithCompression(local) } + startime := time.Now().UnixNano() / 1000000 // time in microseconds xl.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()) @@ -297,7 +299,30 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv metrics.Server.CloseConnection(name, proxyType) metrics.Server.AddTrafficIn(name, proxyType, inCount) metrics.Server.AddTrafficOut(name, proxyType, outCount) - xl.Debug("join connections closed") + + if IsTheTypeToLog(serverCfg.LogDurationTypes, name) { + endtime := time.Now().UnixNano() / 1000000 // time in microseconds + connectionDuration := endtime - startime + xl.Debug("join connection closed, it remains [%d]ms, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", connectionDuration, + workConn.LocalAddr().String(), workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String()) + xl.Info("connection closed, it remains [%d]ms, userConn(l[%s] r[%s])", connectionDuration, + userConn.LocalAddr().String(), userConn.RemoteAddr().String()) + } else { + xl.Debug("join connection closed, userConn(l[%s] r[%s])", userConn.LocalAddr().String(), userConn.RemoteAddr().String()) + } +} + +func IsTheTypeToLog(logDurationTypes string, name string) bool { + if strings.Contains(logDurationTypes, "all") { + return true + } + thestrlist := strings.Split(logDurationTypes, ",") + for i := 0; i < len(thestrlist); i++ { + if strings.Contains(name, thestrlist[i]) { + return true + } + } + return false } type Manager struct {