feat: adding disable and anonymous functionality to telemetry collected (#637)

* chore: changed lib

* chore: changed lib

* chore: changed lib

* chore: changed lib

* chore: changes in params

* chore: changes in params

* chore: moving telemetry to a separate package

* feat: enabling telemetry via env var

* chore: removing posthog api_key

* feat: send heartbeat every 6hr

* feat: enabled version in application

* feat: added getter and setter apis and struct for user preferences

* feat: added version to properties to event

* feat: added apis to set and get user preferences and get version

* chore: refactored get and set userPreferences apis to dao pattern

* chore: added checks for telemetry enabled and anonymous during initialization

* chore: changed anonymous user functionality

* chore: sanitization

* chore: added uuid for userPreferences to send when user is anonymous
This commit is contained in:
Ankit Nayan 2022-01-26 21:40:44 +05:30 committed by GitHub
parent 0ab91707e9
commit be5d1f0090
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 571 additions and 91 deletions

View File

@ -45,8 +45,8 @@ services:
environment:
- ClickHouseUrl=tcp://clickhouse:9000
- STORAGE=clickhouse
- POSTHOG_API_KEY=H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w
- GODEBUG=netdns=go
- TELEMETRY_ENABLED=true
depends_on:
clickhouse:

View File

@ -41,6 +41,8 @@ spec:
value: {{ .Values.configVars.ClickHouseUrl}}
- name: GODEBUG
value: netdns=go
- name: TELEMETRY_ENABLED
value: {{ .Values.configVars.TELEMETRY_ENABLED}}
# livenessProbe:
# httpGet:
# path: /

View File

@ -19,7 +19,6 @@ configVars:
DruidDatasource: flattened_spans
ClickHouseUrl: http://signoz-clickhouse:9000?username=clickhouse_operator&password=clickhouse_operator_password
STORAGE: clickhouse
POSTHOG_API_KEY: "H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w"
serviceAccount:

View File

@ -6,6 +6,7 @@ query-service:
configVars:
ClickHouseUrl: http://signoz-clickhouse:9000?username=clickhouse_operator&password=clickhouse_operator_password
STORAGE: clickhouse
TELEMETRY_ENABLED: true
cloud: aws

View File

@ -10,10 +10,12 @@ import (
"github.com/gorilla/mux"
jsoniter "github.com/json-iterator/go"
_ "github.com/mattn/go-sqlite3"
"github.com/posthog/posthog-go"
"github.com/prometheus/prometheus/promql"
"go.signoz.io/query-service/app/dashboards"
"go.signoz.io/query-service/dao/interfaces"
"go.signoz.io/query-service/model"
"go.signoz.io/query-service/telemetry"
"go.signoz.io/query-service/version"
"go.uber.org/zap"
)
@ -33,28 +35,26 @@ func NewRouter() *mux.Router {
type APIHandler struct {
// queryService *querysvc.QueryService
// queryParser queryParser
basePath string
apiPrefix string
reader *Reader
pc *posthog.Client
distinctId string
ready func(http.HandlerFunc) http.HandlerFunc
basePath string
apiPrefix string
reader *Reader
relationalDB *interfaces.ModelDao
ready func(http.HandlerFunc) http.HandlerFunc
}
// NewAPIHandler returns an APIHandler
func NewAPIHandler(reader *Reader, pc *posthog.Client, distinctId string) (*APIHandler, error) {
func NewAPIHandler(reader *Reader, relationalDB *interfaces.ModelDao) (*APIHandler, error) {
aH := &APIHandler{
reader: reader,
pc: pc,
distinctId: distinctId,
reader: reader,
relationalDB: relationalDB,
}
aH.ready = aH.testReady
errReadingDashboards := dashboards.LoadDashboardFiles()
if errReadingDashboards != nil {
return nil, errReadingDashboards
}
dashboards.LoadDashboardFiles()
// if errReadingDashboards != nil {
// return nil, errReadingDashboards
// }
return aH, nil
}
@ -184,6 +184,7 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/dashboards/{uuid}", aH.deleteDashboard).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/user", aH.user).Methods(http.MethodPost)
router.HandleFunc("/api/v1/feedback", aH.submitFeedback).Methods(http.MethodPost)
// router.HandleFunc("/api/v1/get_percentiles", aH.getApplicationPercentiles).Methods(http.MethodGet)
router.HandleFunc("/api/v1/services", aH.getServices).Methods(http.MethodGet)
@ -203,10 +204,16 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
router.HandleFunc("/api/v1/serviceMapDependencies", aH.serviceMapDependencies).Methods(http.MethodGet)
router.HandleFunc("/api/v1/settings/ttl", aH.setTTL).Methods(http.MethodPost)
router.HandleFunc("/api/v1/settings/ttl", aH.getTTL).Methods(http.MethodGet)
router.HandleFunc("/api/v1/userPreferences", aH.setUserPreferences).Methods(http.MethodPost)
router.HandleFunc("/api/v1/userPreferences", aH.getUserPreferences).Methods(http.MethodGet)
router.HandleFunc("/api/v1/version", aH.getVersion).Methods(http.MethodGet)
router.HandleFunc("/api/v1/getSpanFilters", aH.getSpanFilters).Methods(http.MethodGet)
router.HandleFunc("/api/v1/getTagFilters", aH.getTagFilters).Methods(http.MethodGet)
router.HandleFunc("/api/v1/getFilteredSpans", aH.getFilteredSpans).Methods(http.MethodGet)
router.HandleFunc("/api/v1/getFilteredSpans/aggregates", aH.getFilteredSpanAggregates).Methods(http.MethodGet)
router.HandleFunc("/api/v1/errors", aH.getErrors).Methods(http.MethodGet)
router.HandleFunc("/api/v1/errorWithId", aH.getErrorForId).Methods(http.MethodGet)
router.HandleFunc("/api/v1/errorWithType", aH.getErrorForType).Methods(http.MethodGet)
@ -656,11 +663,11 @@ func (aH *APIHandler) submitFeedback(w http.ResponseWriter, r *http.Request) {
email := postData["email"]
(*aH.pc).Enqueue(posthog.Capture{
DistinctId: distinctId,
Event: "InProduct Feeback Submitted",
Properties: posthog.NewProperties().Set("email", email).Set("message", message),
})
data := map[string]interface{}{
"email": email,
"message": message,
}
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_INPRODUCT_FEEDBACK, data)
}
@ -673,11 +680,12 @@ func (aH *APIHandler) user(w http.ResponseWriter, r *http.Request) {
}
}
(*aH.pc).Enqueue(posthog.Identify{
DistinctId: aH.distinctId,
Properties: posthog.NewProperties().
Set("email", user.Email).Set("name", user.Name),
})
telemetry.GetInstance().IdentifyUser(user)
data := map[string]interface{}{
"name": user.Name,
"email": user.Email,
}
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_USER, data)
}
@ -852,13 +860,12 @@ func (aH *APIHandler) getServices(w http.ResponseWriter, r *http.Request) {
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
// if len(*result) != 4 {
(*aH.pc).Enqueue(posthog.Capture{
DistinctId: distinctId,
Event: "Different Number of Services",
Properties: posthog.NewProperties().Set("number", len(*result)),
})
// }
data := map[string]interface{}{
"number": len(*result),
}
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_NUMBER_OF_SERVICES, data)
aH.writeJSON(w, r, result)
}
@ -1062,6 +1069,39 @@ func (aH *APIHandler) getTTL(w http.ResponseWriter, r *http.Request) {
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) getUserPreferences(w http.ResponseWriter, r *http.Request) {
result, apiError := (*aH.relationalDB).FetchUserPreference(context.Background())
if apiError != nil {
aH.respondError(w, apiError, "Error from Fetch Dao")
return
}
aH.writeJSON(w, r, result)
}
func (aH *APIHandler) setUserPreferences(w http.ResponseWriter, r *http.Request) {
userParams, err := parseUserPreferences(r)
if aH.handleError(w, err, http.StatusBadRequest) {
return
}
apiErr := (*aH.relationalDB).UpdateUserPreferece(context.Background(), userParams)
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
return
}
aH.writeJSON(w, r, map[string]string{"data": "user preferences set successfully"})
}
func (aH *APIHandler) getVersion(w http.ResponseWriter, r *http.Request) {
version := version.GetVersion()
aH.writeJSON(w, r, map[string]string{"version": version})
}
// func (aH *APIHandler) getApplicationPercentiles(w http.ResponseWriter, r *http.Request) {
// // vars := mux.Vars(r)

