telemetry.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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("email", adminEmail). // needed for posthog intgration with hubspot. "admin_email" can only be removed if not used in posthog
  68. Set("is_saas_tenant", d.IsSaasTenant),
  69. })
  70. }
  71. // FetchTelemetryData - fetches telemetry data: count of various object types in DB
  72. func FetchTelemetryData() telemetryData {
  73. var data telemetryData
  74. data.IsPro = servercfg.IsPro
  75. data.ExtClients = getDBLength(database.EXT_CLIENT_TABLE_NAME)
  76. data.Users = getDBLength(database.USERS_TABLE_NAME)
  77. data.Networks = getDBLength(database.NETWORKS_TABLE_NAME)
  78. data.Hosts = getDBLength(database.HOSTS_TABLE_NAME)
  79. data.Version = servercfg.GetVersion()
  80. data.Servers = getServerCount()
  81. nodes, _ := GetAllNodes()
  82. data.Nodes = len(nodes)
  83. data.Count = getClientCount(nodes)
  84. endDate, _ := GetTrialEndDate()
  85. data.ProTrialEndDate = endDate
  86. if endDate.After(time.Now()) {
  87. data.IsProTrial = true
  88. }
  89. data.IsSaasTenant = servercfg.DeployedByOperator()
  90. return data
  91. }
  92. // getServerCount returns number of servers from database
  93. func getServerCount() int {
  94. data, err := database.FetchRecords(database.SERVER_UUID_TABLE_NAME)
  95. if err != nil {
  96. logger.Log(0, "error retrieving server data", err.Error())
  97. }
  98. return len(data)
  99. }
  100. // setTelemetryTimestamp - Give the entry in the DB a new timestamp
  101. func setTelemetryTimestamp(telRecord *models.Telemetry) error {
  102. lastsend := time.Now().Unix()
  103. var serverTelData = models.Telemetry{
  104. UUID: telRecord.UUID,
  105. LastSend: lastsend,
  106. TrafficKeyPriv: telRecord.TrafficKeyPriv,
  107. TrafficKeyPub: telRecord.TrafficKeyPub,
  108. }
  109. jsonObj, err := json.Marshal(&serverTelData)
  110. if err != nil {
  111. return err
  112. }
  113. err = database.Insert(database.SERVER_UUID_RECORD_KEY, string(jsonObj), database.SERVER_UUID_TABLE_NAME)
  114. return err
  115. }
  116. // getClientCount - returns counts of nodes with various OS types and conditions
  117. func getClientCount(nodes []models.Node) clientCount {
  118. var count clientCount
  119. for _, node := range nodes {
  120. host, err := GetHost(node.HostID.String())
  121. if err != nil {
  122. continue
  123. }
  124. switch host.OS {
  125. case "darwin":
  126. count.MacOS += 1
  127. case "windows":
  128. count.Windows += 1
  129. case "linux":
  130. count.Linux += 1
  131. case "freebsd":
  132. count.FreeBSD += 1
  133. }
  134. }
  135. return count
  136. }
  137. // FetchTelemetryRecord - get the existing UUID and Timestamp from the DB
  138. func FetchTelemetryRecord() (models.Telemetry, error) {
  139. var rawData string
  140. var telObj models.Telemetry
  141. var err error
  142. rawData, err = database.FetchRecord(database.SERVER_UUID_TABLE_NAME, database.SERVER_UUID_RECORD_KEY)
  143. if err != nil {
  144. return telObj, err
  145. }
  146. err = json.Unmarshal([]byte(rawData), &telObj)
  147. return telObj, err
  148. }
  149. // getDBLength - get length of DB to get count of objects
  150. func getDBLength(dbname string) int {
  151. data, err := database.FetchRecords(dbname)
  152. if err != nil {
  153. return 0
  154. }
  155. return len(data)
  156. }
  157. // telemetryData - What data to send to posthog
  158. type telemetryData struct {
  159. Nodes int
  160. Hosts int
  161. ExtClients int
  162. Users int
  163. Count clientCount
  164. Networks int
  165. Servers int
  166. Version string
  167. IsPro bool
  168. IsFreeTier bool
  169. IsProTrial bool
  170. ProTrialEndDate time.Time
  171. IsSaasTenant bool
  172. }
  173. // clientCount - What types of netclients we're tallying
  174. type clientCount struct {
  175. MacOS int
  176. Windows int
  177. Linux int
  178. FreeBSD int
  179. K8S int
  180. Docker int
  181. NonServer int
  182. }