Merge pull request #18 from Kugelschieber/tracking

Tracking
This commit is contained in:
Marvin Blum
2020-09-14 21:47:18 +02:00
committed by GitHub
7 changed files with 93 additions and 21 deletions

2
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emvi/api-go v0.2.2 github.com/emvi/api-go v0.2.2
github.com/emvi/logbuch v1.1.1 github.com/emvi/logbuch v1.1.1
github.com/emvi/pirsch v1.5.1 github.com/emvi/pirsch v1.5.3-0.20200914194223-a990d20e91a2
github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/golang-migrate/migrate v3.5.4+incompatible github.com/golang-migrate/migrate v3.5.4+incompatible
github.com/golang-migrate/migrate/v4 v4.12.2 github.com/golang-migrate/migrate/v4 v4.12.2

4
go.sum
View File

@@ -100,6 +100,10 @@ github.com/emvi/pirsch v1.5.1-0.20200911122906-93d727c607a9 h1:H1+nLRJsBy1ZuhBP4
github.com/emvi/pirsch v1.5.1-0.20200911122906-93d727c607a9/go.mod h1:GDijqLHM331iWtmDmc7th19RxDrZadRkKoNvd9/kDX8= github.com/emvi/pirsch v1.5.1-0.20200911122906-93d727c607a9/go.mod h1:GDijqLHM331iWtmDmc7th19RxDrZadRkKoNvd9/kDX8=
github.com/emvi/pirsch v1.5.1 h1:HFlR5Ps2mPFqHGkFvEfHLme6beCn5aIpu/fCNz/B43Y= github.com/emvi/pirsch v1.5.1 h1:HFlR5Ps2mPFqHGkFvEfHLme6beCn5aIpu/fCNz/B43Y=
github.com/emvi/pirsch v1.5.1/go.mod h1:GDijqLHM331iWtmDmc7th19RxDrZadRkKoNvd9/kDX8= github.com/emvi/pirsch v1.5.1/go.mod h1:GDijqLHM331iWtmDmc7th19RxDrZadRkKoNvd9/kDX8=
github.com/emvi/pirsch v1.5.2 h1:fKGTOngDbVFhbzhbXy2NbaeZrVYSiIoDVy+dce0agFs=
github.com/emvi/pirsch v1.5.2/go.mod h1:GDijqLHM331iWtmDmc7th19RxDrZadRkKoNvd9/kDX8=
github.com/emvi/pirsch v1.5.3-0.20200914194223-a990d20e91a2 h1:HoKxeUtA0E4QVuw2kaR4TioT2OZPIzXQ2rA6EJ3GRTM=
github.com/emvi/pirsch v1.5.3-0.20200914194223-a990d20e91a2/go.mod h1:GDijqLHM331iWtmDmc7th19RxDrZadRkKoNvd9/kDX8=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=

View File

