From 884dd94242bfca687c8ff84cda22daf08b467248 Mon Sep 17 00:00:00 2001 From: Amir Raminfar Date: Mon, 2 Jan 2023 09:28:27 -0800 Subject: [PATCH] Adds analytics for requests made (#1999) --- analytics/ga.go | 20 +++++++++++++++++++- analytics/types.go | 6 ++++++ main.go | 1 + web/routes.go | 36 ++++++++++++++++++++++++++++++------ web/routes_test.go | 1 + 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/analytics/ga.go b/analytics/ga.go index 361e4091..5be07b24 100644 --- a/analytics/ga.go +++ b/analytics/ga.go @@ -21,7 +21,25 @@ func SendStartEvent(se StartEvent) error { }, } - jsonValue, err := json.Marshal(postBody) + return doRequest(postBody) +} + +func SendRequestEvent(re RequestEvent) error { + postBody := map[string]interface{}{ + "client_id": re.ClientId, + "events": []map[string]interface{}{ + { + "name": "request", + "params": re, + }, + }, + } + + return doRequest(postBody) +} + +func doRequest(body map[string]interface{}) error { + jsonValue, err := json.Marshal(body) if err != nil { return err } diff --git a/analytics/types.go b/analytics/types.go index d3d1f1ff..6368ce78 100644 --- a/analytics/types.go +++ b/analytics/types.go @@ -9,3 +9,9 @@ type StartEvent struct { Protected bool `json:"protected"` HasHostname bool `json:"hasHostname"` } + +type RequestEvent struct { + ClientId string `json:"-"` + TotalContainers int `json:"totalContainers"` + RunningContainers int `json:"runningContainers"` +} diff --git a/main.go b/main.go index 9678abd9..01815e97 100644 --- a/main.go +++ b/main.go @@ -126,6 +126,7 @@ func main() { Username: args.Username, Password: args.Password, Hostname: args.Hostname, + NoAnalytics: args.NoAnalytics, } assets, err := fs.Sub(content, "dist") diff --git a/web/routes.go b/web/routes.go index 49570a75..7b6d7898 100644 --- a/web/routes.go +++ b/web/routes.go @@ -6,8 +6,10 @@ import ( "io/fs" "io/ioutil" "net/http" + "os" "path" + "github.com/amir20/dozzle/analytics" "github.com/amir20/dozzle/docker" "github.com/gorilla/mux" @@ -16,12 +18,13 @@ import ( // Config is a struct for configuring the web service type Config struct { - Base string - Addr string - Version string - Username string - Password string - Hostname string + Base string + Addr string + Version string + Username string + Password string + Hostname string + NoAnalytics bool } type handler struct { @@ -78,6 +81,27 @@ func (h *handler) index(w http.ResponseWriter, req *http.Request) { _, err := h.content.Open(req.URL.Path) if err == nil && req.URL.Path != "" && req.URL.Path != "/" { fileServer.ServeHTTP(w, req) + if !h.config.NoAnalytics { + go func() { + host, _ := os.Hostname() + + if containers, err := h.client.ListContainers(); err == nil { + totalContainers := len(containers) + runningContainers := 0 + for _, container := range containers { + if container.State == "running" { + runningContainers++ + } + } + re := analytics.RequestEvent{ + ClientId: host, + TotalContainers: totalContainers, + RunningContainers: runningContainers, + } + analytics.SendRequestEvent(re) + } + }() + } } else { if !isAuthorized(req) && req.URL.Path != "login" { http.Redirect(w, req, path.Clean(h.config.Base+"/login"), http.StatusTemporaryRedirect) diff --git a/web/routes_test.go b/web/routes_test.go index c9308a6b..fafa036e 100644 --- a/web/routes_test.go +++ b/web/routes_test.go @@ -434,6 +434,7 @@ func Test_createRoutes_username_password_invalid_session(t *testing.T) { func createHandler(client docker.Client, content fs.FS, config Config) *mux.Router { if client == nil { client = new(MockedClient) + client.(*MockedClient).On("ListContainers").Return([]docker.Container{}, nil) } if content == nil {