-
Notifications
You must be signed in to change notification settings - Fork 41
/
telemetry.go
163 lines (142 loc) · 4.04 KB
/
telemetry.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright (c) 2022-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
import (
"encoding/json"
"net/http"
"github.com/mattermost/mattermost-plugin-calls/server/telemetry"
)
const (
// server-side events
evCallStarted = "call_started"
evCallEnded = "call_ended"
evCallUserJoined = "call_user_joined"
evCallUserLeft = "call_user_left"
evCallNotifyAdmin = "call_notify_admin"
)
var (
telemetryClientTypes = []string{"web", "mobile", "desktop"}
telemetryClientEvents = []string{
"user_open_expanded_view",
"user_close_expanded_view",
"user_open_participants_list",
"user_close_participants_list",
"user_share_screen",
"user_unshare_screen",
"user_raise_hand",
"user_lower_hand",
"user_open_channel_link",
"user_start_recording",
"user_stop_recording",
"notification_join",
"notification_dismiss",
"notification_click_goto_channel",
"live_captions_on",
"live_captions_off",
}
telemetryClientTypesMap map[string]struct{}
telemetryClientEventsMap map[string]struct{}
)
func init() {
telemetryClientEventsMap = make(map[string]struct{}, len(telemetryClientEvents))
for _, eventType := range telemetryClientEvents {
telemetryClientEventsMap[eventType] = struct{}{}
}
telemetryClientTypesMap = make(map[string]struct{}, len(telemetryClientTypes))
for _, clientType := range telemetryClientTypes {
telemetryClientTypesMap[clientType] = struct{}{}
}
}
type trackEventRequest struct {
Event string `json:"event"`
ClientType string `json:"clientType"`
Source string `json:"source"`
Props map[string]interface{} `json:"props"`
}
func (p *Plugin) track(ev string, props map[string]interface{}) {
p.mut.RLock()
defer p.mut.RUnlock()
if p.telemetry == nil {
return
}
if err := p.telemetry.Track(ev, props); err != nil {
p.LogError(err.Error())
}
}
func (p *Plugin) uninitTelemetry() error {
p.mut.Lock()
defer p.mut.Unlock()
if p.telemetry == nil {
return nil
}
return p.telemetry.Close()
}
func (p *Plugin) initTelemetry(enableDiagnostics *bool) error {
p.mut.Lock()
defer p.mut.Unlock()
if p.telemetry == nil && enableDiagnostics != nil && *enableDiagnostics {
p.LogDebug("Initializing telemetry")
// setup telemetry
client, err := telemetry.NewClient(telemetry.ClientConfig{
WriteKey: rudderWriteKey,
DataplaneURL: rudderDataplaneURL,
DiagnosticID: p.API.GetDiagnosticId(),
DefaultProps: map[string]interface{}{
"ServerVersion": p.API.GetServerVersion(),
"PluginVersion": manifest.Version,
"PluginBuild": buildHash,
},
})
if err != nil {
return err
}
p.telemetry = client
} else if p.telemetry != nil && (enableDiagnostics == nil || !*enableDiagnostics) {
p.LogDebug("Deinitializing telemetry")
// destroy telemetry
if err := p.telemetry.Close(); err != nil {
return err
}
p.telemetry = nil
}
return nil
}
func (p *Plugin) handleTrackEvent(w http.ResponseWriter, r *http.Request) {
var res httpResponse
defer p.httpAudit("handleTrackEvent", &res, w, r)
p.mut.RLock()
telemetryEnabled := p.telemetry != nil
p.mut.RUnlock()
if !telemetryEnabled {
res.Err = "telemetry is disabled"
res.Code = http.StatusBadRequest
return
}
var data trackEventRequest
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, requestBodyMaxSizeBytes)).Decode(&data); err != nil {
res.Err = err.Error()
res.Code = http.StatusBadRequest
return
}
if _, ok := telemetryClientEventsMap[data.Event]; !ok {
res.Err = "invalid telemetry event"
res.Code = http.StatusBadRequest
return
}
if _, ok := telemetryClientTypesMap[data.ClientType]; !ok {
res.Err = "invalid client type"
res.Code = http.StatusBadRequest
return
}
if data.Props == nil {
data.Props = map[string]interface{}{}
}
if data.Source != "" {
data.Props["Source"] = data.Source
}
data.Props["ActualUserID"] = r.Header.Get("Mattermost-User-Id")
data.Props["ClientType"] = data.ClientType
p.track(data.Event, data.Props)
res.Code = http.StatusOK
res.Msg = "success"
}