telemetry.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package logic
  2. import (
  3. "encoding/json"
  4. "os"
  5. "time"
  6. "github.com/gravitl/netmaker/database"
  7. "github.com/gravitl/netmaker/logger"
  8. "github.com/gravitl/netmaker/models"
  9. "github.com/gravitl/netmaker/servercfg"
  10. "github.com/posthog/posthog-go"
  11. "golang.org/x/exp/slog"
  12. )
  13. // flags to keep for telemetry
  14. var isFreeTier bool
  15. // posthog_pub_key - Key for sending data to PostHog
  16. const posthog_pub_key = "phc_1vEXhPOA1P7HP5jP2dVU9xDTUqXHAelmtravyZ1vvES"
  17. // posthog_endpoint - Endpoint of PostHog server
  18. const posthog_endpoint = "https://app.posthog.com"
  19. // setFreeTierForTelemetry - store free tier flag without having an import cycle when used for telemetry
  20. // (as the pro package needs the logic package as currently written).
  21. func SetFreeTierForTelemetry(freeTierFlag bool) {
  22. isFreeTier = freeTierFlag
  23. }
  24. // sendTelemetry - gathers telemetry data and sends to posthog
  25. func sendTelemetry() error {
  26. if servercfg.Telemetry() == "off" {
  27. return nil
  28. }
  29. var telRecord, err = FetchTelemetryRecord()
  30. if err != nil {
  31. return err
  32. }
  33. // get telemetry data
  34. d := FetchTelemetryData()
  35. // get tenant admin email
  36. adminEmail := os.Getenv("NM_EMAIL")
  37. client, err := posthog.NewWithConfig(posthog_pub_key, posthog.Config{Endpoint: posthog_endpoint})
  38. if err != nil {
  39. return err
  40. }
  41. defer client.Close()
  42. slog.Info("sending telemetry data to posthog", "data", d)
  43. // send to posthog
  44. return client.Enqueue(posthog.Capture{
  45. DistinctId: telRecord.UUID,
  46. Event: "daily checkin",
  47. Properties: posthog.NewProperties().
  48. Set("nodes", d.Nodes).
  49. Set("hosts", d.Hosts).
  50. Set("servers", d.Servers).
  51. Set("non-server nodes", d.Count.NonServer).
  52. Set("extclients", d.ExtClients).
  53. Set("users", d.Users).
  54. Set("networks", d.Networks).
  55. Set("linux", d.Count.Linux).
  56. Set("darwin", d.Count.MacOS).
  57. Set("windows", d.Count.Windows).
  58. Set("freebsd", d.Count.FreeBSD).
  59. Set("docker", d.Count.Docker).
  60. Set("k8s", d.Count.K8S).
  61. Set("version", d.Version).
  62. Set("is_ee", d.IsPro). // TODO change is_ee to is_pro for consistency, but probably needs changes in posthog
  63. Set("is_free_tier", isFreeTier).
  64. Set("is_pro_trial", d.IsProTrial).
  65. Set("pro_trial_end_date", d.ProTrialEndDate.In(time.UTC).Format("2006-01-02")).
  66. Set("admin_email", adminEmail).
  67. Set("is_saas_tenant", d.IsSaasTenant),
  68. })
  69. }
  70. // FetchTelemetryData - fetches telemetry data: count of various object types in DB
  71. func FetchTelemetryData() telemetryData {
  72. var data telemetryData
  73. data.IsPro = servercfg.IsPro
  74. data.ExtClients = getDBLength(database.EXT_CLIENT_TABLE_NAME)
  75. data.Users = getDBLength(database.USERS_TABLE_NAME)
  76. data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
  77. data.Hosts = getDBLength(database.HOSTS_TABLE_NAME)
  78. data.Version = servercfg.GetVersion()
  79. data.Servers = getServerCount()
  80. nodes, _ := GetAllNodes()
  81. data.Nodes = len(nodes)
  82. data.Count = getClientCount(nodes)
  83. endDate, _ := GetTrialEndDate()
  84. data.ProTrialEndDate = endDate
  85. if endDate.After(time.Now()) {
  86. data.IsProTrial = true
  87. }
  88. data.IsSaasTenant = servercfg.DeployedByOperator()
  89. return data
  90. }
  91. // getServerCount returns number of servers from database
  92. func getServerCount() int {
  93. data, err := database.FetchRecords(database.SERVER_UUID_TABLE_NAME)
  94. if err != nil {
  95. logger.Log(0, "errror retrieving server data", err.Error())
  96. }
  97. return len(data)
  98. }
  99. // setTelemetryTimestamp - Give the entry in the DB a new timestamp
  100. func setTelemetryTimestamp(telRecord *models.Telemetry) error {
  101. lastsend := time.Now().Unix()
  102. var serverTelData = models.Telemetry{
  103. UUID: telRecord.UUID,
  104. LastSend: lastsend,
  105. TrafficKeyPriv: telRecord.TrafficKeyPriv,
  106. TrafficKeyPub: telRecord.TrafficKeyPub,
  107. }
  108. jsonObj, err := json.Marshal(&serverTelData)
  109. if err != nil {
  110. return err
  111. }
  112. err = database.Insert(database.SERVER_UUID_RECORD_KEY, string(jsonObj), database.SERVER_UUID_TABLE_NAME)
  113. return err
  114. }
  115. // getClientCount - returns counts of nodes with various OS types and conditions
  116. func getClientCount(nodes []models.Node) clientCount {
  117. var count clientCount
  118. for _, node := range nodes {
  119. host, err := GetHost(node.HostID.String())
  120. if err != nil {
  121. continue
  122. }
  123. switch host.OS {
  124. case "darwin":
  125. count.MacOS += 1
  126. case "windows":
  127. count.Windows += 1
  128. case "linux":
  129. count.Linux += 1
  130. case "freebsd":
  131. count.FreeBSD += 1
  132. }
  133. }
  134. return count
  135. }
  136. // FetchTelemetryRecord - get the existing UUID and Timestamp from the DB
  137. func FetchTelemetryRecord() (models.Telemetry, error) {
  138. var rawData string
  139. var telObj models.Telemetry
  140. var err error
  141. rawData, err = database.FetchRecord(database.SERVER_UUID_TABLE_NAME, database.SERVER_UUID_RECORD_KEY)
  142. if err != nil {
  143. return telObj, err
  144. }
  145. err = json.Unmarshal([]byte(rawData), &telObj)
  146. return telObj, err
  147. }
  148. // getDBLength - get length of DB to get count of objects
  149. func getDBLength(dbname string) int {
  150. data, err := database.FetchRecords(dbname)
  151. if err != nil {
  152. return 0
  153. }
  154. return len(data)
  155. }
  156. // telemetryData - What data to send to posthog
  157. type telemetryData struct {
  158. Nodes int
  159. Hosts int
  160. ExtClients int
  161. Users int
  162. Count clientCount
  163. Networks int
  164. Servers int
  165. Version string
  166. IsPro bool
  167. IsFreeTier bool
  168. IsProTrial bool
  169. ProTrialEndDate time.Time
  170. IsSaasTenant bool
  171. }
  172. // clientCount - What types of netclients we're tallying
  173. type clientCount struct {
  174. MacOS int
  175. Windows int
  176. Linux int
  177. FreeBSD int
  178. K8S int
  179. Docker int
  180. NonServer int
  181. }