-
-
Notifications
You must be signed in to change notification settings - Fork 151
/
stat.go
129 lines (99 loc) · 3.45 KB
/
stat.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package integram
import (
"fmt"
"gopkg.in/mgo.v2/bson"
"time"
)
type StatKey string
const (
StatInlineQueryAnswered StatKey = "iq_answered"
StatInlineQueryNotAnswered StatKey = "iq_not_answered"
StatInlineQueryTimeouted StatKey = "iq_timeouted"
StatInlineQueryCanceled StatKey = "iq_canceled"
StatInlineQueryChosen StatKey = "iq_chosen"
StatInlineQueryProcessingError StatKey = "iq_error"
StatWebhookHandled StatKey = "wh_handled"
StatWebhookProducedMessageToChat StatKey = "wh_message"
StatWebhookProcessingError StatKey = "wh_error"
StatIncomingMessageAnswered StatKey = "im_replied"
StatIncomingMessageNotAnswered StatKey = "im_not_replied"
StatOAuthSuccess StatKey = "oauth_success"
)
type stat struct {
Service string `bson:"s"`
DayN uint16 `bson:"d"` // Days since unix epoch (Unix TS)/(24*60*60)
Key StatKey `bson:"k"`
Counter uint32 `bson:"v"`
UniqueCounter uint32 `bson:"uv"`
Series5m map[string]uint32 `bson:"v5m"`
UniqueSeries5m map[string]uint32 `bson:"uv5m"`
}
// count only once per user/chat per period
type uniqueStat struct {
Service string `bson:"s"`
DayN uint16 // Days since unix epoch (Unix TS)/(24*60*60)
Key StatKey `bson:"k"`
PeriodN uint16 `bson:"p"` // -1 for the whole day period
IDS []int64 `bson:"u"`
ExpiresAt time.Time `bson:"exp"`
}
func (c *Context) StatIncBy(key StatKey, uniqueID int64, inc int) error {
if !Config.MongoStatistic {
return nil
}
n := time.Now()
unixDay := uint16(n.Unix() / (24 * 60 * 60))
//id := generateStatID(c.Bot().ID, key, unixDay)
requesterID := c.User.ID
if requesterID == 0 {
requesterID = c.Chat.ID
}
startOfTheDayTS := int64(unixDay) * 24 * 60 * 60
periodN := int((n.Unix() - startOfTheDayTS) / (60 * 5)) // number of 5min period within a day
updateInc := bson.M{
"v": inc,
fmt.Sprintf("v5m.%d", periodN): inc,
}
if uniqueID != 0 {
// check the ID uniqueness for the current day
ci, err := c.Db().C("stats_unique").Upsert(
bson.M{"s": c.ServiceName, "k": key, "d": unixDay, "p": -1, "u": bson.M{"$ne": uniqueID}},
bson.M{
"$push": bson.M{
"u": uniqueID,
},
"$setOnInsert": bson.M{"exp": time.Unix(startOfTheDayTS+24*60*60, 0)},
})
if err == nil && (ci.Matched > 0 || ci.UpsertedId != nil) {
// this ID wasn't found for the current day. So we can add to both overall and 5min period
updateInc["uv"] = 1
}
// check the ID uniqueness for the current 5min period
ci, err = c.Db().C("stats_unique").Upsert(
bson.M{"s": c.ServiceName, "k": key, "d": unixDay, "p": periodN, "u": bson.M{"$ne": uniqueID}},
bson.M{
"$push": bson.M{
"u": requesterID,
},
"$setOnInsert": bson.M{"exp": time.Unix(startOfTheDayTS+24*60*60, 0)},
})
if err == nil && (ci.Matched > 0 || ci.UpsertedId != nil) {
// this ID wasn't found for the current day. So we can add to both overall and 5min period
updateInc[fmt.Sprintf("uv5m.%d", periodN)] = 1
}
}
_, err := c.Db().C("stats").Upsert(bson.M{"s": c.ServiceName, "k": key, "d": unixDay}, bson.M{
"$inc": updateInc,
"$setOnInsert": bson.M{"s": c.ServiceName, "d": unixDay, "k": key},
})
return err
}
func (c *Context) StatInc(key StatKey) error {
return c.StatIncBy(key, 0, 1)
}
func (c *Context) StatIncChat(key StatKey) error {
return c.StatIncBy(key, c.Chat.ID, 1)
}
func (c *Context) StatIncUser(key StatKey) error {
return c.StatIncBy(key, c.User.ID, 1)
}