From 07e8b1e294f026ec7e12964775fcd2b1a3a56df8 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Mon, 18 Jan 2021 23:06:14 +0530 Subject: [PATCH] Add GUI metrics to Button.js and refactor metrics tracker and frontend metric architecture (part of #508) (#642) * 1 - changes from existing PR 582 * 2 - changes from my comments on PR * 3 - pass in correct baseURL to sendMetricEvent from Button.js * 4 - fix check for metrics when in local dev mode (no metrics tracker) * 5 - metrics tracker should throw when amplitude returns invalid response * 6 - fix API usage of /sendMetricEvent * 7 - warn when no event name on button * 8 - use correct event name type and data across the frontend, API, backend * 9 - simplify metrics tracker event props naming * 10 - refactor and simplify metricsTracker factory methods to use a single factory method this ensures we do not send cli props for gui actions etc since they are separated * 11 - prefix gui specific event properties as gui_ * 12 - isTestnet should be hardcoded to true by default * 13 - change warning when no event name to an error * 14 - set button names for welcome screen * 15 - set button names for all remaining buttons by threading eventPrefix * 16 - rename event_name to gui_event_name * 17 - fix warnings in Button.js --- cmd/server_amd64.go | 35 ++- cmd/trade.go | 103 +++---- gui/backend/send_metric_event.go | 6 +- gui/web/src/App.js | 12 +- gui/web/src/Constants.js | 12 +- gui/web/src/components/atoms/Button/Button.js | 58 +++- .../components/atoms/StartStop/StartStop.js | 7 +- .../components/molecules/BotCard/BotCard.js | 3 + .../molecules/EmptyList/EmptyList.js | 4 +- gui/web/src/components/molecules/Form/Form.js | 20 +- .../src/components/molecules/Header/Header.js | 14 - .../src/components/molecules/Levels/Levels.js | 5 +- .../src/components/molecules/Modal/Modal.js | 10 +- .../PriceFeedAsset/PriceFeedAsset.js | 3 + .../PriceFeedDisplay/PriceFeedDisplay.js | 6 +- .../molecules/ScreenHeader/ScreenHeader.js | 1 + .../molecules/SecretKey/SecretKey.js | 4 +- .../components/molecules/Welcome/Welcome.js | 6 +- gui/web/src/components/screens/Bots/Bots.js | 1 + .../src/components/screens/Details/Details.js | 35 ++- .../src/components/screens/NewBot/NewBot.js | 2 + gui/web/src/kelp-ops-api/sendMetricEvent.js | 10 +- plugins/metricsTracker.go | 279 +++++++++--------- 23 files changed, 357 insertions(+), 279 deletions(-) diff --git a/cmd/server_amd64.go b/cmd/server_amd64.go index edff4cae4..d5c0eccb4 100644 --- a/cmd/server_amd64.go +++ b/cmd/server_amd64.go @@ -298,24 +298,27 @@ func init() { if e != nil { panic(fmt.Errorf("could not generate machine id: %s", e)) } - - httpClient := &http.Client{} - metricsTracker, e = plugins.MakeMetricsTrackerGui( - deviceID, - deviceID, + userID := deviceID // reuse for now + metricsTracker, e = plugins.MakeMetricsTracker( + http.DefaultClient, amplitudeAPIKey, - httpClient, - time.Now(), // TODO: Find proper time. - version, - gitHash, - env, - runtime.GOOS, - runtime.GOARCH, - "unknown_todo", // TODO DS Determine how to get GOARM. - runtime.Version(), - guiVersion, + userID, + deviceID, + time.Now(), // TODO: Find proper time. *options.noHeaders, // disable metrics if the CLI specified no headers - + plugins.MakeCommonProps( + version, + gitHash, + env, + runtime.GOOS, + runtime.GOARCH, + "unknown_todo", // TODO DS Determine how to get GOARM. + runtime.Version(), + 0, + true, // isTestnet hardcoded to true for now, but once we allow it on the GUI via enablePubnetBots then this should be set accordingly + guiVersion, + ), + nil, ) if e != nil { panic(e) diff --git a/cmd/trade.go b/cmd/trade.go index b95c8cba0..66cb19e10 100644 --- a/cmd/trade.go +++ b/cmd/trade.go @@ -243,7 +243,7 @@ func makeFeeFn(l logger.Logger, botConfig trader.BotConfig, newClient *horizoncl return feeFn } -func readBotConfig(l logger.Logger, options inputs, botStart time.Time) trader.BotConfig { +func readBotConfig(l logger.Logger, options inputs, botStartTime time.Time) trader.BotConfig { var botConfig trader.BotConfig e := config.Read(*options.botConfigPath, &botConfig) utils.CheckConfigError(botConfig, e, *options.botConfigPath) @@ -253,7 +253,7 @@ func readBotConfig(l logger.Logger, options inputs, botStart time.Time) trader.B } if *options.logPrefix != "" { - logFilename := makeLogFilename(*options.logPrefix, botConfig, botStart) + logFilename := makeLogFilename(*options.logPrefix, botConfig, botStartTime) setLogFile(l, logFilename) } @@ -427,7 +427,7 @@ func makeBot( threadTracker *multithreading.ThreadTracker, options inputs, metricsTracker *plugins.MetricsTracker, - botStart time.Time, + botStartTime time.Time, ) *trader.Trader { timeController := plugins.MakeIntervalTimeController( time.Duration(botConfig.TickIntervalMillis)*time.Millisecond, @@ -530,7 +530,7 @@ func makeBot( dataKey, alert, metricsTracker, - botStart, + botStartTime, ) } @@ -558,66 +558,67 @@ func convertDeprecatedBotConfigValues(l logger.Logger, botConfig trader.BotConfi func runTradeCmd(options inputs) { l := logger.MakeBasicLogger() - botStart := time.Now() - botConfig := readBotConfig(l, options, botStart) + botStartTime := time.Now() + botConfig := readBotConfig(l, options, botStartTime) botConfig = convertDeprecatedBotConfigValues(l, botConfig) l.Infof("Trading %s:%s for %s:%s\n", botConfig.AssetCodeA, botConfig.IssuerA, botConfig.AssetCodeB, botConfig.IssuerB) - userID, e := getUserID(l, botConfig) - if e != nil { - logger.Fatal(l, fmt.Errorf("could not get user id: %s", e)) - } - - httpClient := &http.Client{} var guiVersionFlag string if *options.ui { guiVersionFlag = guiVersion } + userID, e := getUserID(l, botConfig) + if e != nil { + logger.Fatal(l, fmt.Errorf("could not get user id: %s", e)) + } deviceID, e := machineid.ID() if e != nil { logger.Fatal(l, fmt.Errorf("could not generate machine id: %s", e)) } - isTestnet := strings.Contains(botConfig.HorizonURL, "test") && botConfig.IsTradingSdex() - - metricsTracker, e := plugins.MakeMetricsTrackerCli( + metricsTracker, e := plugins.MakeMetricsTracker( + http.DefaultClient, + amplitudeAPIKey, userID, deviceID, - amplitudeAPIKey, - httpClient, - botStart, - version, - gitHash, - env, - runtime.GOOS, - runtime.GOARCH, - goarm, - runtime.Version(), - guiVersionFlag, - *options.strategy, - float64(botConfig.TickIntervalMillis)/1000, - botConfig.TradingExchange, - botConfig.TradingPair(), + botStartTime, *options.noHeaders, // disable metrics if the CLI specified no headers - isTestnet, - botConfig.MaxTickDelayMillis, - botConfig.SubmitMode, - botConfig.DeleteCyclesThreshold, - botConfig.FillTrackerSleepMillis, - botConfig.FillTrackerDeleteCyclesThreshold, - botConfig.SynchronizeStateLoadEnable, - botConfig.SynchronizeStateLoadMaxRetries, - botConfig.DollarValueFeedBaseAsset != "" && botConfig.DollarValueFeedQuoteAsset != "", - botConfig.AlertType, - int(botConfig.MonitoringPort) != 0, - len(botConfig.Filters) > 0, - botConfig.PostgresDbConfig != nil, - *options.logPrefix != "", - *options.operationalBuffer, - *options.operationalBufferNonNativePct, - *options.simMode, - *options.fixedIterations, + plugins.MakeCommonProps( + version, + gitHash, + env, + runtime.GOOS, + runtime.GOARCH, + goarm, + runtime.Version(), + 0, + isTestnet, + guiVersionFlag, + ), + plugins.MakeCliProps( + *options.strategy, + float64(botConfig.TickIntervalMillis)/1000, + botConfig.TradingExchange, + botConfig.TradingPair(), + botConfig.MaxTickDelayMillis, + botConfig.SubmitMode, + botConfig.DeleteCyclesThreshold, + botConfig.FillTrackerSleepMillis, + botConfig.FillTrackerDeleteCyclesThreshold, + botConfig.SynchronizeStateLoadEnable, + botConfig.SynchronizeStateLoadMaxRetries, + botConfig.DollarValueFeedBaseAsset != "" && botConfig.DollarValueFeedQuoteAsset != "", + botConfig.AlertType, + int(botConfig.MonitoringPort) != 0, + len(botConfig.Filters) > 0, + botConfig.PostgresDbConfig != nil, + *options.logPrefix != "", + *options.operationalBuffer, + *options.operationalBufferNonNativePct, + *options.simMode, + *options.fixedIterations, + ), ) if e != nil { logger.Fatal(l, fmt.Errorf("could not generate metrics tracker: %s", e)) @@ -774,7 +775,7 @@ func runTradeCmd(options inputs) { threadTracker, options, metricsTracker, - botStart, + botStartTime, ) // --- end initialization of objects --- // --- start initialization of services --- @@ -1048,8 +1049,8 @@ func setLogFile(l logger.Logger, filename string) { defer logPanic(l, false) } -func makeLogFilename(logPrefix string, botConfig trader.BotConfig, botStart time.Time) string { - botStartStr := botStart.Format("20060102T150405MST") +func makeLogFilename(logPrefix string, botConfig trader.BotConfig, botStartTime time.Time) string { + botStartStr := botStartTime.Format("20060102T150405MST") if botConfig.IsTradingSdex() { return fmt.Sprintf("%s_%s_%s_%s_%s_%s.log", logPrefix, botConfig.AssetCodeA, botConfig.IssuerA, botConfig.AssetCodeB, botConfig.IssuerB, botStartStr) } diff --git a/gui/backend/send_metric_event.go b/gui/backend/send_metric_event.go index 1abb2f0bc..3c00c2d65 100644 --- a/gui/backend/send_metric_event.go +++ b/gui/backend/send_metric_event.go @@ -10,7 +10,7 @@ import ( ) type sendMetricEventRequest struct { - EventName string `json:"event_name"` + EventType string `json:"event_type"` EventData map[string]interface{} `json:"event_data"` } @@ -34,9 +34,9 @@ func (s *APIServer) sendMetricEvent(w http.ResponseWriter, r *http.Request) { } // TODO DS Properly extract and compute time for SendEvent - e = s.metricsTracker.SendEvent(req.EventName, req.EventData, time.Now()) + e = s.metricsTracker.SendEvent(req.EventType, req.EventData, time.Now()) if e != nil { - s.writeErrorJson(w, fmt.Sprintf("error sending gui event %s: %s", req.EventName, e)) + s.writeErrorJson(w, fmt.Sprintf("error sending gui event %s: %s", string(bodyBytes), e)) return } diff --git a/gui/web/src/App.js b/gui/web/src/App.js index 35d86445d..033b632da 100644 --- a/gui/web/src/App.js +++ b/gui/web/src/App.js @@ -13,13 +13,14 @@ import removeKelpErrors from './kelp-ops-api/removeKelpErrors'; import Welcome from './components/molecules/Welcome/Welcome'; let baseUrl = function () { - let origin = window.location.origin + let base_url = window.location.origin; if (process.env.REACT_APP_API_PORT) { - let parts = origin.split(":") - return parts[0] + ":" + parts[1] + ":" + process.env.REACT_APP_API_PORT; + let parts = origin.split(":"); + base_url = parts[0] + ":" + parts[1] + ":" + process.env.REACT_APP_API_PORT; } - return origin; -}() + Constants.setGlobalBaseURL(base_url); + return base_url; +}(); class App extends Component { constructor(props) { @@ -296,6 +297,7 @@ class App extends Component { let banner = (