View File

@ -1045,3 +1045,15 @@ func parseGetTTL(r *http.Request) (*model.GetTTLParams, error) {
return &model.GetTTLParams{Type: typeTTL, GetAllTTL: getAllTTL}, nil
}
func parseUserPreferences(r *http.Request) (*model.UserPreferences, error) {
var userPreferences model.UserPreferences
err := json.NewDecoder(r.Body).Decode(&userPreferences)
if err != nil {
return nil, err
}
return &userPreferences, nil
}

View File

@ -7,16 +7,18 @@ import (
"os"
"time"
"github.com/google/uuid"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/posthog/posthog-go"
"github.com/rs/cors"
"github.com/soheilhy/cmux"
"go.signoz.io/query-service/app/clickhouseReader"
"go.signoz.io/query-service/app/dashboards"
"go.signoz.io/query-service/app/druidReader"
"go.signoz.io/query-service/constants"
"go.signoz.io/query-service/dao"
"go.signoz.io/query-service/healthcheck"
"go.signoz.io/query-service/telemetry"
"go.signoz.io/query-service/utils"
"go.uber.org/zap"
)
@ -66,38 +68,35 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
// if err != nil {
// return nil, err
// }
httpServer, err := createHTTPServer()
if err != nil {
return nil, err
}
return &Server{
s := &Server{
// logger: logger,
// querySvc: querySvc,
// queryOptions: options,
// tracer: tracer,
// grpcServer: grpcServer,
serverOptions: serverOptions,
httpServer: httpServer,
separatePorts: true,
// separatePorts: grpcPort != httpPort,
unavailableChannel: make(chan healthcheck.Status),
}, nil
}
}
httpServer, err := s.createHTTPServer()
var posthogClient posthog.Client
var distinctId string
func createHTTPServer() (*http.Server, error) {
posthogClient = posthog.New("H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w")
distinctId = uuid.New().String()
localDB, err := dashboards.InitDB("./signoz.db")
if err != nil {
return nil, err
}
s.httpServer = httpServer
return s, nil
}
func (s *Server) createHTTPServer() (*http.Server, error) {
localDB, err := dashboards.InitDB(constants.RELATIONAL_DATASOURCE_PATH)
if err != nil {
return nil, err
}
localDB.SetMaxOpenConns(10)
var reader Reader
@ -114,14 +113,19 @@ func createHTTPServer() (*http.Server, error) {
return nil, fmt.Errorf("Storage type: %s is not supported in query service", storage)
}
apiHandler, err := NewAPIHandler(&reader, &posthogClient, distinctId)
relationalDB, err := dao.FactoryDao("sqlite")
if err != nil {
return nil, err
}
apiHandler, err := NewAPIHandler(&reader, relationalDB)
if err != nil {
return nil, err
}
r := NewRouter()
r.Use(analyticsMiddleware)
r.Use(s.analyticsMiddleware)
r.Use(loggingMiddleware)
apiHandler.RegisterRoutes(r)
@ -152,15 +156,16 @@ func loggingMiddleware(next http.Handler) http.Handler {
})
}
func analyticsMiddleware(next http.Handler) http.Handler {
func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
route := mux.CurrentRoute(r)
path, _ := route.GetPathTemplate()
posthogClient.Enqueue(posthog.Capture{
DistinctId: distinctId,
Event: path,
})
data := map[string]interface{}{"path": path}
if _, ok := telemetry.IgnoredPaths()[path]; !ok {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data)
}
next.ServeHTTP(w, r)
})

