github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/server/index.go (about)

     1  package server
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  	"os"
     7  
     8  	"github.com/sirupsen/logrus"
     9  
    10  	"github.com/pyroscope-io/pyroscope/pkg/build"
    11  	"github.com/pyroscope-io/pyroscope/pkg/server/httputils"
    12  	"github.com/pyroscope-io/pyroscope/pkg/util/updates"
    13  )
    14  
    15  type Flags struct {
    16  	EnableAdhocUI                   bool `json:"enableAdhocUI"`
    17  	GoogleEnabled                   bool `json:"googleEnabled"`
    18  	GitlabEnabled                   bool `json:"gitlabEnabled"`
    19  	GithubEnabled                   bool `json:"githubEnabled"`
    20  	InternalAuthEnabled             bool `json:"internalAuthEnabled"`
    21  	SignupEnabled                   bool `json:"signupEnabled"`
    22  	ExportToFlamegraphDotComEnabled bool `json:"exportToFlamegraphDotComEnabled"`
    23  	IsAuthRequired                  bool `json:"isAuthRequired"`
    24  	ExemplarsPageEnabled            bool `json:"exemplarsPageEnabled"`
    25  }
    26  
    27  type IndexHandlerConfig struct {
    28  	Flags   Flags
    29  	BaseURL string
    30  }
    31  
    32  type IndexHandler struct {
    33  	log       *logrus.Logger
    34  	dir       http.FileSystem
    35  	fs        http.Handler
    36  	stats     StatsReceiver
    37  	notifier  Notifier
    38  	cfg       *IndexHandlerConfig
    39  	httpUtils httputils.Utils
    40  }
    41  
    42  func (ctrl *Controller) indexHandler() http.HandlerFunc {
    43  	cfg := &IndexHandlerConfig{
    44  		Flags: Flags{
    45  			EnableAdhocUI:                   !ctrl.config.NoAdhocUI,
    46  			GoogleEnabled:                   ctrl.config.Auth.Google.Enabled,
    47  			GitlabEnabled:                   ctrl.config.Auth.Gitlab.Enabled,
    48  			GithubEnabled:                   ctrl.config.Auth.Github.Enabled,
    49  			InternalAuthEnabled:             ctrl.config.Auth.Internal.Enabled,
    50  			SignupEnabled:                   ctrl.config.Auth.Internal.SignupEnabled,
    51  			ExportToFlamegraphDotComEnabled: !ctrl.config.DisableExportToFlamegraphDotCom,
    52  			IsAuthRequired:                  ctrl.isAuthRequired(),
    53  			ExemplarsPageEnabled:            ctrl.config.EnableExperimentalExemplarsPage,
    54  		},
    55  		BaseURL: ctrl.config.BaseURL,
    56  	}
    57  	return NewIndexHandler(ctrl.log, ctrl.dir, ctrl, ctrl.notifier, cfg, ctrl.httpUtils).ServeHTTP
    58  }
    59  
    60  //revive:disable:argument-limit TODO(petethepig): we will refactor this later
    61  func NewIndexHandler(
    62  	log *logrus.Logger,
    63  	dir http.FileSystem,
    64  	stats StatsReceiver,
    65  	notifier Notifier,
    66  	cfg *IndexHandlerConfig,
    67  	httpUtils httputils.Utils,
    68  ) http.Handler {
    69  	fs := http.FileServer(dir)
    70  	return &IndexHandler{
    71  		log:       log,
    72  		dir:       dir,
    73  		fs:        fs,
    74  		stats:     stats,
    75  		notifier:  notifier,
    76  		cfg:       cfg,
    77  		httpUtils: httpUtils,
    78  	}
    79  }
    80  
    81  func (ih *IndexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    82  	ih.stats.StatsInc("index")
    83  	ih.renderIndexPage(w, r)
    84  }
    85  
    86  func (ih *IndexHandler) renderIndexPage(w http.ResponseWriter, r *http.Request) {
    87  	tmpl, err := getTemplate(ih.dir, "/index.html")
    88  	if err != nil {
    89  		ih.httpUtils.WriteInternalServerError(r, w, err, "could not render index page")
    90  		return
    91  	}
    92  
    93  	var b []byte
    94  	if err != nil {
    95  		ih.httpUtils.WriteJSONEncodeError(r, w, err)
    96  		return
    97  	}
    98  
    99  	var extraMetadataStr string
   100  	extraMetadataPath := os.Getenv("PYROSCOPE_EXTRA_METADATA")
   101  	if extraMetadataPath != "" {
   102  		b, err = os.ReadFile(extraMetadataPath)
   103  		if err != nil {
   104  			logrus.Errorf("failed to read file at %s", extraMetadataPath)
   105  		}
   106  		extraMetadataStr = string(b)
   107  	}
   108  
   109  	// Feature Flags
   110  	// Add this intermediate layer instead of just exposing as it comes from ctrl.config
   111  	// Since we may probably want to rename these flags when exposing to the frontend
   112  	b, err = json.Marshal(ih.cfg.Flags)
   113  	if err != nil {
   114  		ih.httpUtils.WriteJSONEncodeError(r, w, err)
   115  		return
   116  	}
   117  	featuresStr := string(b)
   118  
   119  	w.Header().Add("Content-Type", "text/html")
   120  	mustExecute(tmpl, w, map[string]string{
   121  		"BuildInfo":         build.JSON(),
   122  		"LatestVersionInfo": updates.LatestVersionJSON(),
   123  		"ExtraMetadata":     extraMetadataStr,
   124  		"BaseURL":           ih.cfg.BaseURL,
   125  		"NotificationText":  ih.notifier.NotificationText(),
   126  		"Features":          featuresStr,
   127  	})
   128  }