tracks.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. package analytics
  2. import (
  3. "github.com/porter-dev/porter/api/types"
  4. segment "gopkg.in/segmentio/analytics-go.v3"
  5. )
  6. type segmentTrack interface {
  7. getUserId() string
  8. getEvent() SegmentEvent
  9. getProperties() segment.Properties
  10. }
  11. type defaultTrackOpts struct {
  12. AdditionalProps map[string]interface{}
  13. }
  14. type defaultSegmentTrack struct {
  15. event SegmentEvent
  16. properties segmentProperties
  17. }
  18. func getDefaultSegmentTrack(additionalProps map[string]interface{}, event SegmentEvent) *defaultSegmentTrack {
  19. props := newSegmentProperties()
  20. props.addAdditionalProperties(additionalProps)
  21. return &defaultSegmentTrack{
  22. event: event,
  23. properties: props,
  24. }
  25. }
  26. func (t *defaultSegmentTrack) getEvent() SegmentEvent {
  27. return t.event
  28. }
  29. func (t *defaultSegmentTrack) getProperties() segment.Properties {
  30. props := segment.NewProperties()
  31. for key, val := range t.properties {
  32. props = props.Set(key, val)
  33. }
  34. return props
  35. }
  36. type segmentProperties map[string]interface{}
  37. func newSegmentProperties() segmentProperties {
  38. props := make(map[string]interface{})
  39. return props
  40. }
  41. func (p segmentProperties) addProjectProperties(opts *ProjectScopedTrackOpts) {
  42. p["proj_id"] = opts.ProjectID
  43. }
  44. func (p segmentProperties) addClusterProperties(opts *ClusterScopedTrackOpts) {
  45. p["cluster_id"] = opts.ClusterID
  46. }
  47. func (p segmentProperties) addRegistryProperties(opts *RegistryScopedTrackOpts) {
  48. p["registry_id"] = opts.RegistryID
  49. }
  50. func (p segmentProperties) addApplicationProperties(opts *ApplicationScopedTrackOpts) {
  51. p["app_name"] = opts.Name
  52. p["app_namespace"] = opts.Namespace
  53. p["chart_name"] = opts.ChartName
  54. }
  55. func (p segmentProperties) addAdditionalProperties(props map[string]interface{}) {
  56. for key, val := range props {
  57. p[key] = val
  58. }
  59. }
  60. // UserCreateTrackOpts are the options for creating a track when a user is created
  61. type UserCreateTrackOpts struct {
  62. *UserScopedTrackOpts
  63. Email string
  64. FirstName string
  65. LastName string
  66. CompanyName string
  67. }
  68. // UserCreateTrack returns a track for when a user is created
  69. func UserCreateTrack(opts *UserCreateTrackOpts) segmentTrack {
  70. additionalProps := make(map[string]interface{})
  71. additionalProps["email"] = opts.Email
  72. additionalProps["name"] = opts.FirstName + " " + opts.LastName
  73. additionalProps["company"] = opts.CompanyName
  74. return getSegmentUserTrack(
  75. opts.UserScopedTrackOpts,
  76. getDefaultSegmentTrack(additionalProps, UserCreate),
  77. )
  78. }
  79. // UserCreateTrackOpts are the options for creating a track when a user's email is verified
  80. type UserVerifyEmailTrackOpts struct {
  81. *UserScopedTrackOpts
  82. Email string
  83. }
  84. // UserVerifyEmailTrack returns a track for when a user's email is verified
  85. func UserVerifyEmailTrack(opts *UserVerifyEmailTrackOpts) segmentTrack {
  86. additionalProps := make(map[string]interface{})
  87. additionalProps["email"] = opts.Email
  88. return getSegmentUserTrack(
  89. opts.UserScopedTrackOpts,
  90. getDefaultSegmentTrack(additionalProps, UserVerifyEmail),
  91. )
  92. }
  93. // ProjectCreateTrackOpts are the options for creating a track when a project is created
  94. type ProjectCreateTrackOpts struct {
  95. *ProjectScopedTrackOpts
  96. }
  97. // ProjectCreateTrack returns a track for when a project is created
  98. func ProjectCreateTrack(opts *ProjectCreateTrackOpts) segmentTrack {
  99. additionalProps := make(map[string]interface{})
  100. return getSegmentProjectTrack(
  101. opts.ProjectScopedTrackOpts,
  102. getDefaultSegmentTrack(additionalProps, ProjectCreate),
  103. )
  104. }
  105. // CostConsentTrackOpts are the options for creating a track when a user completes the cost consent
  106. type CostConsentTrackOpts struct {
  107. *UserScopedTrackOpts
  108. }
  109. // CostConsentTrack returns a track for when a user completes the cost consent
  110. func CostConsentTrack(opts *CostConsentTrackOpts) segmentTrack {
  111. additionalProps := make(map[string]interface{})
  112. return getSegmentUserTrack(
  113. opts.UserScopedTrackOpts,
  114. getDefaultSegmentTrack(additionalProps, CostConsentComplete),
  115. )
  116. }
  117. // CredentialStepTrackOpts are the options for creating a track when a user completes the credential step
  118. type CredentialStepTrackOpts struct {
  119. *UserScopedTrackOpts
  120. }
  121. // CredentialStepTrack returns a track for when a user completes the credential step
  122. func CredentialStepTrack(opts *CredentialStepTrackOpts) segmentTrack {
  123. additionalProps := make(map[string]interface{})
  124. return getSegmentUserTrack(
  125. opts.UserScopedTrackOpts,
  126. getDefaultSegmentTrack(additionalProps, CredentialStepComplete),
  127. )
  128. }
  129. // PreProvisionCheckTrackOpts are the options for creating a track when a user checks if they can provision
  130. type PreProvisionCheckTrackOpts struct {
  131. *UserScopedTrackOpts
  132. Email string
  133. FirstName string
  134. LastName string
  135. CompanyName string
  136. }
  137. // PreProvisionCheckTrack returns a track for when a user attempts provisioning
  138. func PreProvisionCheckTrack(opts *PreProvisionCheckTrackOpts) segmentTrack {
  139. additionalProps := make(map[string]interface{})
  140. additionalProps["email"] = opts.Email
  141. additionalProps["name"] = opts.FirstName + " " + opts.LastName
  142. additionalProps["company"] = opts.CompanyName
  143. return getSegmentUserTrack(
  144. opts.UserScopedTrackOpts,
  145. getDefaultSegmentTrack(additionalProps, PreProvisionCheck),
  146. )
  147. }
  148. // ProvisioningAttemptedTrackOpts are the options for creating a track when a user attempts provisioning
  149. type ProvisioningAttemptTrackOpts struct {
  150. *UserScopedTrackOpts
  151. Email string
  152. FirstName string
  153. LastName string
  154. CompanyName string
  155. }
  156. // ProvisioningAttemptTrack returns a track for when a user attempts provisioning
  157. func ProvisioningAttemptTrack(opts *ProvisioningAttemptTrackOpts) segmentTrack {
  158. additionalProps := make(map[string]interface{})
  159. additionalProps["email"] = opts.Email
  160. additionalProps["name"] = opts.FirstName + " " + opts.LastName
  161. additionalProps["company"] = opts.CompanyName
  162. return getSegmentUserTrack(
  163. opts.UserScopedTrackOpts,
  164. getDefaultSegmentTrack(additionalProps, ProvisioningAttempted),
  165. )
  166. }
  167. // ClusterProvisioningStartTrackOpts are the options for creating a track when a cluster
  168. // has started provisioning
  169. type ClusterProvisioningStartTrackOpts struct {
  170. // note that this is a project-scoped track, since the cluster has not been created yet
  171. *ProjectScopedTrackOpts
  172. ClusterType types.InfraKind
  173. InfraID uint
  174. }
  175. // ClusterProvisioningStartTrack returns a track for when a cluster
  176. // has started provisioning
  177. func ClusterProvisioningStartTrack(opts *ClusterProvisioningStartTrackOpts) segmentTrack {
  178. additionalProps := make(map[string]interface{})
  179. additionalProps["cluster_type"] = opts.ClusterType
  180. additionalProps["infra_id"] = opts.InfraID
  181. return getSegmentProjectTrack(
  182. opts.ProjectScopedTrackOpts,
  183. getDefaultSegmentTrack(additionalProps, ClusterProvisioningStart),
  184. )
  185. }
  186. // ClusterProvisioningErrorTrackOpts are the options for creating a track when a cluster
  187. // has experienced a provisioning error
  188. type ClusterProvisioningErrorTrackOpts struct {
  189. // note that this is a project-scoped track, since the cluster has not been created yet
  190. *ProjectScopedTrackOpts
  191. ClusterType types.InfraKind
  192. InfraID uint
  193. }
  194. // ClusterProvisioningErrorTrack returns a track for when a cluster
  195. // has experienced a provisioning error
  196. func ClusterProvisioningErrorTrack(opts *ClusterProvisioningErrorTrackOpts) segmentTrack {
  197. additionalProps := make(map[string]interface{})
  198. additionalProps["cluster_type"] = opts.ClusterType
  199. additionalProps["infra_id"] = opts.InfraID
  200. return getSegmentProjectTrack(
  201. opts.ProjectScopedTrackOpts,
  202. getDefaultSegmentTrack(additionalProps, ClusterProvisioningError),
  203. )
  204. }
  205. // ClusterProvisioningSuccessTrackOpts are the options for creating a track when a cluster
  206. // has successfully provisioned
  207. type ClusterProvisioningSuccessTrackOpts struct {
  208. *ClusterScopedTrackOpts
  209. ClusterType types.InfraKind
  210. InfraID uint
  211. }
  212. // ClusterProvisioningSuccessTrack returns a new track for when a cluster
  213. // has successfully provisioned
  214. func ClusterProvisioningSuccessTrack(opts *ClusterProvisioningSuccessTrackOpts) segmentTrack {
  215. additionalProps := make(map[string]interface{})
  216. additionalProps["cluster_type"] = opts.ClusterType
  217. additionalProps["infra_id"] = opts.InfraID
  218. return getSegmentClusterTrack(
  219. opts.ClusterScopedTrackOpts,
  220. getDefaultSegmentTrack(additionalProps, ClusterProvisioningSuccess),
  221. )
  222. }
  223. // ClusterConnectionStartTrackOpts are the options for creating a track when a cluster
  224. // connection has started
  225. type ClusterConnectionStartTrackOpts struct {
  226. // note that this is a project-scoped track, since the cluster has not been created yet
  227. *ProjectScopedTrackOpts
  228. ClusterCandidateID uint
  229. }
  230. // ClusterConnectionStartTrack returns a new track for when a cluster
  231. // connection has started
  232. func ClusterConnectionStartTrack(opts *ClusterConnectionStartTrackOpts) segmentTrack {
  233. additionalProps := make(map[string]interface{})
  234. additionalProps["cc_id"] = opts.ClusterCandidateID
  235. return getSegmentProjectTrack(
  236. opts.ProjectScopedTrackOpts,
  237. getDefaultSegmentTrack(additionalProps, ClusterConnectionStart),
  238. )
  239. }
  240. // ClusterConnectionSuccessTrackOpts are the options for creating a track when a cluster
  241. // connection has finished
  242. type ClusterConnectionSuccessTrackOpts struct {
  243. *ClusterScopedTrackOpts
  244. ClusterCandidateID uint
  245. }
  246. // ClusterConnectionSuccessTrack returns a new track for when a cluster
  247. // connection has finished
  248. func ClusterConnectionSuccessTrack(opts *ClusterConnectionSuccessTrackOpts) segmentTrack {
  249. additionalProps := make(map[string]interface{})
  250. additionalProps["cc_id"] = opts.ClusterCandidateID
  251. return getSegmentClusterTrack(
  252. opts.ClusterScopedTrackOpts,
  253. getDefaultSegmentTrack(additionalProps, ClusterConnectionSuccess),
  254. )
  255. }
  256. // RegistryConnectionStartTrackOpts are the options for creating a track when a registry
  257. // connection has started
  258. type RegistryConnectionStartTrackOpts struct {
  259. // note that this is a project-scoped track, since the cluster has not been created yet
  260. *ProjectScopedTrackOpts
  261. // a random id assigned to this connection request
  262. FlowID string
  263. }
  264. // RegistryConnectionStartTrack returns a new track for when a registry
  265. // connection has started
  266. func RegistryConnectionStartTrack(opts *RegistryConnectionStartTrackOpts) segmentTrack {
  267. additionalProps := make(map[string]interface{})
  268. additionalProps["flow_id"] = opts.FlowID
  269. return getSegmentProjectTrack(
  270. opts.ProjectScopedTrackOpts,
  271. getDefaultSegmentTrack(additionalProps, RegistryConnectionStart),
  272. )
  273. }
  274. // RegistryConnectionSuccessTrackOpts are the options for creating a track when a registry
  275. // connection has completed
  276. type RegistryConnectionSuccessTrackOpts struct {
  277. *RegistryScopedTrackOpts
  278. // a random id assigned to this connection request
  279. FlowID string
  280. }
  281. // RegistryConnectionSuccessTrack returns a new track for when a registry
  282. // connection has completed
  283. func RegistryConnectionSuccessTrack(opts *RegistryConnectionSuccessTrackOpts) segmentTrack {
  284. additionalProps := make(map[string]interface{})
  285. additionalProps["flow_id"] = opts.FlowID
  286. return getSegmentRegistryTrack(
  287. opts.RegistryScopedTrackOpts,
  288. getDefaultSegmentTrack(additionalProps, RegistryConnectionSuccess),
  289. )
  290. }
  291. // GithubConnectionStartTrackOpts are the options for creating a track when a github account
  292. // connection has started
  293. type GithubConnectionStartTrackOpts struct {
  294. // note that this is a user-scoped track, since github repos are tied to the user
  295. *UserScopedTrackOpts
  296. }
  297. // GithubConnectionStartTrack returns a new track for when a github account
  298. // connection has started
  299. func GithubConnectionStartTrack(opts *GithubConnectionStartTrackOpts) segmentTrack {
  300. additionalProps := make(map[string]interface{})
  301. return getSegmentUserTrack(
  302. opts.UserScopedTrackOpts,
  303. getDefaultSegmentTrack(additionalProps, GithubConnectionStart),
  304. )
  305. }
  306. // GithubConnectionSuccessTrackOpts are the options for creating a track when a github account
  307. // connection has completed
  308. type GithubConnectionSuccessTrackOpts struct {
  309. // note that this is a user-scoped track, since github repos are tied to the user
  310. *UserScopedTrackOpts
  311. }
  312. // GithubConnectionSuccessTrack returns a new track when a github account
  313. // connection has completed
  314. func GithubConnectionSuccessTrack(opts *GithubConnectionSuccessTrackOpts) segmentTrack {
  315. additionalProps := make(map[string]interface{})
  316. return getSegmentUserTrack(
  317. opts.UserScopedTrackOpts,
  318. getDefaultSegmentTrack(additionalProps, GithubConnectionSuccess),
  319. )
  320. }
  321. // ApplicationLaunchStartTrackOpts are the options for creating a track when an application
  322. // launch has started
  323. type ApplicationLaunchStartTrackOpts struct {
  324. *ClusterScopedTrackOpts
  325. FlowID string
  326. }
  327. // ApplicationLaunchStartTrack returns a new track for when an application
  328. // launch has started
  329. func ApplicationLaunchStartTrack(opts *ApplicationLaunchStartTrackOpts) segmentTrack {
  330. additionalProps := make(map[string]interface{})
  331. additionalProps["flow_id"] = opts.FlowID
  332. return getSegmentClusterTrack(
  333. opts.ClusterScopedTrackOpts,
  334. getDefaultSegmentTrack(additionalProps, ApplicationLaunchStart),
  335. )
  336. }
  337. // ApplicationLaunchSuccessTrackOpts are the options for creating a track when an application
  338. // launch has completed
  339. type ApplicationLaunchSuccessTrackOpts struct {
  340. *ApplicationScopedTrackOpts
  341. FlowID string
  342. }
  343. // ApplicationLaunchSuccessTrack returns a new track for when an application
  344. // launch has completed
  345. func ApplicationLaunchSuccessTrack(opts *ApplicationLaunchSuccessTrackOpts) segmentTrack {
  346. additionalProps := make(map[string]interface{})
  347. additionalProps["flow_id"] = opts.FlowID
  348. return getSegmentApplicationTrack(
  349. opts.ApplicationScopedTrackOpts,
  350. getDefaultSegmentTrack(additionalProps, ApplicationLaunchSuccess),
  351. )
  352. }
  353. // ApplicationDeploymentWebhookTrackOpts are the options for creating a track when an application
  354. // launch has completed from a webhook
  355. type ApplicationDeploymentWebhookTrackOpts struct {
  356. *ApplicationScopedTrackOpts
  357. ImageURI string
  358. }
  359. // ApplicationDeploymentWebhookTrack returns a new track for when an application
  360. // launch has completed from a webhook
  361. func ApplicationDeploymentWebhookTrack(opts *ApplicationDeploymentWebhookTrackOpts) segmentTrack {
  362. additionalProps := make(map[string]interface{})
  363. additionalProps["image_uri"] = opts.ImageURI
  364. return getSegmentApplicationTrack(
  365. opts.ApplicationScopedTrackOpts,
  366. getDefaultSegmentTrack(additionalProps, ApplicationDeploymentWebhook),
  367. )
  368. }
  369. // RegistryProvisioningStartTrackOpts are the options for creating a track when a registry
  370. // provisioning has started
  371. type RegistryProvisioningStartTrackOpts struct {
  372. // note that this is a project-scoped track, since the registry has not been created yet
  373. *ProjectScopedTrackOpts
  374. RegistryType types.InfraKind
  375. InfraID uint
  376. }
  377. // RegistryProvisioningStartTrack returns a new track for when a registry
  378. // provisioning has started
  379. func RegistryProvisioningStartTrack(opts *RegistryProvisioningStartTrackOpts) segmentTrack {
  380. additionalProps := make(map[string]interface{})
  381. additionalProps["registry_type"] = opts.RegistryType
  382. additionalProps["infra_id"] = opts.InfraID
  383. return getSegmentProjectTrack(
  384. opts.ProjectScopedTrackOpts,
  385. getDefaultSegmentTrack(additionalProps, RegistryProvisioningStart),
  386. )
  387. }
  388. // RegistryProvisioningErrorTrackOpts are the options for creating a track when a registry
  389. // provisioning has failed
  390. type RegistryProvisioningErrorTrackOpts struct {
  391. // note that this is a project-scoped track, since the registry has not been created yet
  392. *ProjectScopedTrackOpts
  393. RegistryType types.InfraKind
  394. InfraID uint
  395. }
  396. // RegistryProvisioningErrorTrack returns a new track for when a registry
  397. // provisioning has failed
  398. func RegistryProvisioningErrorTrack(opts *RegistryProvisioningErrorTrackOpts) segmentTrack {
  399. additionalProps := make(map[string]interface{})
  400. additionalProps["registry_type"] = opts.RegistryType
  401. additionalProps["infra_id"] = opts.InfraID
  402. return getSegmentProjectTrack(
  403. opts.ProjectScopedTrackOpts,
  404. getDefaultSegmentTrack(additionalProps, RegistryProvisioningError),
  405. )
  406. }
  407. // RegistryProvisioningSuccessTrackOpts are the options for creating a track when a registry
  408. // provisioning has completed
  409. type RegistryProvisioningSuccessTrackOpts struct {
  410. *RegistryScopedTrackOpts
  411. RegistryType types.InfraKind
  412. InfraID uint
  413. }
  414. // RegistryProvisioningSuccessTrack returns a new track for when a registry
  415. // provisioning has completed
  416. func RegistryProvisioningSuccessTrack(opts *RegistryProvisioningSuccessTrackOpts) segmentTrack {
  417. additionalProps := make(map[string]interface{})
  418. additionalProps["registry_type"] = opts.RegistryType
  419. additionalProps["infra_id"] = opts.InfraID
  420. return getSegmentRegistryTrack(
  421. opts.RegistryScopedTrackOpts,
  422. getDefaultSegmentTrack(additionalProps, RegistryProvisioningSuccess),
  423. )
  424. }
  425. // ClusterDestroyingStartTrackOpts are the options for creating a track when a cluster
  426. // has started destroying
  427. type ClusterDestroyingStartTrackOpts struct {
  428. *ClusterScopedTrackOpts
  429. ClusterType types.InfraKind
  430. InfraID uint
  431. }
  432. // ClusterDestroyingStartTrack returns a track for when a cluster
  433. // has started destroying
  434. func ClusterDestroyingStartTrack(opts *ClusterDestroyingStartTrackOpts) segmentTrack {
  435. additionalProps := make(map[string]interface{})
  436. additionalProps["cluster_type"] = opts.ClusterType
  437. additionalProps["infra_id"] = opts.InfraID
  438. return getSegmentClusterTrack(
  439. opts.ClusterScopedTrackOpts,
  440. getDefaultSegmentTrack(additionalProps, ClusterDestroyingStart),
  441. )
  442. }
  443. // ClusterDestroyingSuccessTrackOpts are the options for creating a track when a cluster
  444. // has successfully provisioned
  445. type ClusterDestroyingSuccessTrackOpts struct {
  446. *ClusterScopedTrackOpts
  447. ClusterType types.InfraKind
  448. InfraID uint
  449. }
  450. // ClusterDestroyingSuccessTrack returns a new track for when a cluster
  451. // has successfully provisioned
  452. func ClusterDestroyingSuccessTrack(opts *ClusterDestroyingSuccessTrackOpts) segmentTrack {
  453. additionalProps := make(map[string]interface{})
  454. additionalProps["cluster_type"] = opts.ClusterType
  455. additionalProps["infra_id"] = opts.InfraID
  456. return getSegmentClusterTrack(
  457. opts.ClusterScopedTrackOpts,
  458. getDefaultSegmentTrack(additionalProps, ClusterDestroyingSuccess),
  459. )
  460. }