View File

@ -23,4 +23,4 @@ scrape_configs:
remote_read:
- url: tcp://3.135.248.251:9001/?database=signoz_metrics
- url: tcp://localhost:9001/?database=signoz_metrics

View File

@ -2,14 +2,26 @@ package constants
import (
"os"
"strconv"
)
const HTTPHostPort = "0.0.0.0:8080"
var DruidClientUrl = os.Getenv("DruidClientUrl")
var DruidDatasource = os.Getenv("DruidDatasource")
var DEFAULT_TELEMETRY_ANONYMOUS = false
func IsTelemetryEnabled() bool {
isTelemetryEnabledStr := os.Getenv("TELEMETRY_ENABLED")
isTelemetryEnabledBool, err := strconv.ParseBool(isTelemetryEnabledStr)
if err != nil {
return true
}
return isTelemetryEnabledBool
}
const TraceTTL = "traces"
const MetricsTTL = "metrics"
const ALERTMANAGER_API_PREFIX = "http://alertmanager:9093/api/"
const RELATIONAL_DATASOURCE_PATH = "/var/lib/signoz/signoz.db"

View File

@ -0,0 +1,26 @@
package dao
import (
"fmt"
"go.signoz.io/query-service/constants"
"go.signoz.io/query-service/dao/interfaces"
"go.signoz.io/query-service/dao/sqlite"
)
func FactoryDao(engine string) (*interfaces.ModelDao, error) {
var i interfaces.ModelDao
var err error
switch engine {
case "sqlite":
i, err = sqlite.InitDB(constants.RELATIONAL_DATASOURCE_PATH)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("RelationalDB type: %s is not supported in query service", engine)
}
return &i, nil
}

