move metrics server into platform service (#20683)
move metrics into platform
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
07623a70fd
Коммит
b18a42313b
@@ -3,14 +3,28 @@
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/config"
|
||||
"github.com/mattermost/mattermost-server/v6/einterfaces"
|
||||
)
|
||||
|
||||
// ServiceConfig is used to initialize the PlatformService.
|
||||
// The mandatory fields will be checked during the initialization of the service.
|
||||
type ServiceConfig struct {
|
||||
// Mandatory fields
|
||||
ConfigStore *config.Store
|
||||
StartMetrics bool // TODO: find an elegant way to start/stop metrics server by default
|
||||
// Optional fields
|
||||
Metrics einterfaces.MetricsInterface
|
||||
Cluster einterfaces.ClusterInterface
|
||||
}
|
||||
|
||||
func (c *ServiceConfig) validate() error {
|
||||
// Mandatory fields need to be checked here
|
||||
if c.ConfigStore == nil {
|
||||
return errors.New("ConfigStore is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
162
app/platform/metrics.go
Обычный файл
162
app/platform/metrics.go
Обычный файл
@@ -0,0 +1,162 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"runtime"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/mattermost-server/v6/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const TimeToWaitForConnectionsToCloseOnServerShutdown = time.Second
|
||||
|
||||
type platformMetrics struct {
|
||||
server *http.Server
|
||||
router *mux.Router
|
||||
lock sync.Mutex
|
||||
|
||||
metricsImpl einterfaces.MetricsInterface
|
||||
|
||||
cfgFn func() *model.Config
|
||||
}
|
||||
|
||||
func newPlatformMetrics(metricsImpl einterfaces.MetricsInterface, cfgFn func() *model.Config) *platformMetrics {
|
||||
if !*cfgFn().MetricsSettings.Enable {
|
||||
return nil
|
||||
}
|
||||
|
||||
pm := &platformMetrics{
|
||||
cfgFn: cfgFn,
|
||||
}
|
||||
|
||||
pm.stopMetricsServer()
|
||||
|
||||
if err := pm.initMetricsRouter(); err != nil {
|
||||
mlog.Error("Error initiating metrics router.", mlog.Err(err))
|
||||
}
|
||||
|
||||
if metricsImpl != nil {
|
||||
metricsImpl.Register()
|
||||
}
|
||||
|
||||
pm.startMetricsServer()
|
||||
|
||||
return pm
|
||||
}
|
||||
|
||||
func (pm *platformMetrics) stopMetricsServer() {
|
||||
pm.lock.Lock()
|
||||
defer pm.lock.Unlock()
|
||||
|
||||
if pm.server != nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), TimeToWaitForConnectionsToCloseOnServerShutdown)
|
||||
defer cancel()
|
||||
|
||||
pm.server.Shutdown(ctx)
|
||||
mlog.Info("Metrics and profiling server is stopping")
|
||||
}
|
||||
}
|
||||
|
||||
func (pm *platformMetrics) startMetricsServer() {
|
||||
var notify chan struct{}
|
||||
pm.lock.Lock()
|
||||
defer func() {
|
||||
if notify != nil {
|
||||
<-notify
|
||||
}
|
||||
pm.lock.Unlock()
|
||||
}()
|
||||
|
||||
l, err := net.Listen("tcp", *pm.cfgFn().MetricsSettings.ListenAddress)
|
||||
if err != nil {
|
||||
mlog.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
notify = make(chan struct{})
|
||||
pm.server = &http.Server{
|
||||
Handler: handlers.RecoveryHandler(handlers.PrintRecoveryStack(true))(pm.router),
|
||||
ReadTimeout: time.Duration(*pm.cfgFn().ServiceSettings.ReadTimeout) * time.Second,
|
||||
WriteTimeout: time.Duration(*pm.cfgFn().ServiceSettings.WriteTimeout) * time.Second,
|
||||
}
|
||||
|
||||
go func() {
|
||||
close(notify)
|
||||
if err := pm.server.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
mlog.Critical(err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
mlog.Info("Metrics and profiling server is started", mlog.String("address", l.Addr().String()))
|
||||
}
|
||||
|
||||
func (pm *platformMetrics) initMetricsRouter() error {
|
||||
pm.router = mux.NewRouter()
|
||||
runtime.SetBlockProfileRate(*pm.cfgFn().MetricsSettings.BlockProfileRate)
|
||||
|
||||
metricsPage := `
|
||||
<html>
|
||||
<body>{{if .}}
|
||||
<div><a href="/metrics">Metrics</a></div>{{end}}
|
||||
<div><a href="/debug/pprof/">Profiling Root</a></div>
|
||||
<div><a href="/debug/pprof/cmdline">Profiling Command Line</a></div>
|
||||
<div><a href="/debug/pprof/symbol">Profiling Symbols</a></div>
|
||||
<div><a href="/debug/pprof/goroutine">Profiling Goroutines</a></div>
|
||||
<div><a href="/debug/pprof/heap">Profiling Heap</a></div>
|
||||
<div><a href="/debug/pprof/threadcreate">Profiling Threads</a></div>
|
||||
<div><a href="/debug/pprof/block">Profiling Blocking</a></div>
|
||||
<div><a href="/debug/pprof/trace">Profiling Execution Trace</a></div>
|
||||
<div><a href="/debug/pprof/profile">Profiling CPU</a></div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
metricsPageTmpl, err := template.New("page").Parse(metricsPage)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create template")
|
||||
}
|
||||
|
||||
rootHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
metricsPageTmpl.Execute(w, pm.metricsImpl != nil)
|
||||
}
|
||||
|
||||
pm.router.HandleFunc("/", rootHandler)
|
||||
pm.router.StrictSlash(true)
|
||||
|
||||
pm.router.Handle("/debug", http.RedirectHandler("/", http.StatusMovedPermanently))
|
||||
pm.router.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
pm.router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
pm.router.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
pm.router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
pm.router.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
// Manually add support for paths linked to by index page at /debug/pprof/
|
||||
pm.router.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
|
||||
pm.router.Handle("/debug/pprof/heap", pprof.Handler("heap"))
|
||||
pm.router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
|
||||
pm.router.Handle("/debug/pprof/block", pprof.Handler("block"))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *PlatformService) HandleMetrics(route string, h http.Handler) {
|
||||
if ps.metrics.router != nil {
|
||||
ps.metrics.router.Handle(route, h)
|
||||
}
|
||||
}
|
||||
|
||||
func (ps *PlatformService) RestartMetrics() {
|
||||
ps.metrics = newPlatformMetrics(ps.serviceConfig.Metrics, ps.serviceConfig.ConfigStore.Get)
|
||||
}
|
||||
@@ -3,17 +3,42 @@
|
||||
|
||||
package platform
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/v6/config"
|
||||
"github.com/mattermost/mattermost-server/v6/einterfaces"
|
||||
)
|
||||
|
||||
// PlatformService is the service for the platform related tasks. It is
|
||||
// responsible for non-entity related functionalities that are required
|
||||
// by a product such as database access, configuration access, licensing etc.
|
||||
type PlatformService struct {
|
||||
serviceConfig ServiceConfig
|
||||
configStore *config.Store
|
||||
|
||||
metrics *platformMetrics
|
||||
|
||||
cluster einterfaces.ClusterInterface
|
||||
}
|
||||
|
||||
// New creates a new PlatformService.
|
||||
func New(c ServiceConfig) (*PlatformService, error) {
|
||||
if err := c.validate(); err != nil {
|
||||
func New(sc ServiceConfig) (*PlatformService, error) {
|
||||
if err := sc.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PlatformService{}, nil
|
||||
ps := &PlatformService{
|
||||
serviceConfig: sc,
|
||||
configStore: sc.ConfigStore,
|
||||
cluster: sc.Cluster,
|
||||
}
|
||||
|
||||
ps.metrics = newPlatformMetrics(sc.Metrics, ps.configStore.Get)
|
||||
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func (ps *PlatformService) ShutdownMetrics() {
|
||||
if ps.metrics != nil {
|
||||
ps.metrics.stopMetricsServer()
|
||||
}
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user