mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
With this change in place, the grafana service will signal readiness to serve by writing "READY=1" to the path specified through the NOTIFY_SOCKET environment variable. If this environment variable is not present or empty, no notification will happen. This notification is the standard systemd mechanism for indicating a service is ready to serve. For Grafana this may be a couple of seconds from startup due to database migrations. This change also adjusts the Grafana systemd service definition to make use of this feature.
174 lines
4.1 KiB
Go
174 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
|
"github.com/grafana/grafana/pkg/services/provisioning"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
"github.com/grafana/grafana/pkg/api"
|
|
"github.com/grafana/grafana/pkg/log"
|
|
"github.com/grafana/grafana/pkg/login"
|
|
"github.com/grafana/grafana/pkg/metrics"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/plugins"
|
|
"github.com/grafana/grafana/pkg/services/alerting"
|
|
"github.com/grafana/grafana/pkg/services/cleanup"
|
|
"github.com/grafana/grafana/pkg/services/notifications"
|
|
"github.com/grafana/grafana/pkg/services/search"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
"github.com/grafana/grafana/pkg/social"
|
|
"github.com/grafana/grafana/pkg/tracing"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
)
|
|
|
|
func NewGrafanaServer() models.GrafanaServer {
|
|
rootCtx, shutdownFn := context.WithCancel(context.Background())
|
|
childRoutines, childCtx := errgroup.WithContext(rootCtx)
|
|
|
|
return &GrafanaServerImpl{
|
|
context: childCtx,
|
|
shutdownFn: shutdownFn,
|
|
childRoutines: childRoutines,
|
|
log: log.New("server"),
|
|
}
|
|
}
|
|
|
|
type GrafanaServerImpl struct {
|
|
context context.Context
|
|
shutdownFn context.CancelFunc
|
|
childRoutines *errgroup.Group
|
|
log log.Logger
|
|
|
|
httpServer *api.HttpServer
|
|
}
|
|
|
|
func (g *GrafanaServerImpl) Start() {
|
|
go listenToSystemSignals(g)
|
|
|
|
g.initLogging()
|
|
g.writePIDFile()
|
|
|
|
initSql()
|
|
|
|
metrics.Init(setting.Cfg)
|
|
search.Init()
|
|
login.Init()
|
|
social.NewOAuthService()
|
|
plugins.Init()
|
|
|
|
if err := provisioning.StartUp(setting.DatasourcesPath); err != nil {
|
|
logger.Error("Failed to provision Grafana from config", "error", err)
|
|
g.Shutdown(1, "Startup failed")
|
|
return
|
|
}
|
|
|
|
closer, err := tracing.Init(setting.Cfg)
|
|
if err != nil {
|
|
g.log.Error("Tracing settings is not valid", "error", err)
|
|
g.Shutdown(1, "Startup failed")
|
|
return
|
|
}
|
|
defer closer.Close()
|
|
|
|
// init alerting
|
|
if setting.AlertingEnabled && setting.ExecuteAlerts {
|
|
engine := alerting.NewEngine()
|
|
g.childRoutines.Go(func() error { return engine.Run(g.context) })
|
|
}
|
|
|
|
// cleanup service
|
|
cleanUpService := cleanup.NewCleanUpService()
|
|
g.childRoutines.Go(func() error { return cleanUpService.Run(g.context) })
|
|
|
|
if err = notifications.Init(); err != nil {
|
|
g.log.Error("Notification service failed to initialize", "error", err)
|
|
g.Shutdown(1, "Startup failed")
|
|
return
|
|
}
|
|
|
|
util.SdNotify("READY=1")
|
|
g.startHttpServer()
|
|
}
|
|
|
|
func initSql() {
|
|
sqlstore.NewEngine()
|
|
sqlstore.EnsureAdminUser()
|
|
}
|
|
|
|
func (g *GrafanaServerImpl) initLogging() {
|
|
err := setting.NewConfigContext(&setting.CommandLineArgs{
|
|
Config: *configFile,
|
|
HomePath: *homePath,
|
|
Args: flag.Args(),
|
|
})
|
|
|
|
if err != nil {
|
|
g.log.Error(err.Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
g.log.Info("Starting Grafana", "version", version, "commit", commit, "compiled", time.Unix(setting.BuildStamp, 0))
|
|
setting.LogConfigurationInfo()
|
|
}
|
|
|
|
func (g *GrafanaServerImpl) startHttpServer() {
|
|
g.httpServer = api.NewHttpServer()
|
|
|
|
err := g.httpServer.Start(g.context)
|
|
|
|
if err != nil {
|
|
g.log.Error("Fail to start server", "error", err)
|
|
g.Shutdown(1, "Startup failed")
|
|
return
|
|
}
|
|
}
|
|
|
|
func (g *GrafanaServerImpl) Shutdown(code int, reason string) {
|
|
g.log.Info("Shutdown started", "code", code, "reason", reason)
|
|
|
|
err := g.httpServer.Shutdown(g.context)
|
|
if err != nil {
|
|
g.log.Error("Failed to shutdown server", "error", err)
|
|
}
|
|
|
|
g.shutdownFn()
|
|
err = g.childRoutines.Wait()
|
|
|
|
g.log.Info("Shutdown completed", "reason", err)
|
|
log.Close()
|
|
os.Exit(code)
|
|
}
|
|
|
|
func (g *GrafanaServerImpl) writePIDFile() {
|
|
if *pidFile == "" {
|
|
return
|
|
}
|
|
|
|
// Ensure the required directory structure exists.
|
|
err := os.MkdirAll(filepath.Dir(*pidFile), 0700)
|
|
if err != nil {
|
|
g.log.Error("Failed to verify pid directory", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Retrieve the PID and write it.
|
|
pid := strconv.Itoa(os.Getpid())
|
|
if err := ioutil.WriteFile(*pidFile, []byte(pid), 0644); err != nil {
|
|
g.log.Error("Failed to write pidfile", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
g.log.Info("Writing PID file", "path", *pidFile, "pid", pid)
|
|
}
|