View File

@ -0,0 +1,5 @@
package interfaces
type ModelDao interface {
UserPreferenceDao
}

View File

@ -0,0 +1,12 @@
package interfaces
import (
"context"
"go.signoz.io/query-service/model"
)
type UserPreferenceDao interface {
UpdateUserPreferece(ctx context.Context, userPreferences *model.UserPreferences) *model.ApiError
FetchUserPreference(ctx context.Context) (*model.UserPreferences, *model.ApiError)
}

View File

@ -0,0 +1,70 @@
package sqlite
import (
"context"
"fmt"
"github.com/jmoiron/sqlx"
"go.signoz.io/query-service/constants"
"go.signoz.io/query-service/telemetry"
)
type ModelDaoSqlite struct {
db *sqlx.DB
}
// InitDB sets up setting up the connection pool global variable.
func InitDB(dataSourceName string) (*ModelDaoSqlite, error) {
var err error
db, err := sqlx.Open("sqlite3", dataSourceName)
if err != nil {
return nil, err
}
db.SetMaxOpenConns(10)
table_schema := `CREATE TABLE IF NOT EXISTS user_preferences (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid TEXT NOT NULL,
isAnonymous INTEGER NOT NULL DEFAULT 0 CHECK(isAnonymous IN (0,1)),
hasOptedUpdates INTEGER NOT NULL DEFAULT 1 CHECK(hasOptedUpdates IN (0,1))
);`
_, err = db.Exec(table_schema)
if err != nil {
return nil, fmt.Errorf("Error in creating user_preferences table: ", err.Error())
}
mds := &ModelDaoSqlite{db: db}
err = mds.initializeUserPreferences()
if err != nil {
return nil, err
}
return mds, nil
}
func (mds *ModelDaoSqlite) initializeUserPreferences() error {
// set anonymous setting as default in case of any failures to fetch UserPreference in below section
telemetry.GetInstance().SetTelemetryAnonymous(constants.DEFAULT_TELEMETRY_ANONYMOUS)
ctx := context.Background()
userPreference, apiError := mds.FetchUserPreference(ctx)
if apiError != nil {
return apiError.Err
}
if userPreference == nil {
userPreference, apiError = mds.CreateDefaultUserPreference(ctx)
}
if apiError != nil {
return apiError.Err
}
// set telemetry fields from userPreferences
telemetry.GetInstance().SetTelemetryAnonymous(userPreference.GetIsAnonymous())
telemetry.GetInstance().SetDistinctId(userPreference.GetUUID())
return nil
}

View File