@@ -123,7 +123,7 @@ func serveTracking() http.HandlerFunc {
} }
activeVisitorPages, activeVisitors := tracking.GetActiveVisitors() activeVisitorPages, activeVisitors := tracking.GetActiveVisitors()
totalVisitorsLabels, totalVisitorsDps := tracking.GetTotalVisitors(startDate, endDate) totalVisitorsLabels, totalVisitorsDps, sessionsDps, bouncesDps := tracking.GetTotalVisitors(startDate, endDate)
hourlyVisitorsTodayLabels, hourlyVisitorsTodayDps := tracking.GetHourlyVisitorsToday() hourlyVisitorsTodayLabels, hourlyVisitorsTodayDps := tracking.GetHourlyVisitorsToday()
pageVisitors, pageRank := tracking.GetPageVisits(startDate, endDate) pageVisitors, pageRank := tracking.GetPageVisits(startDate, endDate)
tplCache.RenderWithoutCache(w, "tracking.html", struct { tplCache.RenderWithoutCache(w, "tracking.html", struct {
@@ -132,6 +132,8 @@ func serveTracking() http.HandlerFunc {
EndDate time.Time EndDate time.Time
TotalVisitorsLabels template.JS TotalVisitorsLabels template.JS
TotalVisitorsDps template.JS TotalVisitorsDps template.JS
SessionsDps template.JS
BouncesDps template.JS
PageVisitors []tracking.PageVisitors PageVisitors []tracking.PageVisitors
PageRank []tracking.PageVisitors PageRank []tracking.PageVisitors
Languages []pirsch.LanguageStats Languages []pirsch.LanguageStats
@@ -149,6 +151,8 @@ func serveTracking() http.HandlerFunc {
endDate, endDate,
totalVisitorsLabels, totalVisitorsLabels,
totalVisitorsDps, totalVisitorsDps,
sessionsDps,
bouncesDps,
pageVisitors, pageVisitors,
pageRank, pageRank,
tracking.GetLanguages(startDate, endDate), tracking.GetLanguages(startDate, endDate),

View File

@@ -0,0 +1,23 @@
ALTER TABLE "hit" ADD COLUMN "screen_width" integer DEFAULT 0;
ALTER TABLE "hit" ADD COLUMN "screen_height" integer DEFAULT 0;
CREATE TABLE "screen_stats" (
id bigint NOT NULL UNIQUE,
tenant_id bigint,
day date NOT NULL,
visitors integer NOT NULL,
width integer NOT NULL,
height integer NOT NULL
);
CREATE SEQUENCE screen_stats_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE screen_stats_id_seq OWNED BY "screen_stats".id;
ALTER TABLE ONLY "screen_stats" ALTER COLUMN id SET DEFAULT nextval('screen_stats_id_seq'::regclass);
ALTER TABLE ONLY "screen_stats" ADD CONSTRAINT screen_stats_pkey PRIMARY KEY (id);
CREATE INDEX screen_stats_day_index ON screen_stats(day);

View File

@@ -234,12 +234,26 @@
type: "line", type: "line",
data: { data: {
labels: [{{.TotalVisitorsLabels}}], labels: [{{.TotalVisitorsLabels}}],
datasets: [{ datasets: [
backgroundColor: "rgba(127, 127, 127, 0.05)", {
borderColor: "#7f7f7f", backgroundColor: "rgb(43, 180, 0, 0.02)",
label: "Total Visitors", borderColor: "rgb(40, 152, 0, 0.5)",
data: [{{.TotalVisitorsDps}}] label: "Total Visitors",
}] data: [{{.TotalVisitorsDps}}]
},
{
backgroundColor: "rgb(0, 63, 197, 0.02)",
borderColor: "rgb(0, 53, 159, 0.5)",
label: "Sessions",
data: [{{.SessionsDps}}]
},
{
backgroundColor: "rgba(194, 0, 0, 0.02)",
borderColor: "rgb(152, 0, 0, 0.5)",
label: "Bounces",
data: [{{.BouncesDps}}]
}
]
} }
}); });
@@ -263,12 +277,26 @@
type: "line", type: "line",
data: { data: {
labels: [{{$data.Labels}}], labels: [{{$data.Labels}}],
datasets: [{ datasets: [
backgroundColor: "rgba(127, 127, 127, 0.05)", {
borderColor: "#7f7f7f", backgroundColor: "rgb(43, 180, 0, 0.02)",
label: "Page Visits", borderColor: "rgb(40, 152, 0, 0.5)",
data: [{{$data.Data}}] label: "Page Visits",
}] data: [{{$data.Data}}]
},
{
backgroundColor: "rgb(0, 63, 197, 0.02)",
borderColor: "rgb(0, 53, 159, 0.5)",
label: "Sessions",
data: [{{$data.Sessions}}]
},
{
backgroundColor: "rgba(194, 0, 0, 0.02)",
borderColor: "rgb(152, 0, 0, 0.5)",
label: "Bounces",
data: [{{$data.Bounces}}]
}
]
} }
}); });
{{end}} {{end}}

View File

