Skip to content

Commit 7a499b7

Browse files
committed
Add JSON export
The old CSV export works only if you have collection of individual pageviews enabled in the settings, which is disabled by default now. So directly export the data and stats tables, and insert them directly. TODO: kind of works, but needs some work to not be ugly and fragile. Ideally a lot of this can/should be merged with how cron works.
1 parent dca131d commit 7a499b7

File tree

9 files changed

+799
-26
lines changed

9 files changed

+799
-26
lines changed

e.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package goatcounter
2+
3+
import (
4+
"time"
5+
6+
"zgo.at/json"
7+
)
8+
9+
type (
10+
ExportInfo struct {
11+
CreatedAt time.Time `json:"created_at"`
12+
Version int `json:"version"`
13+
Site string `json:"site"`
14+
}
15+
ExportLanguage struct {
16+
ISO6393 string `db:"iso_639_3" json:"iso_639_3"`
17+
Name string `db:"name" json:"name"`
18+
}
19+
ExportBrowserStat struct {
20+
Day string `db:"day" json:"day"`
21+
PathID PathID `db:"path_id" json:"path_id"`
22+
BrowserID BrowserID `db:"browser_id" json:"browser_id"`
23+
Count int `db:"count" json:"count"`
24+
}
25+
ExportSystemStat struct {
26+
Day string `db:"day" json:"day"`
27+
PathID PathID `db:"path_id" json:"path_id"`
28+
SystemID SystemID `db:"system_id" json:"system_id"`
29+
Count int `db:"count" json:"count"`
30+
}
31+
ExportLocationStat struct {
32+
Day string `db:"day" json:"day"`
33+
PathID PathID `db:"path_id" json:"path_id"`
34+
Location string `db:"location" json:"location"`
35+
Count int `db:"count" json:"count"`
36+
}
37+
ExportSizeStat struct {
38+
Day string `db:"day" json:"day"`
39+
PathID PathID `db:"path_id" json:"path_id"`
40+
Width int `db:"width" json:"width"`
41+
Count int `db:"count" json:"count"`
42+
}
43+
ExportLanguageStat struct {
44+
Day string `db:"day" json:"day"`
45+
PathID PathID `db:"path_id" json:"path_id"`
46+
Language string `db:"language" json:"language"`
47+
Count int `db:"count" json:"count"`
48+
}
49+
ExportCampaignStat struct {
50+
Day string `db:"day" json:"day"`
51+
PathID PathID `db:"path_id" json:"path_id"`
52+
CampaignID CampaignID `db:"campaign_id" json:"campaign_id"`
53+
Ref string `db:"ref" json:"ref"`
54+
Count int `db:"count" json:"count"`
55+
}
56+
ExportHitStat struct {
57+
Day string `db:"day" json:"day"`
58+
PathID PathID `db:"path_id" json:"path_id"`
59+
//Stats Stat `db:"stats" json:"stats"`
60+
Stats json.RawMessage `db:"stats" json:"stats"`
61+
}
62+
ExportRefStat struct {
63+
Hour string `db:"hour" json:"hour"`
64+
PathID PathID `db:"path_id" json:"path_id"`
65+
RefID RefID `db:"ref_id" json:"ref_id"`
66+
Count int `db:"total" json:"count"`
67+
}
68+
)

export.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ func (e Export) Exists() bool {
4949
if e.Path == "" {
5050
return false
5151
}
52-
5352
_, err := os.Stat(e.Path)
5453
return err == nil
5554
}

exportcsv.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,23 @@ func (e *Export) CreateCSV(ctx context.Context, startFrom HitID) (*os.File, erro
4242
`insert into exports (site_id, path, created_at, start_from_hit_id) values (?, ?, ?, ?)`,
4343
e.SiteID, e.Path, e.CreatedAt, e.StartFromHitID)
4444
if err != nil {
45-
return nil, errors.Wrap(err, "Export.Create")
45+
return nil, errors.Wrap(err, "Export.CreateCSV")
4646
}
4747

4848
fp, err := os.Create(e.Path)
49-
return fp, errors.Wrap(err, "Export.Create")
49+
return fp, errors.Wrap(err, "Export.CreateCSV")
5050
}
5151

5252
// Export all data to a CSV file.
5353
func (e *Export) RunCSV(ctx context.Context, fp *os.File, mailUser bool) {
5454
l := log.Module("export").With("id", e.ID)
55-
l.Info(ctx, "export started")
55+
l.Info(ctx, "CSV export started")
5656

5757
gzfp := gzip.NewWriter(fp)
58-
defer fp.Close() // No need to error-check; just for safety.
59-
defer gzfp.Close()
58+
defer func() {
59+
gzfp.Close()
60+
fp.Close()
61+
}()
6062

6163
c := csv.NewWriter(gzfp)
6264
c.Write([]string{ExportCSVVersion + "Path", "Title", "Event", "UserAgent",
@@ -104,11 +106,10 @@ func (e *Export) RunCSV(ctx context.Context, fp *os.File, mailUser bool) {
104106

105107
if exportErr != nil {
106108
l.Error(ctx, exportErr, "export", e)
107-
err := zdb.Exec(ctx,
108-
`update exports set error=$1 where export_id=$2`,
109+
err := zdb.Exec(ctx, `update exports set error=$1 where export_id=$2`,
109110
exportErr.Error(), e.ID)
110111
if err != nil {
111-
log.Error(ctx, err)
112+
l.Error(ctx, err)
112113
}
113114

114115
_ = gzfp.Close()
@@ -122,12 +123,12 @@ func (e *Export) RunCSV(ctx context.Context, fp *os.File, mailUser bool) {
122123
l.Error(ctx, err)
123124
return
124125
}
126+
125127
err = fp.Sync() // Ensure stat is correct.
126128
if err != nil {
127129
l.Error(ctx, err)
128130
return
129131
}
130-
131132
stat, err := fp.Stat()
132133
size := "0"
133134
if err == nil {
@@ -157,7 +158,7 @@ func (e *Export) RunCSV(ctx context.Context, fp *os.File, mailUser bool) {
157158
where export_id=$6`,
158159
&now, e.NumRows, e.Size, e.Hash, e.LastHitID, e.ID)
159160
if err != nil {
160-
log.Error(ctx, err)
161+
l.Error(ctx, err)
161162
}
162163

163164
if mailUser {

0 commit comments

Comments
 (0)