mirror of
https://github.com/status-im/status-go.git
synced 2025-01-12 23:55:03 +00:00
9a59d6a459
This commit adds support for centralized metrics. There are two providers as of now, and we haven't quite decided which one to go for, so for the time being both are supported. It also introduces a new endpoint InitializeApplication that replaces OpenAccounts
191 lines
4.7 KiB
Go
191 lines
4.7 KiB
Go
package providers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
|
|
"github.com/status-im/status-go/centralizedmetrics/common"
|
|
)
|
|
|
|
const MixpanelBaseURL = "https://api.mixpanel.com"
|
|
|
|
var MixpanelToken = ""
|
|
var MixpanelAppID = ""
|
|
|
|
// MixpanelMetricProcessor implements MetricProcessor for Mixpanel
|
|
type MixpanelMetricProcessor struct {
|
|
appID string
|
|
secret string
|
|
baseURL string
|
|
}
|
|
|
|
// NewMixpanelMetricProcessor is a constructor for MixpanelMetricProcessor
|
|
func NewMixpanelMetricProcessor(appID, secret, baseURL string) *MixpanelMetricProcessor {
|
|
return &MixpanelMetricProcessor{
|
|
appID: appID,
|
|
secret: secret,
|
|
baseURL: baseURL,
|
|
}
|
|
}
|
|
|
|
func (amp *MixpanelMetricProcessor) GetAppID() string {
|
|
if len(amp.appID) != 0 {
|
|
return amp.appID
|
|
}
|
|
return MixpanelAppID
|
|
}
|
|
|
|
func (amp *MixpanelMetricProcessor) GetToken() string {
|
|
if len(amp.secret) != 0 {
|
|
return amp.secret
|
|
}
|
|
|
|
return MixpanelToken
|
|
}
|
|
|
|
// Process processes an array of metrics and sends them to the Mixpanel API
|
|
func (amp *MixpanelMetricProcessor) Process(metrics []common.Metric) error {
|
|
if err := amp.sendToMixpanel(metrics); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// sendToMixpanel sends a single metric to the Mixpanel API
|
|
func (amp *MixpanelMetricProcessor) sendToMixpanel(metrics []common.Metric) error {
|
|
url := fmt.Sprintf("%s/track?project_id=%s&strict=1", amp.baseURL, amp.GetAppID())
|
|
|
|
var mixPanelMetrics []mixpanelMetric
|
|
|
|
for _, metric := range metrics {
|
|
mixPanelMetrics = append(mixPanelMetrics, toMixpanelMetric(metric, amp.GetToken()))
|
|
}
|
|
payload, err := json.Marshal(mixPanelMetrics)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Info("sending metrics to", "url", url, "metric", mixPanelMetrics, "secret", amp.GetToken())
|
|
|
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("accept", "application/json")
|
|
req.Header.Set("content-type", "application/json")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, err := io.ReadAll(resp.Body)
|
|
fmt.Println(resp.StatusCode, string(body), err)
|
|
log.Warn("failed to send metric", "status-code", resp.StatusCode, "body", resp.Body)
|
|
return errors.New("failed to send metric to Mixpanel")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func toMixpanelMetric(metric common.Metric, token string) mixpanelMetric {
|
|
|
|
properties := mixpanelMetricProperties{
|
|
Time: metric.Timestamp,
|
|
UserID: metric.UserID,
|
|
Platform: metric.Platform,
|
|
InsertID: metric.ID,
|
|
AppVersion: metric.AppVersion,
|
|
Token: token,
|
|
AdditionalProperties: metric.EventValue,
|
|
}
|
|
|
|
return mixpanelMetric{
|
|
Event: metric.EventName,
|
|
Properties: properties,
|
|
}
|
|
}
|
|
|
|
type mixpanelMetricProperties struct {
|
|
Time int64 `json:"time"`
|
|
UserID string `json:"distinct_id"`
|
|
InsertID string `json:"$insert_id"`
|
|
Platform string `json:"platform"`
|
|
AppVersion string `json:"app_version"`
|
|
AdditionalProperties map[string]any `json:"-"`
|
|
Token string `json:"token"`
|
|
}
|
|
|
|
type mixpanelMetric struct {
|
|
Event string `json:"event"`
|
|
Properties mixpanelMetricProperties `json:"properties"`
|
|
}
|
|
|
|
func (p mixpanelMetricProperties) MarshalJSON() ([]byte, error) {
|
|
// Create a map and marshal the struct fields into it
|
|
type alias mixpanelMetricProperties // Alias to avoid recursion
|
|
data, err := json.Marshal(alias(p))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Unmarshal the JSON into a map
|
|
var mmpMap map[string]any
|
|
if err := json.Unmarshal(data, &mmpMap); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Merge AdditionalProperties into the map
|
|
for key, value := range p.AdditionalProperties {
|
|
mmpMap[key] = value
|
|
}
|
|
|
|
// Marshal the merged map back to JSON
|
|
marshaled, err := json.Marshal(mmpMap)
|
|
|
|
return marshaled, err
|
|
}
|
|
|
|
func (p *mixpanelMetricProperties) UnmarshalJSON(data []byte) error {
|
|
// Create a temporary alias type to unmarshal known fields
|
|
type alias mixpanelMetricProperties
|
|
aux := &struct {
|
|
*alias
|
|
}{
|
|
alias: (*alias)(p),
|
|
}
|
|
|
|
if err := json.Unmarshal(data, &aux); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Unmarshal into a map to capture additional properties
|
|
var rawMap map[string]any
|
|
if err := json.Unmarshal(data, &rawMap); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Remove known fields from the map
|
|
delete(rawMap, "time")
|
|
delete(rawMap, "token")
|
|
delete(rawMap, "distinct_id")
|
|
delete(rawMap, "$insert_id")
|
|
delete(rawMap, "platform")
|
|
delete(rawMap, "app_version")
|
|
|
|
// Assign the remaining fields to AdditionalProperties
|
|
p.AdditionalProperties = rawMap
|
|
|
|
return nil
|
|
}
|