feat: Implement simple page metrics
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				ci/woodpecker/push/woodpecker Pipeline was successful
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	ci/woodpecker/push/woodpecker Pipeline was successful
				
			This commit is contained in:
		
							parent
							
								
									0341ed8219
								
							
						
					
					
						commit
						8f09aa959b
					
				@ -24,7 +24,7 @@ import (
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func handleSubdomain(pagesDomain, domain, cname, path, giteaUrl, defaultCsp string, giteaClient *repo.GiteaClient, w http.ResponseWriter) {
 | 
			
		||||
func handleSubdomain(pagesDomain, domain, cname, path, giteaUrl, defaultCsp string, giteaClient *repo.GiteaClient, lokiConfig *pages.LokiMetricConfig, w http.ResponseWriter) {
 | 
			
		||||
	username := ""
 | 
			
		||||
	if cname != "" {
 | 
			
		||||
		// If we are accessed via a CNAME, then CNAME contains our <user>.<pages domain> value.
 | 
			
		||||
@ -60,10 +60,10 @@ func handleSubdomain(pagesDomain, domain, cname, path, giteaUrl, defaultCsp stri
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pages.ServeFile(username, repo.Name, path, defaultCsp, giteaClient, w)
 | 
			
		||||
	pages.ServeFile(username, repo.Name, path, defaultCsp, domain, giteaClient, lokiConfig, w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Handler(pagesDomain, giteaUrl, defaultCsp string, giteaClient *repo.GiteaClient) http.HandlerFunc {
 | 
			
		||||
func Handler(pagesDomain, giteaUrl, defaultCsp string, giteaClient *repo.GiteaClient, lokiConfig *pages.LokiMetricConfig) http.HandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
		w.Header().Set("Server", "rio")
 | 
			
		||||
 | 
			
		||||
@ -79,7 +79,7 @@ func Handler(pagesDomain, giteaUrl, defaultCsp string, giteaClient *repo.GiteaCl
 | 
			
		||||
		// Is a direct subdomain requested?
 | 
			
		||||
		if strings.HasSuffix(req.Host, pagesDomain) {
 | 
			
		||||
			log.Debug("Domain can be directly handled")
 | 
			
		||||
			handleSubdomain(pagesDomain, req.Host, "", req.URL.Path, giteaUrl, defaultCsp, giteaClient, w)
 | 
			
		||||
			handleSubdomain(pagesDomain, req.Host, "", req.URL.Path, giteaUrl, defaultCsp, giteaClient, lokiConfig, w)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ func Handler(pagesDomain, giteaUrl, defaultCsp string, giteaClient *repo.GiteaCl
 | 
			
		||||
		//       pages domain makes no sense.
 | 
			
		||||
		if strings.HasSuffix(cname, "."+pagesDomain) {
 | 
			
		||||
			log.Debugf("%s is alias of %s and can be handled after a CNAME query", req.Host, cname)
 | 
			
		||||
			handleSubdomain(pagesDomain, req.Host, cname, req.URL.Path, giteaUrl, defaultCsp, giteaClient, w)
 | 
			
		||||
			handleSubdomain(pagesDomain, req.Host, cname, req.URL.Path, giteaUrl, defaultCsp, giteaClient, lokiConfig, w)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -131,6 +131,7 @@ func runServer(ctx *cli.Context) error {
 | 
			
		||||
	acmeDnsProvider := ctx.String("acme-dns-provider")
 | 
			
		||||
	acmeDisable := ctx.Bool("acme-disable")
 | 
			
		||||
	defaultCsp := ctx.String("default-csp")
 | 
			
		||||
	lokiUrl := ctx.String("loki-url")
 | 
			
		||||
 | 
			
		||||
	// Init Logging
 | 
			
		||||
	if ctx.Bool("debug") {
 | 
			
		||||
@ -139,6 +140,19 @@ func runServer(ctx *cli.Context) error {
 | 
			
		||||
		log.SetLevel(log.InfoLevel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Set up the Loki metrics
 | 
			
		||||
	var lokiConfig pages.LokiMetricConfig
 | 
			
		||||
	if lokiUrl == "" {
 | 
			
		||||
		lokiConfig = pages.LokiMetricConfig{
 | 
			
		||||
			Enabled: false,
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		lokiConfig = pages.LokiMetricConfig{
 | 
			
		||||
			Enabled: true,
 | 
			
		||||
			Url:     lokiUrl,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Setup the Gitea stuff
 | 
			
		||||
	httpClient := http.Client{Timeout: 10 * time.Second}
 | 
			
		||||
	giteaApiClient, err := gitea.NewClient(
 | 
			
		||||
@ -240,7 +254,7 @@ func runServer(ctx *cli.Context) error {
 | 
			
		||||
		defer waitGroup.Done()
 | 
			
		||||
 | 
			
		||||
		log.Debug("Listening on main HTTP server")
 | 
			
		||||
		if err := http.Serve(listener, Handler(domain, giteaUrl, defaultCsp, &giteaClient)); err != nil {
 | 
			
		||||
		if err := http.Serve(listener, Handler(domain, giteaUrl, defaultCsp, &giteaClient, &lokiConfig)); err != nil {
 | 
			
		||||
			log.Fatal(fmt.Errorf("Listening failed: %v", err))
 | 
			
		||||
		}
 | 
			
		||||
		log.Debug("Listening on main HTTP server done!")
 | 
			
		||||
@ -350,6 +364,12 @@ func main() {
 | 
			
		||||
				Value:   "",
 | 
			
		||||
				EnvVars: []string{"DEFAULT_CSP"},
 | 
			
		||||
			},
 | 
			
		||||
			&cli.StringFlag{
 | 
			
		||||
				Name:    "loki-url",
 | 
			
		||||
				Usage:   "The URL for Loki metric pings",
 | 
			
		||||
				Value:   "",
 | 
			
		||||
				EnvVars: []string{"LOKI_URL"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								internal/pages/metrics.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								internal/pages/metrics.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
package pages
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LokiMetricConfig struct {
 | 
			
		||||
	Url     string
 | 
			
		||||
	Enabled bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Checks if we should send a metric ping to Loki based on the served path.
 | 
			
		||||
func (c *LokiMetricConfig) shouldSendMetrics(path string) bool {
 | 
			
		||||
	return strings.HasSuffix(path, ".html") && c.Enabled
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *LokiMetricConfig) sendMetricPing(domain, path string) {
 | 
			
		||||
	data := map[string]interface{}{
 | 
			
		||||
		"steams": []map[string]interface{}{
 | 
			
		||||
			{
 | 
			
		||||
				"stream": map[string]string{
 | 
			
		||||
					// Labels
 | 
			
		||||
					"service": "rio",
 | 
			
		||||
					"domain":  domain,
 | 
			
		||||
					"type":    "metric",
 | 
			
		||||
				},
 | 
			
		||||
				"values": [][]interface{}{
 | 
			
		||||
					{
 | 
			
		||||
						strconv.Itoa(int(time.Now().UnixNano())),
 | 
			
		||||
						"path=" + path,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	jsonData, err := json.Marshal(data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("Failed to send metric ping to Loki: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send the ping to the Loki server
 | 
			
		||||
	go func() {
 | 
			
		||||
		http.Post(
 | 
			
		||||
			c.Url,
 | 
			
		||||
			"application/json",
 | 
			
		||||
			strings.NewReader(string(jsonData)),
 | 
			
		||||
		)
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
@ -45,7 +45,7 @@ func addHeaders(csp, contentType string, contentLength int, w http.ResponseWrite
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ServeFile(username, reponame, path, defaultCsp string, giteaClient *repo.GiteaClient, w http.ResponseWriter) {
 | 
			
		||||
func ServeFile(username, reponame, path, defaultCsp, domain string, giteaClient *repo.GiteaClient, metricConfig *LokiMetricConfig, w http.ResponseWriter) {
 | 
			
		||||
	// Strip away a starting / as it messes with Gitea
 | 
			
		||||
	if path[:1] == "/" {
 | 
			
		||||
		path = path[1:]
 | 
			
		||||
@ -116,4 +116,9 @@ func ServeFile(username, reponame, path, defaultCsp string, giteaClient *repo.Gi
 | 
			
		||||
	addHeaders(csp, mimeType, len(content), w)
 | 
			
		||||
	w.WriteHeader(200)
 | 
			
		||||
	w.Write(content)
 | 
			
		||||
 | 
			
		||||
	// Tell Loki about if, if desired
 | 
			
		||||
	if metricConfig.shouldSendMetrics(path) {
 | 
			
		||||
		metricConfig.sendMetricPing(domain, path)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user