mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 14:50:55 +03:00
feat: add new telemetry server (#254)
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/drakkan/sftpgo/kms"
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/sftpd"
|
||||
"github.com/drakkan/sftpgo/telemetry"
|
||||
"github.com/drakkan/sftpgo/utils"
|
||||
"github.com/drakkan/sftpgo/version"
|
||||
"github.com/drakkan/sftpgo/webdavd"
|
||||
@@ -46,6 +47,7 @@ type globalConfig struct {
|
||||
HTTPDConfig httpd.Conf `json:"httpd" mapstructure:"httpd"`
|
||||
HTTPConfig httpclient.Config `json:"http" mapstructure:"http"`
|
||||
KMSConfig kms.Configuration `json:"kms" mapstructure:"kms"`
|
||||
TelemetryConfig telemetry.Conf `json:"telemetry" mapstructure:"telemetry"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -182,6 +184,10 @@ func Init() {
|
||||
MasterKeyPath: "",
|
||||
},
|
||||
},
|
||||
TelemetryConfig: telemetry.Conf{
|
||||
BindPort: 10000,
|
||||
BindAddress: "127.0.0.1",
|
||||
},
|
||||
}
|
||||
|
||||
viper.SetEnvPrefix(configEnvPrefix)
|
||||
@@ -268,6 +274,16 @@ func SetKMSConfig(config kms.Configuration) {
|
||||
globalConf.KMSConfig = config
|
||||
}
|
||||
|
||||
// GetTelemetryConfig returns the telemetry configuration
|
||||
func GetTelemetryConfig() telemetry.Conf {
|
||||
return globalConf.TelemetryConfig
|
||||
}
|
||||
|
||||
// SetTelemetryConfig sets the telemetry configuration
|
||||
func SetTelemetryConfig(config telemetry.Conf) {
|
||||
globalConf.TelemetryConfig = config
|
||||
}
|
||||
|
||||
// HasServicesToStart returns true if the config defines at least a service to start.
|
||||
// Supported services are SFTP, FTP and WebDAV
|
||||
func HasServicesToStart() bool {
|
||||
@@ -496,4 +512,6 @@ func setViperDefaults() {
|
||||
viper.SetDefault("http.skip_tls_verify", globalConf.HTTPConfig.SkipTLSVerify)
|
||||
viper.SetDefault("kms.secrets.url", globalConf.KMSConfig.Secrets.URL)
|
||||
viper.SetDefault("kms.secrets.master_key_path", globalConf.KMSConfig.Secrets.MasterKeyPath)
|
||||
viper.SetDefault("telemetry.bind_port", globalConf.TelemetryConfig.BindPort)
|
||||
viper.SetDefault("telemetry.bind_address", globalConf.TelemetryConfig.BindAddress)
|
||||
}
|
||||
|
||||
@@ -315,6 +315,12 @@ func TestSetGetConfig(t *testing.T) {
|
||||
config.SetKMSConfig(kmsConf)
|
||||
assert.Equal(t, kmsConf.Secrets.MasterKeyPath, config.GetKMSConfig().Secrets.MasterKeyPath)
|
||||
assert.Equal(t, kmsConf.Secrets.URL, config.GetKMSConfig().Secrets.URL)
|
||||
telemetryConf := config.GetTelemetryConfig()
|
||||
telemetryConf.BindPort = 10001
|
||||
telemetryConf.BindAddress = "0.0.0.0"
|
||||
config.SetTelemetryConfig(telemetryConf)
|
||||
assert.Equal(t, telemetryConf.BindPort, config.GetTelemetryConfig().BindPort)
|
||||
assert.Equal(t, telemetryConf.BindAddress, config.GetTelemetryConfig().BindAddress)
|
||||
}
|
||||
|
||||
func TestServiceToStart(t *testing.T) {
|
||||
|
||||
@@ -128,6 +128,7 @@ func (s *Service) startServices() {
|
||||
ftpdConf := config.GetFTPDConfig()
|
||||
httpdConf := config.GetHTTPDConfig()
|
||||
webDavDConf := config.GetWebDAVDConfig()
|
||||
telemetryConf := config.GetTelemetryConfig()
|
||||
|
||||
if sftpdConf.BindPort > 0 {
|
||||
go func() {
|
||||
@@ -182,6 +183,21 @@ func (s *Service) startServices() {
|
||||
} else {
|
||||
logger.Debug(logSender, "", "WebDAV server not started, disabled in config file")
|
||||
}
|
||||
if telemetryConf.BindPort > 0 {
|
||||
go func() {
|
||||
if err := telemetryConf.Initialize(s.Profiler); err != nil {
|
||||
logger.Error(logSender, "", "could not start telemetry server: %v", err)
|
||||
logger.ErrorToConsole("could not start telemetry server: %v", err)
|
||||
s.Error = err
|
||||
}
|
||||
s.Shutdown <- true
|
||||
}()
|
||||
} else {
|
||||
logger.Debug(logSender, "", "telemetry server not started, disabled in config file")
|
||||
if s.PortableMode != 1 {
|
||||
logger.DebugToConsole("telemetry server not started, disabled in config file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait blocks until the service exits
|
||||
|
||||
32
telemetry/router.go
Normal file
32
telemetry/router.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/go-chi/render"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
"github.com/drakkan/sftpgo/metrics"
|
||||
)
|
||||
|
||||
func initializeRouter(enableProfiler bool) {
|
||||
router = chi.NewRouter()
|
||||
|
||||
router.Use(middleware.Recoverer)
|
||||
|
||||
router.Group(func(r chi.Router) {
|
||||
r.Get("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
||||
render.PlainText(w, r, "ok")
|
||||
})
|
||||
})
|
||||
|
||||
metrics.AddMetricsEndpoint(metricsPath, router)
|
||||
|
||||
if enableProfiler {
|
||||
logger.InfoToConsole("enabling the built-in profiler")
|
||||
logger.Info(logSender, "", "enabling the built-in profiler")
|
||||
router.Mount(pprofBasePath, middleware.Profiler())
|
||||
}
|
||||
}
|
||||
48
telemetry/telemetry.go
Normal file
48
telemetry/telemetry.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Package telemetry provides telemetry information for SFTPGo, such as:
|
||||
// - health information (for health checks)
|
||||
// - metrics
|
||||
// - profiling information
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
"github.com/drakkan/sftpgo/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
logSender = "telemetry"
|
||||
metricsPath = "/metrics"
|
||||
pprofBasePath = "/debug"
|
||||
)
|
||||
|
||||
var (
|
||||
router *chi.Mux
|
||||
)
|
||||
|
||||
// Conf telemetry server configuration.
|
||||
type Conf struct {
|
||||
// The port used for serving HTTP requests. 0 disable the HTTP server. Default: 8080
|
||||
BindPort int `json:"bind_port" mapstructure:"bind_port"`
|
||||
// The address to listen on. A blank value means listen on all available network interfaces. Default: "127.0.0.1"
|
||||
BindAddress string `json:"bind_address" mapstructure:"bind_address"`
|
||||
}
|
||||
|
||||
// Initialize configures and starts the telemetry server.
|
||||
func (c Conf) Initialize(enableProfiler bool) error {
|
||||
logger.Debug(logSender, "", "initializing telemetry server with config %+v", c)
|
||||
initializeRouter(enableProfiler)
|
||||
httpServer := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", c.BindAddress, c.BindPort),
|
||||
Handler: router,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
WriteTimeout: 60 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
MaxHeaderBytes: 1 << 16, // 64KB
|
||||
}
|
||||
return httpServer.ListenAndServe()
|
||||
}
|
||||
Reference in New Issue
Block a user