@@ -19,6 +19,8 @@ type PageVisitors struct {
Visitors int Visitors int
Labels template.JS Labels template.JS
Data template.JS Data template.JS
Sessions template.JS
Bounces template.JS
} }
func GetActiveVisitors() ([]pirsch.Stats, int) { func GetActiveVisitors() ([]pirsch.Stats, int) {
@@ -43,12 +45,12 @@ func GetHourlyVisitorsToday() (template.JS, template.JS) {
return getLabelsAndDataHourly(visitors) return getLabelsAndDataHourly(visitors)
} }
func GetTotalVisitors(startDate, endDate time.Time) (template.JS, template.JS) { func GetTotalVisitors(startDate, endDate time.Time) (template.JS, template.JS, template.JS, template.JS) {
visitors, err := analyzer.Visitors(&pirsch.Filter{From: startDate, To: endDate}) visitors, err := analyzer.Visitors(&pirsch.Filter{From: startDate, To: endDate})
if err != nil { if err != nil {
logbuch.Error("Error reading visitor statistics", logbuch.Fields{"err": err}) logbuch.Error("Error reading visitor statistics", logbuch.Fields{"err": err})
return "", "" return "", "", "", ""
} }
return getLabelsAndData(visitors) return getLabelsAndData(visitors)
@@ -65,12 +67,14 @@ func GetPageVisits(startDate, endDate time.Time) ([]PageVisitors, []PageVisitors
pageVisitors := make([]PageVisitors, len(visits)) pageVisitors := make([]PageVisitors, len(visits))
for i, visit := range visits { for i, visit := range visits {
labels, data := getLabelsAndData(visit.Stats) labels, data, sessions, bounces := getLabelsAndData(visit.Stats)
pageVisitors[i] = PageVisitors{ pageVisitors[i] = PageVisitors{
Path: visit.Path, Path: visit.Path,
Visitors: sumVisitors(visit.Stats), Visitors: sumVisitors(visit.Stats),
Labels: labels, Labels: labels,
Data: data, Data: data,
Sessions: sessions,
Bounces: bounces,
} }
} }
@@ -148,18 +152,27 @@ func sumVisitors(stats []pirsch.Stats) int {
return sum return sum
} }
func getLabelsAndData(visitors []pirsch.Stats) (template.JS, template.JS) { func getLabelsAndData(visitors []pirsch.Stats) (template.JS, template.JS, template.JS, template.JS) {
var labels strings.Builder var labels strings.Builder
var dp strings.Builder var dp strings.Builder
var sessions strings.Builder
var bounces strings.Builder
for _, point := range visitors { for _, point := range visitors {
labels.WriteString(fmt.Sprintf("'%s',", point.Day.Format(statisticsDateFormat))) labels.WriteString(fmt.Sprintf("'%s',", point.Day.Format(statisticsDateFormat)))
dp.WriteString(fmt.Sprintf("%d,", point.Visitors)) dp.WriteString(fmt.Sprintf("%d,", point.Visitors))
sessions.WriteString(fmt.Sprintf("%d,", point.Sessions))
bounces.WriteString(fmt.Sprintf("%d,", point.Bounces))
} }
labelsStr := labels.String() labelsStr := labels.String()
dataStr := dp.String() dataStr := dp.String()
return template.JS(labelsStr[:len(labelsStr)-1]), template.JS(dataStr[:len(dataStr)-1]) sessionsStr := sessions.String()
bouncesStr := bounces.String()
return template.JS(labelsStr[:len(labelsStr)-1]),
template.JS(dataStr[:len(dataStr)-1]),
template.JS(sessionsStr[:len(sessionsStr)-1]),
template.JS(bouncesStr[:len(bouncesStr)-1])
} }
func getLabelsAndDataHourly(visitors []pirsch.VisitorTimeStats) (template.JS, template.JS) { func getLabelsAndDataHourly(visitors []pirsch.VisitorTimeStats) (template.JS, template.JS) {

View File

@@ -30,9 +30,9 @@ func NewTracker() (*pirsch.Tracker, context.CancelFunc) {
store = pirsch.NewPostgresStore(conn, nil) store = pirsch.NewPostgresStore(conn, nil)
tracker := pirsch.NewTracker(store, os.Getenv("MB_TRACKING_SALT"), &pirsch.TrackerConfig{ tracker := pirsch.NewTracker(store, os.Getenv("MB_TRACKING_SALT"), &pirsch.TrackerConfig{
// I don't care about traffic from my own website ReferrerDomainBlacklist: []string{"marvinblum.de"}, // I don't care about traffic from my own website
ReferrerDomainBlacklist: []string{"marvinblum.de"},
ReferrerDomainBlacklistIncludesSubdomains: true, ReferrerDomainBlacklistIncludesSubdomains: true,
Sessions: true,
}) })
analyzer = pirsch.NewAnalyzer(store) analyzer = pirsch.NewAnalyzer(store)
processor := pirsch.NewProcessor(store) processor := pirsch.NewProcessor(store)