@ -0,0 +1,91 @@
package sqlite
import (
"context"
"fmt"
"github.com/google/uuid"
"go.signoz.io/query-service/model"
"go.signoz.io/query-service/telemetry"
"go.uber.org/zap"
)
func (mds *ModelDaoSqlite) FetchUserPreference(ctx context.Context) (*model.UserPreferences, *model.ApiError) {
userPreferences := []model.UserPreferences{}
query := fmt.Sprintf("SELECT id, uuid, isAnonymous, hasOptedUpdates FROM user_preferences;")
err := mds.db.Select(&userPreferences, query)
if err != nil {
zap.S().Debug("Error in processing sql query: ", err)
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
// zap.S().Info(query)
if len(userPreferences) > 1 {
zap.S().Debug("Error in processing sql query: ", fmt.Errorf("more than 1 row in user_preferences found"))
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
if len(userPreferences) == 0 {
return nil, nil
}
return &userPreferences[0], nil
}
func (mds *ModelDaoSqlite) UpdateUserPreferece(ctx context.Context, userPreferences *model.UserPreferences) *model.ApiError {
tx, err := mds.db.Begin()
if err != nil {
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
userPreferencesFound, apiError := mds.FetchUserPreference(ctx)
if apiError != nil {
return apiError
}
stmt, err := tx.Prepare(`UPDATE user_preferences SET isAnonymous=$1, hasOptedUpdates=$2 WHERE id=$3;`)
defer stmt.Close()
if err != nil {
zap.S().Errorf("Error in preparing statement for INSERT to user_preferences\n", err)
tx.Rollback()
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
query_result, err := stmt.Exec(userPreferences.GetIsAnonymous(), userPreferences.GetHasOptedUpdate(), userPreferencesFound.GetId())
if err != nil {
zap.S().Errorf("Error in Executing prepared statement for INSERT to user_preferences\n", err)
tx.Rollback() // return an error too, we may want to wrap them
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
zap.S().Debug(query_result.RowsAffected())
zap.S().Debug(userPreferences.GetIsAnonymous(), userPreferences.GetHasOptedUpdate(), userPreferencesFound.GetId())
err = tx.Commit()
if err != nil {
zap.S().Errorf("Error in commiting transaction for INSERT to user_preferences\n", err)
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
telemetry.GetInstance().SetTelemetryAnonymous(userPreferences.GetIsAnonymous())
return nil
}
func (mds *ModelDaoSqlite) CreateDefaultUserPreference(ctx context.Context) (*model.UserPreferences, *model.ApiError) {
uuid := uuid.New().String()
_, err := mds.db.ExecContext(ctx, `INSERT INTO user_preferences (uuid, isAnonymous, hasOptedUpdates) VALUES (?, 0, 1);`, uuid)
if err != nil {
zap.S().Errorf("Error in preparing statement for INSERT to user_preferences\n", err)
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
}
return mds.FetchUserPreference(ctx)
}

View File

@ -4,14 +4,19 @@ go 1.14
require (
cloud.google.com/go v0.88.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/ClickHouse/clickhouse-go v1.4.5
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/aws/aws-sdk-go v1.27.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/containerd/containerd v1.4.12 // indirect
github.com/dhui/dktest v0.3.4 // indirect
github.com/docker/docker v20.10.12+incompatible // indirect
github.com/frankban/quicktest v1.13.0 // indirect
github.com/go-kit/log v0.1.0
github.com/golang-migrate/migrate/v4 v4.14.1
@ -36,7 +41,6 @@ require (
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/oklog/oklog v0.3.2
github.com/oklog/run v1.1.0 // indirect
github.com/onsi/gomega v1.14.0 // indirect
@ -45,7 +49,6 @@ require (
github.com/pascaldekloe/goe v0.1.0 // indirect
github.com/pierrec/lz4 v2.4.1+incompatible // indirect
github.com/pkg/errors v0.9.1
github.com/posthog/posthog-go v0.0.0-20200525173953-e46dc8e6b89b
github.com/prometheus/client_golang v0.9.0-pre1.0.20181001174001-0a8115f42e03
github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1
github.com/prometheus/procfs v0.0.8 // indirect
@ -53,9 +56,11 @@ require (
github.com/rs/cors v1.7.0
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da // indirect
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
github.com/segmentio/backo-go v1.0.0 // indirect
github.com/smartystreets/goconvey v1.6.4
github.com/soheilhy/cmux v0.1.4
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/pflag v1.0.3 // indirect
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
go.uber.org/zap v1.16.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
@ -68,7 +73,7 @@ require (
google.golang.org/grpc/examples v0.0.0-20210803221256-6ba56c814be7 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gotest.tools/v3 v3.0.3 // indirect
gopkg.in/segmentio/analytics-go.v3 v3.1.0
)

View File

@ -58,7 +58,6 @@ github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhH
github.com/ClickHouse/clickhouse-go v1.4.5 h1:FfhyEnv6/BaWldyjgT2k4gDDmeNwJ9C4NbY/MXxJlXk=
github.com/ClickHouse/clickhouse-go v1.4.5/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -76,11 +75,13 @@ github.com/aws/aws-sdk-go v1.13.44-0.20180507225419-00862f899353/go.mod h1:ZRmQr
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.27.0 h1:0xphMHGMLBrPMfxR2AmVjZKcMEESEgWF8Kru94BNByk=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1 h1:OnJHjoVbY69GG4gclp0ngXfywigLhR6rrgUxmxQRWO4=
github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -104,16 +105,12 @@ github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292/go.mod h1:qRiX68m
github.com/cockroachdb/cockroach v0.0.0-20170608034007-84bc9597164f/go.mod h1:xeT/CQ0qZHangbYbWShlCGAx31aV4AjGswDUjhKS6HQ=
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY=
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.12 h1:V+SHzYmhng/iju6M5nFrpTTusrhidoxKTwdwLw+u4c4=
github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -123,15 +120,12 @@ github.com/dgrijalva/jwt-go v3.0.1-0.20161101193935-9ed569b5d1ac+incompatible/go
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-bits v0.0.0-20160601073636-2ad8d707cc05/go.mod h1:/9UYwwvZuEgp+mQ4960SHWCU1FS+FgdFX+m5ExFByNs=
github.com/dhui/dktest v0.3.3 h1:DBuH/9GFaWbDRa42qsut/hbQu+srAQ0rPWnUoiGX7CA=
github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ=
github.com/dhui/dktest v0.3.4 h1:VbUEcaSP+U2/yUr9d2JhSThXYEnDlGabRSHe2rIE46E=
github.com/dhui/dktest v0.3.4/go.mod h1:4m4n6lmXlmVfESth7mzdcv8nBI5mOb5UROPqjM02csU=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8=
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20210128214336-420b1d36250f+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U=
github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
@ -177,9 +171,8 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
github.com/gogo/protobuf v0.0.0-20171123125729-971cbfd2e72b/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcItYNxJ3iUHHE=
github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
@ -378,7 +371,6 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -421,8 +413,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -479,8 +469,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posthog/posthog-go v0.0.0-20200525173953-e46dc8e6b89b h1:a8lLvAV+8OQXnG18ZOV5ctFQY7jLHa3brA9BBhe1SVs=
github.com/posthog/posthog-go v0.0.0-20200525173953-e46dc8e6b89b/go.mod h1:s7IZAf1WuSPTb/R/agnboYa+gDnoKGdqIk7p2aFHDYs=
github.com/prometheus/client_golang v0.9.0-pre1.0.20181001174001-0a8115f42e03 h1:hqNopISksxji/N5zEy1xMN7TrnSyVG/LymiwnkXi6/Q=
github.com/prometheus/client_golang v0.9.0-pre1.0.20181001174001-0a8115f42e03/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
@ -507,6 +495,8 @@ github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZj
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/backo-go v1.0.0 h1:kbOAtGJY2DqOR0jfRkYEorx/b18RgtepGtY3+Cpe6qA=
github.com/segmentio/backo-go v1.0.0/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20180711163814-62bca832be04/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
@ -795,7 +785,6 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -825,7 +814,6 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200806022845-90696ccdc692/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@ -839,7 +827,6 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@ -931,7 +918,6 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@ -1004,6 +990,8 @@ gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U=
gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -1018,9 +1006,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,27 @@
package model
type UserPreferences struct {
Id int `json:"id" db:"id"`
Uuid string `json:"uuid" db:"uuid"`
IsAnonymous bool `json:"isAnonymous" db:"isAnonymous"`
HasOptedUpdates bool `json:"hasOptedUpdates" db:"hasOptedUpdates"`
}
func (up *UserPreferences) SetIsAnonymous(isAnonymous bool) {
up.IsAnonymous = isAnonymous
}
func (up *UserPreferences) SetHasOptedUpdate(hasOptedUpdates bool) {
up.HasOptedUpdates = hasOptedUpdates
}
func (up *UserPreferences) GetIsAnonymous() bool {
return up.IsAnonymous
}
func (up *UserPreferences) GetHasOptedUpdate() bool {
return up.HasOptedUpdates
}
func (up *UserPreferences) GetId() int {
return up.Id
}
func (up *UserPreferences) GetUUID() string {
return up.Uuid
}

View File

@ -0,0 +1,9 @@
package telemetry
func IgnoredPaths() map[string]struct{} {
ignoredPaths := map[string]struct{}{
"/api/v1/tags": struct{}{},
}
return ignoredPaths
}

View File

@ -0,0 +1,155 @@
package telemetry
import (
"io/ioutil"
"net/http"
"sync"
"time"
"go.signoz.io/query-service/constants"
"go.signoz.io/query-service/model"
"go.signoz.io/query-service/version"
"gopkg.in/segmentio/analytics-go.v3"
)
const (
TELEMETRY_EVENT_PATH = "API Call"
TELEMETRY_EVENT_USER = "User"
TELEMETRY_EVENT_INPRODUCT_FEEDBACK = "InProduct Feeback Submitted"
TELEMETRY_EVENT_NUMBER_OF_SERVICES = "Number of Services"
TELEMETRY_EVENT_HEART_BEAT = "Heart Beat"
)
const api_key = "4Gmoa4ixJAUHx2BpJxsjwA1bEfnwEeRz"
var telemetry *Telemetry
var once sync.Once
type Telemetry struct {
operator analytics.Client
ipAddress string
isEnabled bool
isAnonymous bool
distinctId string
}
func createTelemetry() {
telemetry = &Telemetry{
operator: analytics.New(api_key),
ipAddress: getOutboundIP(),
}
data := map[string]interface{}{}
telemetry.SetTelemetryEnabled(constants.IsTelemetryEnabled())
telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data)
ticker := time.NewTicker(6 * time.Hour)
go func() {
for {
select {
case <-ticker.C:
telemetry.SendEvent(TELEMETRY_EVENT_HEART_BEAT, data)
}
}
}()
}
// Get preferred outbound ip of this machine
func getOutboundIP() string {
ip := []byte("NA")
resp, err := http.Get("https://api.ipify.org?format=text")
defer resp.Body.Close()
if err == nil {
ipBody, err := ioutil.ReadAll(resp.Body)
if err == nil {
ip = ipBody
}
}
return string(ip)
}
func (a *Telemetry) IdentifyUser(user *model.User) {
if !a.isTelemetryEnabled() || a.isTelemetryAnonymous() {
return
}
a.operator.Enqueue(analytics.Identify{
UserId: a.ipAddress,
Traits: analytics.NewTraits().SetName(user.Name).SetEmail(user.Email).Set("ip", a.ipAddress),
})
}
func (a *Telemetry) checkEvents(event string) bool {
sendEvent := true
if event == TELEMETRY_EVENT_USER && a.isTelemetryAnonymous() {
sendEvent = false
}
return sendEvent
}
func (a *Telemetry) SendEvent(event string, data map[string]interface{}) {
if !a.isTelemetryEnabled() {
return
}
ok := a.checkEvents(event)
if !ok {
return
}
// zap.S().Info(data)
properties := analytics.NewProperties()
properties.Set("version", version.GetVersion())
for k, v := range data {
properties.Set(k, v)
}
userId := a.ipAddress
if a.isTelemetryAnonymous() {
userId = a.GetDistinctId()
}
a.operator.Enqueue(analytics.Track{
Event: event,
UserId: userId,
Properties: properties,
})
}
func (a *Telemetry) GetDistinctId() string {
return a.distinctId
}
func (a *Telemetry) SetDistinctId(distinctId string) {
a.distinctId = distinctId
}
func (a *Telemetry) isTelemetryAnonymous() bool {
return a.isAnonymous
}
func (a *Telemetry) SetTelemetryAnonymous(value bool) {
a.isAnonymous = value
}
func (a *Telemetry) isTelemetryEnabled() bool {
return a.isEnabled
}
func (a *Telemetry) SetTelemetryEnabled(value bool) {
a.isEnabled = value
}
func GetInstance() *Telemetry {
once.Do(func() {
createTelemetry()
})
return telemetry
}

View File

@ -0,0 +1,24 @@
package version
import (
"go.uber.org/zap"
)
// These fields are set during an official build
// Global vars set from command-line arguments
var (
version = "--"
buildhash = "--"
buildtime = "--"
)
//PrintVersionInfo displays the kyverno version - git version
func PrintVersionInfo() {
zap.S().Info("Version: ", version)
zap.S().Info("BuildHash: ", buildhash)
zap.S().Info("BuildTime: ", buildtime)
}
func GetVersion() string {
return version
}