diff --git a/cmd/exchange_template/wrapper_file.tmpl b/cmd/exchange_template/wrapper_file.tmpl index 672ad855..eb6836b4 100644 --- a/cmd/exchange_template/wrapper_file.tmpl +++ b/cmd/exchange_template/wrapper_file.tmpl @@ -24,9 +24,9 @@ func ({{.Variable}} *{{.CapitalName}}) Start(wg *sync.WaitGroup) { // Run implements the {{.CapitalName}} wrapper func ({{.Variable}} *{{.CapitalName}}) Run() { if {{.Variable}}.Verbose { -{{if .WS}} log.Debugf("%s Websocket: %s. (url: %s).\n", {{.Variable}}.GetName(), common.IsEnabled({{.Variable}}.Websocket.IsEnabled()), {{.Variable}}.Websocket.GetWebsocketURL()) {{end}} - log.Debugf("%s polling delay: %ds.\n", {{.Variable}}.GetName(), {{.Variable}}.RESTPollingDelay) - log.Debugf("%s %d currencies enabled: %s.\n", {{.Variable}}.GetName(), len({{.Variable}}.EnabledPairs), {{.Variable}}.EnabledPairs) +{{if .WS}} log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", {{.Variable}}.GetName(), common.IsEnabled({{.Variable}}.Websocket.IsEnabled()), {{.Variable}}.Websocket.GetWebsocketURL()) {{end}} + log.Debugf(log.ExchangeSys, "%s polling delay: %ds.\n", {{.Variable}}.GetName(), {{.Variable}}.RESTPollingDelay) + log.Debugf(log.ExchangeSys, "%s %d currencies enabled: %s.\n", {{.Variable}}.GetName(), len({{.Variable}}.EnabledPairs), {{.Variable}}.EnabledPairs) } } diff --git a/cmd/gctcli/commands.go b/cmd/gctcli/commands.go index 1cae5f76..a7ab413f 100644 --- a/cmd/gctcli/commands.go +++ b/cmd/gctcli/commands.go @@ -1948,3 +1948,104 @@ var withdrawFiatFundsCommand = cli.Command{ func withdrawFiatFunds(_ *cli.Context) error { return common.ErrNotYetImplemented } + +var getLoggerDetailsCommand = cli.Command{ + Name: "getloggerdetails", + Action: getLoggerDetails, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "logger", + Usage: "logger to get level details of", + }, + }, +} + +func getLoggerDetails(c *cli.Context) error { + if c.NArg() == 0 && c.NumFlags() == 0 { + cli.ShowCommandHelp(c, "getloggerdetails") + return nil + } + + var logger string + if c.IsSet("logger") { + logger = c.String("logger") + } else { + logger = c.Args().First() + } + + conn, err := setupClient() + if err != nil { + return err + } + defer conn.Close() + + client := gctrpc.NewGoCryptoTraderClient(conn) + + result, err := client.GetLoggerDetails(context.Background(), + &gctrpc.GetLoggerDetailsRequest{ + Logger: logger, + }, + ) + if err != nil { + return err + } + jsonOutput(result) + return nil +} + +var setLoggerDetailsCommand = cli.Command{ + Name: "setloggerdetails", + Action: setLoggerDetails, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "logger", + Usage: "logger to get level details of", + }, + cli.StringFlag{ + Name: "flags", + Usage: "pipe separated value of loggers e.g INFO|WARN", + }, + }, +} + +func setLoggerDetails(c *cli.Context) error { + if c.NArg() == 0 && c.NumFlags() == 0 { + cli.ShowCommandHelp(c, "setloggerdetails") + return nil + } + + var logger string + var level string + + if c.IsSet("logger") { + logger = c.String("logger") + } else { + logger = c.Args().First() + } + + if c.IsSet("level") { + level = c.String("level") + } else { + level = c.Args().Get(1) + } + + conn, err := setupClient() + if err != nil { + return err + } + defer conn.Close() + + client := gctrpc.NewGoCryptoTraderClient(conn) + + result, err := client.SetLoggerDetails(context.Background(), + &gctrpc.SetLoggerDetailsRequest{ + Logger: logger, + Level: level, + }, + ) + if err != nil { + return err + } + jsonOutput(result) + return nil +} diff --git a/cmd/gctcli/main.go b/cmd/gctcli/main.go index 2ba53d45..11e43506 100644 --- a/cmd/gctcli/main.go +++ b/cmd/gctcli/main.go @@ -122,6 +122,8 @@ func main() { getCryptocurrencyDepositAddressCommand, withdrawCryptocurrencyFundsCommand, withdrawFiatFundsCommand, + getLoggerDetailsCommand, + setLoggerDetailsCommand, } err := app.Run(os.Args) diff --git a/cmd/portfolio/portfolio.go b/cmd/portfolio/portfolio.go index 23e8e3b7..2477c441 100644 --- a/cmd/portfolio/portfolio.go +++ b/cmd/portfolio/portfolio.go @@ -3,11 +3,12 @@ package main import ( "flag" "fmt" + "log" + "os" "github.com/thrasher-/gocryptotrader/config" "github.com/thrasher-/gocryptotrader/currency" "github.com/thrasher-/gocryptotrader/exchanges/bitfinex" - log "github.com/thrasher-/gocryptotrader/logger" "github.com/thrasher-/gocryptotrader/portfolio" ) @@ -25,7 +26,7 @@ func printSummary(msg string, amount float64) { currency.USD, displayCurrency) if err != nil { - log.Error(err) + log.Println(err) } else { symb, err := currency.GetSymbolByCurrencyName(displayCurrency) if err != nil { @@ -64,7 +65,8 @@ func main() { defaultCfg, err := config.GetFilePath("") if err != nil { - log.Fatal(err) + log.Println(err) + os.Exit(1) } flag.StringVar(&inFile, "infile", defaultCfg, "The config input file to process.") @@ -76,7 +78,8 @@ func main() { var cfg config.Config err = cfg.LoadConfig(inFile) if err != nil { - log.Fatal(err) + log.Println(err) + os.Exit(1) } log.Println("Loaded config file.") @@ -105,7 +108,8 @@ func main() { } err = currency.SeedForeignExchangeData(fiatCurrencies) if err != nil { - log.Fatal(err) + log.Println(err) + os.Exit(1) } log.Println("Fetched currency data.") diff --git a/cmd/websocket_client/main.go b/cmd/websocket_client/main.go index d3522c9b..ac3ff3bf 100644 --- a/cmd/websocket_client/main.go +++ b/cmd/websocket_client/main.go @@ -42,8 +42,8 @@ type WebsocketEventResponse struct { // WebsocketOrderbookTickerRequest is a struct used for ticker and orderbook // requests type WebsocketOrderbookTickerRequest struct { - Exchange string `json:"exchangeName"` - Currency string `json:"currency"` + Exchange string `json:"exchangeName"` + Currency string `json:"currency"` AssetType asset.Item `json:"assetType"` } diff --git a/common/common.go b/common/common.go index 67e2e05c..a11cd71d 100644 --- a/common/common.go +++ b/common/common.go @@ -201,7 +201,7 @@ func SendHTTPRequest(method, urlPath string, headers map[string]string, body io. // on failure. func SendHTTPGetRequest(urlPath string, jsonDecode, isVerbose bool, result interface{}) error { if isVerbose { - log.Debugf("Raw URL: %s", urlPath) + log.Debugf(log.Global, "Raw URL: %s\n", urlPath) } initialiseHTTPClient() @@ -221,7 +221,7 @@ func SendHTTPGetRequest(urlPath string, jsonDecode, isVerbose bool, result inter } if isVerbose { - log.Debugf("Raw Resp: %s", string(contents)) + log.Debugf(log.Global, "Raw Resp: %s\n", string(contents)) } defer res.Body.Close() @@ -336,7 +336,7 @@ func GetDefaultDataDir(env string) string { dir, err := os.UserHomeDir() if err != nil { - log.Warn("Environment variable unset, defaulting to current directory") + log.Warnln(log.Global, "Environment variable unset, defaulting to current directory") dir = "." } return filepath.Join(dir, ".gocryptotrader") @@ -349,7 +349,7 @@ func CreateDir(dir string) error { return nil } - log.Warnf("Directory %s does not exist.. creating.", dir) + log.Warnf(log.Global, "Directory %s does not exist.. creating.\n", dir) return os.MkdirAll(dir, 0770) } diff --git a/communications/base/base_interface.go b/communications/base/base_interface.go index cb5635c2..465f630b 100644 --- a/communications/base/base_interface.go +++ b/communications/base/base_interface.go @@ -29,10 +29,10 @@ func (c IComm) Setup() { if c[i].IsEnabled() && !c[i].IsConnected() { err := c[i].Connect() if err != nil { - log.Errorf("Communications: %s failed to connect. Err: %s", c[i].GetName(), err) + log.Errorf(log.CommunicationMgr, "Communications: %s failed to connect. Err: %s", c[i].GetName(), err) continue } - log.Debugf("Communications: %v is enabled and online.", c[i].GetName()) + log.Debugf(log.CommunicationMgr, "Communications: %v is enabled and online.", c[i].GetName()) } } } @@ -43,7 +43,7 @@ func (c IComm) PushEvent(event Event) { if c[i].IsEnabled() && c[i].IsConnected() { err := c[i].PushEvent(event) if err != nil { - log.Errorf("Communications error - PushEvent() in package %s with %v. Err %s", + log.Errorf(log.CommunicationMgr, "Communications error - PushEvent() in package %s with %v. Err %s", c[i].GetName(), event, err) } } @@ -69,7 +69,7 @@ func (c IComm) GetEnabledCommunicationMediums() error { var count int for i := range c { if c[i].IsEnabled() && c[i].IsConnected() { - log.Debugf("Communications: Medium %s is enabled.", c[i].GetName()) + log.Debugf(log.CommunicationMgr, "Communications: Medium %s is enabled.", c[i].GetName()) count++ } } diff --git a/communications/slack/slack.go b/communications/slack/slack.go index dad5a45e..e1f83802 100644 --- a/communications/slack/slack.go +++ b/communications/slack/slack.go @@ -162,13 +162,13 @@ func (s *Slack) NewConnection() error { } if s.Verbose { - log.Debugf("Slack: %s [%s] connected to %s [%s] \nWebsocket URL: %s.\n", + log.Debugf(log.CommunicationMgr, "Slack: %s [%s] connected to %s [%s] \nWebsocket URL: %s.\n", s.Details.Self.Name, s.Details.Self.ID, s.Details.Team.Domain, s.Details.Team.ID, s.Details.URL) - log.Debugf("Slack: Public channels: %s", s.GetChannelsString()) + log.Debugf(log.CommunicationMgr, "Slack: Public channels: %s\n", s.GetChannelsString()) } s.TargetChannelID, err = s.GetIDByName(s.TargetChannel) @@ -176,7 +176,7 @@ func (s *Slack) NewConnection() error { return err } - log.Debugf("Slack: Target channel ID: %v [#%v]", s.TargetChannelID, + log.Debugf(log.CommunicationMgr, "Slack: Target channel ID: %v [#%v]\n", s.TargetChannelID, s.TargetChannel) return s.WebsocketConnect() } @@ -208,13 +208,13 @@ func (s *Slack) WebsocketReader() { for { _, resp, err := s.WebsocketConn.ReadMessage() if err != nil { - log.Error(err) + log.Errorln(log.CommunicationMgr, err) } var data WebsocketResponse err = common.JSONDecode(resp, &data) if err != nil { - log.Error(err) + log.Errorln(log.CommunicationMgr, err) continue } @@ -249,10 +249,10 @@ func (s *Slack) WebsocketReader() { case "pong": if s.Verbose { - log.Debugf("Slack: Pong received from server") + log.Debugln(log.CommunicationMgr, "Slack: Pong received from server") } default: - log.Debugf(string(resp)) + log.Debugln(log.CommunicationMgr, string(resp)) } } } @@ -264,7 +264,7 @@ func (s *Slack) handlePresenceChange(resp []byte) error { return err } if s.Verbose { - log.Debugf("Slack: Presence change. User %s [%s] changed status to %s\n", + log.Debugf(log.CommunicationMgr, "Slack: Presence change. User %s [%s] changed status to %s\n", s.GetUsernameByID(pres.User), pres.User, pres.Presence) } @@ -281,7 +281,7 @@ func (s *Slack) handleMessageResponse(resp []byte, data WebsocketResponse) error return err } if s.Verbose { - log.Debugf("Slack: Message received by %s [%s] with text: %s\n", + log.Debugf(log.CommunicationMgr, "Slack: Message received by %s [%s] with text: %s\n", s.GetUsernameByID(msg.User), msg.User, msg.Text) } @@ -293,7 +293,7 @@ func (s *Slack) handleMessageResponse(resp []byte, data WebsocketResponse) error func (s *Slack) handleErrorResponse(data WebsocketResponse) error { if data.Error.Msg == "Socket URL has expired" { if s.Verbose { - log.Debugf("Slack websocket URL has expired.. Reconnecting") + log.Debugln(log.CommunicationMgr, "Slack websocket URL has expired.. Reconnecting") } if s.WebsocketConn == nil { @@ -301,7 +301,7 @@ func (s *Slack) handleErrorResponse(data WebsocketResponse) error { } if err := s.WebsocketConn.Close(); err != nil { - log.Error(err) + log.Errorln(log.CommunicationMgr, err) } s.ReconnectURL = "" @@ -313,7 +313,7 @@ func (s *Slack) handleErrorResponse(data WebsocketResponse) error { func (s *Slack) handleHelloResponse() { if s.Verbose { - log.Debugln("Slack: Websocket connected successfully.") + log.Debugln(log.CommunicationMgr, "Slack: Websocket connected successfully.") } s.Connected = true go s.WebsocketKeepAlive() @@ -330,7 +330,7 @@ func (s *Slack) handleReconnectResponse(resp []byte) error { } s.ReconnectURL = recURL.URL if s.Verbose { - log.Debugf("Slack: Reconnect URL set to %s\n", s.ReconnectURL) + log.Debugf(log.CommunicationMgr, "Slack: Reconnect URL set to %s\n", s.ReconnectURL) } return nil } @@ -343,7 +343,7 @@ func (s *Slack) WebsocketKeepAlive() { for { <-ticker.C if err := s.WebsocketSend("ping", ""); err != nil { - log.Debugf("Slack: WebsocketKeepAlive() error %s", err) + log.Errorf(log.CommunicationMgr, "Slack: WebsocketKeepAlive() error %s\n", err) } } } @@ -364,7 +364,7 @@ func (s *Slack) WebsocketSend(eventType, text string) error { } if s.Verbose { - log.Debugf("Slack: Sending websocket message: %s", string(data)) + log.Debugf(log.CommunicationMgr, "Slack: Sending websocket message: %s\n", string(data)) } if s.WebsocketConn == nil { diff --git a/communications/smsglobal/smsglobal.go b/communications/smsglobal/smsglobal.go index 7f21bf61..3b75ea87 100644 --- a/communications/smsglobal/smsglobal.go +++ b/communications/smsglobal/smsglobal.go @@ -51,7 +51,7 @@ func (s *SMSGlobal) Setup(cfg *config.CommunicationsConfig) { Enabled: cfg.SMSGlobalConfig.Contacts[x].Enabled, }, ) - log.Debugf("SMSGlobal: SMS Contact: %s. Number: %s. Enabled: %v", + log.Debugf(log.CommunicationMgr, "SMSGlobal: SMS Contact: %s. Number: %s. Enabled: %v\n", cfg.SMSGlobalConfig.Contacts[x].Name, cfg.SMSGlobalConfig.Contacts[x].Number, cfg.SMSGlobalConfig.Contacts[x].Enabled) @@ -151,7 +151,7 @@ func (s *SMSGlobal) SendMessageToAll(message string) error { for x := range s.Contacts { if s.Contacts[x].Enabled { if s.Verbose { - log.Debugf("SMSGlobal: Sending SMS to %s. Number: %s. Message: %s [From: %s]", + log.Debugf(log.CommunicationMgr, "SMSGlobal: Sending SMS to %s. Number: %s. Message: %s [From: %s]\n", s.Contacts[x].Name, s.Contacts[x].Number, message, s.SendFrom) } err := s.SendMessage(s.Contacts[x].Number, message) diff --git a/communications/smtpservice/smtpservice.go b/communications/smtpservice/smtpservice.go index 90fe0fd4..b67b145e 100644 --- a/communications/smtpservice/smtpservice.go +++ b/communications/smtpservice/smtpservice.go @@ -39,7 +39,7 @@ func (s *SMTPservice) Setup(cfg *config.CommunicationsConfig) { s.AccountPassword = cfg.SMTPConfig.AccountPassword s.From = cfg.SMTPConfig.From s.RecipientList = cfg.SMTPConfig.RecipientList - log.Debugf("SMTP: Setup - From: %v. To: %s. Server: %s.", s.From, s.RecipientList, s.Host) + log.Debugf(log.CommunicationMgr, "SMTP: Setup - From: %v. To: %s. Server: %s.\n", s.From, s.RecipientList, s.Host) } // IsConnected returns whether or not the connection is connected @@ -65,7 +65,7 @@ func (s *SMTPservice) Send(subject, msg string) error { return errors.New("STMPservice Send() please add subject and alert") } - log.Debugf("SMTP: Sending email to %v. Subject: %s Message: %s [From: %s]", s.RecipientList, + log.Debugf(log.CommunicationMgr, "SMTP: Sending email to %v. Subject: %s Message: %s [From: %s]\n", s.RecipientList, subject, msg, s.From) messageToSend := fmt.Sprintf( msgSMTP, diff --git a/communications/telegram/telegram.go b/communications/telegram/telegram.go index 11a200f0..b12eb33e 100644 --- a/communications/telegram/telegram.go +++ b/communications/telegram/telegram.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net/http" + "os" "strings" "github.com/thrasher-/gocryptotrader/common" @@ -86,7 +87,7 @@ func (t *Telegram) PollerStart() { for { resp, err := t.GetUpdates() if err != nil { - log.Error(err) + log.Errorln(log.CommunicationMgr, err) } for i := range resp.Result { @@ -94,7 +95,7 @@ func (t *Telegram) PollerStart() { if string(resp.Result[i].Message.Text[0]) == "/" { err = t.HandleMessages(resp.Result[i].Message.Text, resp.Result[i].Message.From.ID) if err != nil { - log.Error(err) + log.Errorln(log.CommunicationMgr, err) } } t.Offset = resp.Result[i].UpdateID @@ -108,11 +109,13 @@ func (t *Telegram) PollerStart() { func (t *Telegram) InitialConnect() { resp, err := t.GetUpdates() if err != nil { - log.Fatal(err) + log.Errorln(log.CommunicationMgr, err) + os.Exit(1) } if !resp.Ok { - log.Fatal(resp.Description) + log.Errorln(log.CommunicationMgr, resp.Description) + os.Exit(1) } warmWelcomeList := make(map[string]int64) @@ -125,7 +128,8 @@ func (t *Telegram) InitialConnect() { for userName, ID := range warmWelcomeList { err = t.SendMessage(fmt.Sprintf("GoCryptoTrader bot has connected: Hello, %s!", userName), ID) if err != nil { - log.Fatal(err) + log.Errorln(log.CommunicationMgr, err) + os.Exit(1) } } if len(resp.Result) == 0 { diff --git a/config/config.go b/config/config.go index 6bfbb9b1..1b70e5b6 100644 --- a/config/config.go +++ b/config/config.go @@ -184,20 +184,20 @@ func (c *Config) CheckClientBankAccounts() { if c.BankAccounts[i].Enabled { if c.BankAccounts[i].BankName == "" || c.BankAccounts[i].BankAddress == "" { c.BankAccounts[i].Enabled = false - log.Warnf("banking details for %s is enabled but variables not set correctly", + log.Warnf(log.ConfigMgr, "banking details for %s is enabled but variables not set correctly\n", c.BankAccounts[i].BankName) continue } if c.BankAccounts[i].AccountName == "" || c.BankAccounts[i].AccountNumber == "" { c.BankAccounts[i].Enabled = false - log.Warnf("banking account details for %s variables not set correctly", + log.Warnf(log.ConfigMgr, "banking account details for %s variables not set correctly\n", c.BankAccounts[i].BankName) continue } if c.BankAccounts[i].IBAN == "" && c.BankAccounts[i].SWIFTCode == "" && c.BankAccounts[i].BSBNumber == "" { c.BankAccounts[i].Enabled = false - log.Warnf("critical banking numbers not set for %s in %s account", + log.Warnf(log.ConfigMgr, "critical banking numbers not set for %s in %s account\n", c.BankAccounts[i].BankName, c.BankAccounts[i].AccountName) continue @@ -335,7 +335,7 @@ func (c *Config) CheckCommunicationsConfig() { } if len(c.Communications.SMSGlobalConfig.From) > 11 { - log.Warnf("SMSGlobal config supplied from name exceeds 11 characters, trimming.") + log.Warnf(log.ConfigMgr, "SMSGlobal config supplied from name exceeds 11 characters, trimming.\n") c.Communications.SMSGlobalConfig.From = c.Communications.SMSGlobalConfig.From[:11] } @@ -367,14 +367,14 @@ func (c *Config) CheckCommunicationsConfig() { c.Communications.SMSGlobalConfig.Name != "SMSGlobal" || c.Communications.SMTPConfig.Name != "SMTP" || c.Communications.TelegramConfig.Name != "Telegram" { - log.Warn("Communications config name/s not set correctly") + log.Warnln(log.ConfigMgr, "Communications config name/s not set correctly") } if c.Communications.SlackConfig.Enabled { if c.Communications.SlackConfig.TargetChannel == "" || c.Communications.SlackConfig.VerificationToken == "" || c.Communications.SlackConfig.VerificationToken == "testtest" { c.Communications.SlackConfig.Enabled = false - log.Warn("Slack enabled in config but variable data not set, disabling.") + log.Warnln(log.ConfigMgr, "Slack enabled in config but variable data not set, disabling.") } } if c.Communications.SMSGlobalConfig.Enabled { @@ -382,7 +382,7 @@ func (c *Config) CheckCommunicationsConfig() { c.Communications.SMSGlobalConfig.Password == "" || len(c.Communications.SMSGlobalConfig.Contacts) == 0 { c.Communications.SMSGlobalConfig.Enabled = false - log.Warn("SMSGlobal enabled in config but variable data not set, disabling.") + log.Warnln(log.ConfigMgr, "SMSGlobal enabled in config but variable data not set, disabling.") } } if c.Communications.SMTPConfig.Enabled { @@ -391,13 +391,13 @@ func (c *Config) CheckCommunicationsConfig() { c.Communications.SMTPConfig.AccountName == "" || c.Communications.SMTPConfig.AccountPassword == "" { c.Communications.SMTPConfig.Enabled = false - log.Warn("SMTP enabled in config but variable data not set, disabling.") + log.Warnln(log.ConfigMgr, "SMTP enabled in config but variable data not set, disabling.") } } if c.Communications.TelegramConfig.Enabled { if c.Communications.TelegramConfig.VerificationToken == "" { c.Communications.TelegramConfig.Enabled = false - log.Warn("Telegram enabled in config but variable data not set, disabling.") + log.Warnln(log.ConfigMgr, "Telegram enabled in config but variable data not set, disabling.") } } } @@ -454,7 +454,7 @@ func (c *Config) CheckExchangeAssetsConsistency(exchName string) { storedAssetTypes := exchCfg.CurrencyPairs.GetAssetTypes() for x := range storedAssetTypes { if !exchangeAssetTypes.Contains(storedAssetTypes[x]) { - log.Warnf("%s has non-needed stored asset type %v. Removing..", exchName, storedAssetTypes[x]) + log.Warnf(log.ConfigMgr, "%s has non-needed stored asset type %v. Removing..\n", exchName, storedAssetTypes[x]) exchCfg.CurrencyPairs.Delete(storedAssetTypes[x]) } } @@ -620,7 +620,7 @@ func (c *Config) CheckPairConsistency(exchName string) error { if err != nil { return fmt.Errorf("exchange %s failed to set pairs: %v", exchName, err) } - log.Warnf("Exchange %s: [%v] No enabled pairs found in available pairs, randomly added %v pair.\n", + log.Warnf(log.ExchangeSys, "Exchange %s: [%v] No enabled pairs found in available pairs, randomly added %v pair.\n", exchName, assetTypes[x], newPair) continue } else { @@ -629,7 +629,7 @@ func (c *Config) CheckPairConsistency(exchName string) error { return fmt.Errorf("exchange %s failed to set pairs: %v", exchName, err) } } - log.Warnf("Exchange %s: [%v] Removing enabled pair(s) %v from enabled pairs as it isn't an available pair.", + log.Warnf(log.ExchangeSys, "Exchange %s: [%v] Removing enabled pair(s) %v from enabled pairs as it isn't an available pair.\n", exchName, assetTypes[x], pairsRemoved.Strings()) } return nil @@ -952,7 +952,7 @@ func (c *Config) CheckExchangeConfigValues() error { if c.Exchanges[i].Enabled { if c.Exchanges[i].Name == "" { - log.Error(ErrExchangeNameEmpty, i) + log.Error(log.ConfigMgr, ErrExchangeNameEmpty, i) c.Exchanges[i].Enabled = false continue } @@ -973,46 +973,46 @@ func (c *Config) CheckExchangeConfigValues() error { if failed { c.Exchanges[i].API.AuthenticatedSupport = false c.Exchanges[i].API.AuthenticatedWebsocketSupport = false - log.Warnf(WarningExchangeAuthAPIDefaultOrEmptyValues, c.Exchanges[i].Name) + log.Warnf(log.ExchangeSys, WarningExchangeAuthAPIDefaultOrEmptyValues, c.Exchanges[i].Name) } } if !c.Exchanges[i].Features.Supports.RESTCapabilities.AutoPairUpdates && !c.Exchanges[i].Features.Supports.WebsocketCapabilities.AutoPairUpdates { lastUpdated := convert.UnixTimestampToTime(c.Exchanges[i].CurrencyPairs.LastUpdated) lastUpdated = lastUpdated.AddDate(0, 0, configPairsLastUpdatedWarningThreshold) if lastUpdated.Unix() <= time.Now().Unix() { - log.Warnf(WarningPairsLastUpdatedThresholdExceeded, c.Exchanges[i].Name, configPairsLastUpdatedWarningThreshold) + log.Warnf(log.ExchangeSys, WarningPairsLastUpdatedThresholdExceeded, c.Exchanges[i].Name, configPairsLastUpdatedWarningThreshold) } } if c.Exchanges[i].HTTPTimeout <= 0 { - log.Warnf("Exchange %s HTTP Timeout value not set, defaulting to %v.", c.Exchanges[i].Name, configDefaultHTTPTimeout) + log.Warnf(log.ExchangeSys, "Exchange %s HTTP Timeout value not set, defaulting to %v.\n", c.Exchanges[i].Name, configDefaultHTTPTimeout) c.Exchanges[i].HTTPTimeout = configDefaultHTTPTimeout } if c.Exchanges[i].HTTPRateLimiter != nil { if c.Exchanges[i].HTTPRateLimiter.Authenticated.Duration < 0 { - log.Warnf("Exchange %s HTTP Rate Limiter authenticated duration set to negative value, defaulting to 0", c.Exchanges[i].Name) + log.Warnf(log.ExchangeSys, "Exchange %s HTTP Rate Limiter authenticated duration set to negative value, defaulting to 0\n", c.Exchanges[i].Name) c.Exchanges[i].HTTPRateLimiter.Authenticated.Duration = 0 } if c.Exchanges[i].HTTPRateLimiter.Authenticated.Rate < 0 { - log.Warnf("Exchange %s HTTP Rate Limiter authenticated rate set to negative value, defaulting to 0", c.Exchanges[i].Name) + log.Warnf(log.ExchangeSys, "Exchange %s HTTP Rate Limiter authenticated rate set to negative value, defaulting to 0\n", c.Exchanges[i].Name) c.Exchanges[i].HTTPRateLimiter.Authenticated.Rate = 0 } if c.Exchanges[i].HTTPRateLimiter.Unauthenticated.Duration < 0 { - log.Warnf("Exchange %s HTTP Rate Limiter unauthenticated duration set to negative value, defaulting to 0", c.Exchanges[i].Name) + log.Warnf(log.ExchangeSys, "Exchange %s HTTP Rate Limiter unauthenticated duration set to negative value, defaulting to 0\n", c.Exchanges[i].Name) c.Exchanges[i].HTTPRateLimiter.Unauthenticated.Duration = 0 } if c.Exchanges[i].HTTPRateLimiter.Unauthenticated.Rate < 0 { - log.Warnf("Exchange %s HTTP Rate Limiter unauthenticated rate set to negative value, defaulting to 0", c.Exchanges[i].Name) + log.Warnf(log.ExchangeSys, "Exchange %s HTTP Rate Limiter unauthenticated rate set to negative value, defaulting to 0\n", c.Exchanges[i].Name) c.Exchanges[i].HTTPRateLimiter.Unauthenticated.Rate = 0 } } err := c.CheckPairConsistency(c.Exchanges[i].Name) if err != nil { - log.Errorf("Exchange %s: CheckPairConsistency error: %s", c.Exchanges[i].Name, err) + log.Errorf(log.ExchangeSys, "Exchange %s: CheckPairConsistency error: %s\n", c.Exchanges[i].Name, err) c.Exchanges[i].Enabled = false continue } @@ -1026,26 +1026,26 @@ func (c *Config) CheckExchangeConfigValues() error { } bankError := false if c.Exchanges[i].BankAccounts[x].BankName == "" || c.Exchanges[i].BankAccounts[x].BankAddress == "" { - log.Warnf("banking details for %s is enabled but variables not set", + log.Warnf(log.ExchangeSys, "banking details for %s is enabled but variables not set\n", c.Exchanges[i].Name) bankError = true } if c.Exchanges[i].BankAccounts[x].AccountName == "" || c.Exchanges[i].BankAccounts[x].AccountNumber == "" { - log.Warnf("banking account details for %s variables not set", + log.Warnf(log.ExchangeSys, "banking account details for %s variables not set\n", c.Exchanges[i].Name) bankError = true } if c.Exchanges[i].BankAccounts[x].SupportedCurrencies == "" { - log.Warnf("banking account details for %s acceptable funding currencies not set", + log.Warnf(log.ExchangeSys, "banking account details for %s acceptable funding currencies not set\n", c.Exchanges[i].Name) bankError = true } if c.Exchanges[i].BankAccounts[x].BSBNumber == "" && c.Exchanges[i].BankAccounts[x].IBAN == "" && c.Exchanges[i].BankAccounts[x].SWIFTCode == "" { - log.Warnf("banking account details for %s critical banking numbers not set", + log.Warnf(log.ExchangeSys, "banking account details for %s critical banking numbers not set\n", c.Exchanges[i].Name) bankError = true } @@ -1075,7 +1075,7 @@ func (c *Config) CheckCurrencyConfigValues() error { for x := range fxProviders { _, err := c.GetForexProviderConfig(fxProviders[x]) if err != nil { - log.Warnf("%s forex provider not found, adding to config..", fxProviders[x]) + log.Warnf(log.Global, "%s forex provider not found, adding to config..\n", fxProviders[x]) c.Currency.ForexProviders = append(c.Currency.ForexProviders, base.Settings{ Name: fxProviders[x], RESTPollingDelay: 600, @@ -1090,7 +1090,7 @@ func (c *Config) CheckCurrencyConfigValues() error { for i := range c.Currency.ForexProviders { if c.Currency.ForexProviders[i].Enabled { if c.Currency.ForexProviders[i].APIKey == DefaultUnsetAPIKey && c.Currency.ForexProviders[i].Name != DefaultForexProviderExchangeRatesAPI { - log.Warnf("%s enabled forex provider API key not set. Please set this in your config.json file", c.Currency.ForexProviders[i].Name) + log.Warnf(log.Global, "%s enabled forex provider API key not set. Please set this in your config.json file\n", c.Currency.ForexProviders[i].Name) c.Currency.ForexProviders[i].Enabled = false c.Currency.ForexProviders[i].PrimaryProvider = false continue @@ -1101,7 +1101,7 @@ func (c *Config) CheckCurrencyConfigValues() error { c.Currency.ForexProviders[i].PrimaryProvider && (c.Currency.ForexProviders[i].APIKey == "" || c.Currency.ForexProviders[i].APIKey == DefaultUnsetAPIKey) { - log.Warnf("CurrencyConverter forex provider no longer supports unset API key requests. Switching to ExchangeRates FX provider..") + log.Warnln(log.Global, "CurrencyConverter forex provider no longer supports unset API key requests. Switching to ExchangeRates FX provider..") c.Currency.ForexProviders[i].Enabled = false c.Currency.ForexProviders[i].PrimaryProvider = false c.Currency.ForexProviders[i].APIKey = DefaultUnsetAPIKey @@ -1111,7 +1111,7 @@ func (c *Config) CheckCurrencyConfigValues() error { } if c.Currency.ForexProviders[i].APIKeyLvl == -1 && c.Currency.ForexProviders[i].Name != DefaultForexProviderExchangeRatesAPI { - log.Warnf("%s APIKey Level not set, functions limited. Please set this in your config.json file", + log.Warnf(log.Global, "%s APIKey Level not set, functions limited. Please set this in your config.json file\n", c.Currency.ForexProviders[i].Name) } count++ @@ -1123,7 +1123,7 @@ func (c *Config) CheckCurrencyConfigValues() error { if c.Currency.ForexProviders[x].Name == DefaultForexProviderExchangeRatesAPI { c.Currency.ForexProviders[x].Enabled = true c.Currency.ForexProviders[x].PrimaryProvider = true - log.Warn("Using ExchangeRatesAPI for default forex provider.") + log.Warnln(log.ConfigMgr, "Using ExchangeRatesAPI for default forex provider.") } } } @@ -1139,11 +1139,11 @@ func (c *Config) CheckCurrencyConfigValues() error { if c.Currency.CryptocurrencyProvider.Enabled { if c.Currency.CryptocurrencyProvider.APIkey == "" || c.Currency.CryptocurrencyProvider.APIkey == DefaultUnsetAPIKey { - log.Warnf("CryptocurrencyProvider enabled but api key is unset please set this in your config.json file") + log.Warnln(log.ConfigMgr, "CryptocurrencyProvider enabled but api key is unset please set this in your config.json file") } if c.Currency.CryptocurrencyProvider.AccountPlan == "" || c.Currency.CryptocurrencyProvider.AccountPlan == DefaultUnsetAccountPlan { - log.Warnf("CryptocurrencyProvider enabled but account plan is unset please set this in your config.json file") + log.Warnln(log.ConfigMgr, "CryptocurrencyProvider enabled but account plan is unset please set this in your config.json file") } } else { if c.Currency.CryptocurrencyProvider.APIkey == "" { @@ -1248,34 +1248,34 @@ func (c *Config) CheckLoggerConfig() error { m.Lock() defer m.Unlock() - // check if enabled is nil or level is a blank string - if c.Logging.Enabled == nil || c.Logging.Level == "" { - // Creates a new pointer to bool and sets it as true - t := func(t bool) *bool { return &t }(true) - - log.Warn("Missing or invalid config settings using safe defaults") - - // Set logger to safe defaults - c.Logging = log.Logging{ - Enabled: t, - Level: "DEBUG|INFO|WARN|ERROR|FATAL", - ColourOutput: false, - File: "debug.txt", - Rotate: false, - } - log.Logger = &c.Logging - } else { - log.Logger = &c.Logging + if c.Logging.Enabled == nil || c.Logging.Output == "" { + c.Logging = log.GenDefaultSettings() } - if len(c.Logging.File) > 0 { - logPath := filepath.Join(common.GetDefaultDataDir(runtime.GOOS), "logs") - err := common.CreateDir(logPath) - if err != nil { - return err + f := func(f bool) *bool { return &f }(false) + + if c.Logging.LoggerFileConfig != nil { + if c.Logging.LoggerFileConfig.FileName == "" { + c.Logging.LoggerFileConfig.FileName = "log.txt" } - log.LogPath = logPath + if c.Logging.LoggerFileConfig.Rotate == nil { + c.Logging.LoggerFileConfig.Rotate = f + } + if c.Logging.LoggerFileConfig.MaxSize < 0 { + c.Logging.LoggerFileConfig.MaxSize = 100 + } + log.FileLoggingConfiguredCorrectly = true } + + log.GlobalLogConfig = &c.Logging + + logPath := filepath.Join(common.GetDefaultDataDir(runtime.GOOS), "logs") + err := common.CreateDir(logPath) + if err != nil { + return err + } + log.LogPath = logPath + return nil } @@ -1295,7 +1295,7 @@ func (c *Config) CheckNTPConfig() { } if len(c.NTPClient.Pool) < 1 { - log.Warn("NTPClient enabled with no servers configured, enabling default pool.") + log.Warnln(log.ConfigMgr, "NTPClient enabled with no servers configured, enabling default pool.") c.NTPClient.Pool = []string{"pool.ntp.org:123"} } } @@ -1306,8 +1306,8 @@ func (c *Config) DisableNTPCheck(input io.Reader) (string, error) { defer m.Unlock() reader := bufio.NewReader(input) - log.Warn("Your system time is out of sync, this may cause issues with trading.") - log.Warn("How would you like to show future notifications? (a)lert / (w)arn / (d)isable. \n") + log.Warnln(log.ConfigMgr, "Your system time is out of sync, this may cause issues with trading.") + log.Warnln(log.ConfigMgr, "How would you like to show future notifications? (a)lert / (w)arn / (d)isable.") var answered = false for ok := true; ok; ok = (!answered) { @@ -1395,13 +1395,13 @@ func GetFilePath(file string) (string, error) { if err != nil { return "", err } - log.Debugf("Renamed old config file %s to %s", oldDirs[x], newDirs[0]) + log.Debugf(log.ConfigMgr, "Renamed old config file %s to %s\n", oldDirs[x], newDirs[0]) } else { err = os.Rename(oldDirs[x], newDirs[1]) if err != nil { return "", err } - log.Debugf("Renamed old config file %s to %s", oldDirs[x], newDirs[1]) + log.Debugf(log.ConfigMgr, "Renamed old config file %s to %s\n", oldDirs[x], newDirs[1]) } } @@ -1484,7 +1484,7 @@ func (c *Config) ReadConfig(configPath string) error { } key, err := PromptForConfigKey(IsInitialSetup) if err != nil { - log.Errorf("PromptForConfigKey err: %s", err) + log.Errorf(log.ConfigMgr, "PromptForConfigKey err: %s", err) errCounter++ continue } @@ -1493,7 +1493,7 @@ func (c *Config) ReadConfig(configPath string) error { f = append(f, file...) data, err := DecryptConfigFile(f, key) if err != nil { - log.Errorf("DecryptConfigFile err: %s", err) + log.Errorf(log.ConfigMgr, "DecryptConfigFile err: %s", err) errCounter++ continue } @@ -1501,7 +1501,7 @@ func (c *Config) ReadConfig(configPath string) error { err = ConfirmConfigJSON(data, &c) if err != nil { if errCounter < configMaxAuthFailures { - log.Errorf("Invalid password.") + log.Error(log.ConfigMgr, "Invalid password.") } errCounter++ continue @@ -1591,7 +1591,7 @@ func (c *Config) CheckRemoteControlConfig() { func (c *Config) CheckConfig() error { err := c.CheckLoggerConfig() if err != nil { - log.Errorf("Failed to configure logger. Err: %s", err) + log.Errorf(log.ConfigMgr, "Failed to configure logger, some logging features unavailable: %s\n", err) } err = c.CheckExchangeConfigValues() @@ -1610,7 +1610,7 @@ func (c *Config) CheckConfig() error { } if c.GlobalHTTPTimeout <= 0 { - log.Warnf("Global HTTP Timeout value not set, defaulting to %v.", configDefaultHTTPTimeout) + log.Warnf(log.ConfigMgr, "Global HTTP Timeout value not set, defaulting to %v.\n", configDefaultHTTPTimeout) c.GlobalHTTPTimeout = configDefaultHTTPTimeout } diff --git a/config/config_encryption.go b/config/config_encryption.go index b0ac465f..416a8ee1 100644 --- a/config/config_encryption.go +++ b/config/config_encryption.go @@ -11,7 +11,6 @@ import ( "github.com/thrasher-/gocryptotrader/common" gctcrypto "github.com/thrasher-/gocryptotrader/common/crypto" - log "github.com/thrasher-/gocryptotrader/logger" "golang.org/x/crypto/scrypt" ) @@ -34,7 +33,7 @@ var ( // PromptForConfigEncryption asks for encryption key func (c *Config) PromptForConfigEncryption() bool { - log.Infof("Would you like to encrypt your config file (y/n)?") + fmt.Println("Would you like to encrypt your config file (y/n)?") input := "" _, err := fmt.Scanln(&input) @@ -55,7 +54,7 @@ func PromptForConfigKey(initialSetup bool) ([]byte, error) { var cryptoKey []byte for { - log.Println("Please enter in your password: ") + fmt.Println("Please enter in your password: ") pwPrompt := func(i *[]byte) error { _, err := fmt.Scanln(i) return err @@ -73,7 +72,7 @@ func PromptForConfigKey(initialSetup bool) ([]byte, error) { } var p2 []byte - log.Println("Please re-enter your password: ") + fmt.Println("Please re-enter your password: ") err = pwPrompt(&p2) if err != nil { return nil, err @@ -83,7 +82,7 @@ func PromptForConfigKey(initialSetup bool) ([]byte, error) { cryptoKey = p1 break } - log.Printf("Passwords did not match, please try again.") + fmt.Printf("Passwords did not match, please try again.") } return cryptoKey, nil } diff --git a/config/config_test.go b/config/config_test.go index c4917dd7..88600fb6 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -855,7 +855,7 @@ func TestCheckLoggerConfig(t *testing.T) { if err != nil { t.Fatal(err) } - c.Logging = log.Logging{} + c.Logging = log.Config{} err = c.CheckLoggerConfig() if err != nil { t.Errorf("Failed to create default logger reason: %v", err) diff --git a/config/config_types.go b/config/config_types.go index b4e82549..9df0c36c 100644 --- a/config/config_types.go +++ b/config/config_types.go @@ -16,7 +16,7 @@ type Config struct { Name string `json:"name"` EncryptConfig int `json:"encryptConfig"` GlobalHTTPTimeout time.Duration `json:"globalHTTPTimeout"` - Logging log.Logging `json:"logging"` + Logging log.Config `json:"logging"` ConnectionMonitor ConnectionMonitorConfig `json:"connectionMonitor"` Profiler ProfilerConfig `json:"profiler"` NTPClient NTPClientConfig `json:"ntpclient"` diff --git a/config_example.json b/config_example.json index 621dd928..f04556a5 100644 --- a/config_example.json +++ b/config_example.json @@ -4,10 +4,24 @@ "globalHTTPTimeout": 15000000000, "logging": { "enabled": true, - "file": "debug.txt", - "colour": false, - "level": "DEBUG|WARN|INFO|ERROR|FATAL", - "rotate": false + "level": "INFO|WARN|DEBUG|ERROR", + "output": "console", + "fileSettings": { + "filename": "log.txt", + "rotate": true, + "maxsize": 250 + }, + "advancedSettings": { + "spacer": " | ", + "timeStampFormat": "02/01/2006 15:04:05", + "headers": { + "info": "[INFO] ", + "warn": "[WARN] ", + "debug": "[DEBUG]", + "error": "[ERROR]" + } + }, + "subloggers": [] }, "profiler": { "enabled": false @@ -1322,4 +1336,4 @@ "checkInterval": 1000000000 }, "fiatDispayCurrency": "" -} \ No newline at end of file +} diff --git a/connchecker/connchecker.go b/connchecker/connchecker.go index 6c9c4f99..cb523e8a 100644 --- a/connchecker/connchecker.go +++ b/connchecker/connchecker.go @@ -53,9 +53,9 @@ func New(dnsList, domainList []string, checkInterval time.Duration) (*Checker, e } if c.connected { - log.Debug(ConnFound) + log.Debugln(log.Global, ConnFound) } else { - log.Warnf(ConnNotFound) + log.Warnln(log.Global, ConnNotFound) } c.shutdown = make(chan struct{}, 1) @@ -137,7 +137,7 @@ func (c *Checker) connectionTest() { if err == nil { c.Lock() if !c.connected { - log.Debug(ConnRe) + log.Debugln(log.Global, ConnRe) c.connected = true } c.Unlock() @@ -150,7 +150,7 @@ func (c *Checker) connectionTest() { if err == nil { c.Lock() if !c.connected { - log.Debug(ConnRe) + log.Debugln(log.Global, ConnRe) c.connected = true } c.Unlock() @@ -160,7 +160,7 @@ func (c *Checker) connectionTest() { c.Lock() if c.connected { - log.Warn(ConnLost) + log.Warnln(log.Global, ConnLost) c.connected = false } c.Unlock() diff --git a/currency/coinmarketcap/coinmarketcap.go b/currency/coinmarketcap/coinmarketcap.go index d57a68af..b22fe52d 100644 --- a/currency/coinmarketcap/coinmarketcap.go +++ b/currency/coinmarketcap/coinmarketcap.go @@ -86,7 +86,7 @@ func (c *Coinmarketcap) Setup(conf Settings) { } else { err := c.SetAccountPlan(conf.AccountPlan) if err != nil { - log.Errorf("CoinMarketCap enabled but SetAccountPlan failed. Err: %s", err) + log.Errorf(log.Global, "CoinMarketCap enabled but SetAccountPlan failed. Err: %s\n", err) return } c.Enabled = true diff --git a/currency/coinmarketcap/coinmarketcap_test.go b/currency/coinmarketcap/coinmarketcap_test.go index 336f8512..cd6492a3 100644 --- a/currency/coinmarketcap/coinmarketcap_test.go +++ b/currency/coinmarketcap/coinmarketcap_test.go @@ -20,7 +20,7 @@ const ( func areAPICredtionalsSet(minAllowable uint8) bool { if apiAccountPlanLevel != "" && apikey != "" { if err := c.CheckAccountPlan(minAllowable); err != nil { - log.Warn("coinmarketpcap test suite - account plan not allowed for function, please review or upgrade plan to test") + log.Warn(log.Global, "coinmarketpcap test suite - account plan not allowed for function, please review or upgrade plan to test") return false } return true diff --git a/currency/conversion.go b/currency/conversion.go index 5743b4f7..abc0316b 100644 --- a/currency/conversion.go +++ b/currency/conversion.go @@ -76,13 +76,15 @@ func (c *ConversionRates) Register(from, to Code) (Conversion, error) { p, ok := c.m[from.Item][to.Item] if !ok { - log.Errorf("currency conversion rate not found from %s to %s", from, to) + log.Errorf(log.Global, + "currency conversion rate not found from %s to %s\n", from, to) return Conversion{}, errors.New("no rate found") } i, ok := c.m[to.Item][from.Item] if !ok { - log.Errorf("currency conversion inversion rate not found from %s to %s", + log.Errorf(log.Global, + "currency conversion inversion rate not found from %s to %s\n", to, from) return Conversion{}, errors.New("no rate found") @@ -100,7 +102,7 @@ func (c *ConversionRates) Update(m map[string]float64) error { } if storage.IsVerbose() { - log.Debug("Conversion rates are being updated.") + log.Debugln(log.Global, "Conversion rates are being updated.") } solidvalues := make(map[Code]map[Code]float64) @@ -197,7 +199,8 @@ func (c *ConversionRates) Update(m map[string]float64) error { crossRate = 1 / v } if storage.IsVerbose() { - log.Debugf("Conversion from %s to %s deriving cross rate value %f", + log.Debugf(log.Global, + "Conversion from %s to %s deriving cross rate value %f\n", base, term, crossRate) diff --git a/currency/forexprovider/currencyconverterapi/currencyconverterapi.go b/currency/forexprovider/currencyconverterapi/currencyconverterapi.go index d63082db..9ed79b8f 100644 --- a/currency/forexprovider/currencyconverterapi/currencyconverterapi.go +++ b/currency/forexprovider/currencyconverterapi/currencyconverterapi.go @@ -76,7 +76,7 @@ func (c *CurrencyConverter) GetRates(baseCurrency, symbols string) (map[string]f batch := completedStrings[i : i+2] result, err := c.ConvertMany(batch) if err != nil { - log.Errorf("Failed to get batch err: %s", err) + log.Errorf(log.Global, "Failed to get batch err: %s\n", err) continue } for k, v := range result { diff --git a/currency/forexprovider/currencylayer/currencylayer.go b/currency/forexprovider/currencylayer/currencylayer.go index 45f33592..570ebcb2 100644 --- a/currency/forexprovider/currencylayer/currencylayer.go +++ b/currency/forexprovider/currencylayer/currencylayer.go @@ -57,7 +57,8 @@ type CurrencyLayer struct { // Setup sets appropriate values for CurrencyLayer func (c *CurrencyLayer) Setup(config base.Settings) error { if config.APIKeyLvl < 0 || config.APIKeyLvl > 3 { - log.Errorf("apikey incorrectly set in config.json for %s, please set appropriate account levels", + log.Errorf(log.Global, + "apikey incorrectly set in config.json for %s, please set appropriate account levels\n", config.Name) return errors.New("apikey set failure") } diff --git a/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go b/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go index 5a5289a6..076abb09 100644 --- a/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go +++ b/currency/forexprovider/exchangeratesapi.io/exchangeratesapi.go @@ -67,7 +67,8 @@ func cleanCurrencies(baseCurrency, symbols string) string { // remove and warn about any unsupported currencies if !strings.Contains(exchangeRatesSupportedCurrencies, x) { // nolint:gocritic - log.Warnf("Forex provider ExchangeRatesAPI does not support currency %s, removing from forex rates query.", x) + log.Warnf(log.Global, + "Forex provider ExchangeRatesAPI does not support currency %s, removing from forex rates query.\n", x) continue } cleanedCurrencies = append(cleanedCurrencies, x) diff --git a/currency/forexprovider/fixer.io/fixer.go b/currency/forexprovider/fixer.io/fixer.go index 85848cce..bcfda588 100644 --- a/currency/forexprovider/fixer.io/fixer.go +++ b/currency/forexprovider/fixer.io/fixer.go @@ -51,7 +51,8 @@ type Fixer struct { // Setup sets appropriate values for fixer object func (f *Fixer) Setup(config base.Settings) error { if config.APIKeyLvl < 0 || config.APIKeyLvl > 4 { - log.Errorf("apikey incorrectly set in config.json for %s, please set appropriate account levels", + log.Errorf(log.Global, + "apikey incorrectly set in config.json for %s, please set appropriate account levels\n", config.Name) return errors.New("apikey set failure") } diff --git a/currency/forexprovider/openexchangerates/openexchangerates.go b/currency/forexprovider/openexchangerates/openexchangerates.go index 6ac7cfcf..2d4c0b2a 100644 --- a/currency/forexprovider/openexchangerates/openexchangerates.go +++ b/currency/forexprovider/openexchangerates/openexchangerates.go @@ -65,7 +65,8 @@ type OXR struct { // Setup sets values for the OXR object func (o *OXR) Setup(config base.Settings) error { if config.APIKeyLvl < 0 || config.APIKeyLvl > 2 { - log.Errorf("apikey incorrectly set in config.json for %s, please set appropriate account levels", + log.Errorf(log.Global, + "apikey incorrectly set in config.json for %s, please set appropriate account levels\n", config.Name) return errors.New("apikey set failure") } diff --git a/currency/pairs.go b/currency/pairs.go index c6882e66..536faf03 100644 --- a/currency/pairs.go +++ b/currency/pairs.go @@ -51,7 +51,8 @@ func (p Pairs) Format(delimiter, index string, uppercase bool) Pairs { if index != "" { newP, err := NewPairFromIndex(p[i].String(), index) if err != nil { - log.Errorf("failed to create NewPairFromIndex. Err: %s", err) + log.Errorf(log.Global, + "failed to create NewPairFromIndex. Err: %s\n", err) continue } formattedPair.Base = newP.Base diff --git a/currency/storage.go b/currency/storage.go index 87b1a5f1..e4145798 100644 --- a/currency/storage.go +++ b/currency/storage.go @@ -113,10 +113,13 @@ func (s *Storage) RunUpdater(overrides BotOverrides, settings *MainConfiguration return errors.New("currency storage error, no fiat display currency set in config") } s.baseCurrency = settings.FiatDisplayCurrency - log.Debugf("Fiat display currency: %s.", s.baseCurrency) + log.Debugf(log.Global, + "Fiat display currency: %s.\n", s.baseCurrency) if settings.CryptocurrencyProvider.Enabled { - log.Debugf("Setting up currency analysis system with Coinmarketcap...") + log.Debugln( + log.Global, + "Setting up currency analysis system with Coinmarketcap...") c := &coinmarketcap.Coinmarketcap{} c.SetDefaults() c.Setup(coinmarketcap.Settings{ @@ -200,11 +203,13 @@ func (s *Storage) RunUpdater(overrides BotOverrides, settings *MainConfiguration return err } - log.Debugf("Primary foreign exchange conversion provider %s enabled", + log.Debugf(log.Global, + "Primary foreign exchange conversion provider %s enabled\n", s.fiatExchangeMarkets.Primary.Provider.GetName()) for i := range s.fiatExchangeMarkets.Support { - log.Debugf("Support forex conversion provider %s enabled", + log.Debugf(log.Global, + "Support forex conversion provider %s enabled\n", s.fiatExchangeMarkets.Support[i].Provider.GetName()) } @@ -212,7 +217,8 @@ func (s *Storage) RunUpdater(overrides BotOverrides, settings *MainConfiguration // until this system initially updates go s.ForeignExchangeUpdater() } else { - log.Warnf("No foreign exchange providers enabled in config.json") + log.Warnln(log.Global, + "No foreign exchange providers enabled in config.json") s.mtx.Unlock() } @@ -258,19 +264,20 @@ func (s *Storage) SetupForexProviders(setting ...base.Settings) error { // ForeignExchangeUpdater is a routine that seeds foreign exchange rate and keeps // updated as fast as possible func (s *Storage) ForeignExchangeUpdater() { - log.Debugf("Foreign exchange updater started, seeding FX rate list..") + log.Debugln(log.Global, + "Foreign exchange updater started, seeding FX rate list..") s.wg.Add(1) defer s.wg.Done() err := s.SeedCurrencyAnalysisData() if err != nil { - log.Error(err) + log.Errorln(log.Global, err) } err = s.SeedForeignExchangeRates() if err != nil { - log.Error(err) + log.Errorln(log.Global, err) } // Unlock main rate retrieval mutex so all routines waiting can get access @@ -291,13 +298,13 @@ func (s *Storage) ForeignExchangeUpdater() { case <-SeedForeignExchangeTick.C: err := s.SeedForeignExchangeRates() if err != nil { - log.Error(err) + log.Errorln(log.Global, err) } case <-SeedCurrencyAnalysisTick.C: err := s.SeedCurrencyAnalysisData() if err != nil { - log.Error(err) + log.Errorln(log.Global, err) } } } @@ -344,7 +351,8 @@ func (s *Storage) SeedCurrencyAnalysisData() error { // loads it into memory func (s *Storage) FetchCurrencyAnalysisData() error { if s.currencyAnalysis == nil { - log.Warn("Currency analysis system offline, please set api keys for coinmarketcap if you wish to use this feature.") + log.Warnln(log.Global, + "Currency analysis system offline, please set api keys for coinmarketcap if you wish to use this feature.") return errors.New("currency analysis system offline") } diff --git a/engine/addr_helpers_test.go b/engine/addr_helpers_test.go index 34f29a25..e4053a1c 100644 --- a/engine/addr_helpers_test.go +++ b/engine/addr_helpers_test.go @@ -1,64 +1,64 @@ -package engine - -import ( - "testing" - - "github.com/thrasher-/gocryptotrader/currency" -) - -const ( - testBTCAddress = "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX" -) - -func TestSeed(t *testing.T) { - var d DepositAddressStore - u := map[string]map[string]string{ - "BITSTAMP": map[string]string{ - "BTC": testBTCAddress, - }, - } - - d.Seed(u) - r, err := d.GetDepositAddress("BITSTAMP", currency.BTC) - if err != nil { - t.Error("unexpected result") - } - - if r != testBTCAddress { - t.Error("unexpected result") - } -} - -func TestGetDepositAddress(t *testing.T) { - var d DepositAddressStore - _, err := d.GetDepositAddress("", currency.BTC) - if err != ErrDepositAddressStoreIsNil { - t.Error("non-error on non-existent exchange") - } - - d.Store = map[string]map[string]string{ - "BITSTAMP": map[string]string{ - "BTC": testBTCAddress, - }, - } - - _, err = d.GetDepositAddress("", currency.BTC) - if err != ErrExchangeNotFound { - t.Error("non-error on non-existent exchange") - } - - var r string - r, err = d.GetDepositAddress("BiTStAmP", currency.NewCode("bTC")) - if err != nil { - t.Error("unexpected err: ", err) - } - - if r != testBTCAddress { - t.Error("unexpected BTC address: ", r) - } - - _, err = d.GetDepositAddress("BiTStAmP", currency.LTC) - if err != ErrDepositAddressNotFound { - t.Error("unexpected err: ", err) - } -} +package engine + +import ( + "testing" + + "github.com/thrasher-/gocryptotrader/currency" +) + +const ( + testBTCAddress = "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX" +) + +func TestSeed(t *testing.T) { + var d DepositAddressStore + u := map[string]map[string]string{ + "BITSTAMP": { + "BTC": testBTCAddress, + }, + } + + d.Seed(u) + r, err := d.GetDepositAddress("BITSTAMP", currency.BTC) + if err != nil { + t.Error("unexpected result") + } + + if r != testBTCAddress { + t.Error("unexpected result") + } +} + +func TestGetDepositAddress(t *testing.T) { + var d DepositAddressStore + _, err := d.GetDepositAddress("", currency.BTC) + if err != ErrDepositAddressStoreIsNil { + t.Error("non-error on non-existent exchange") + } + + d.Store = map[string]map[string]string{ + "BITSTAMP": { + "BTC": testBTCAddress, + }, + } + + _, err = d.GetDepositAddress("", currency.BTC) + if err != ErrExchangeNotFound { + t.Error("non-error on non-existent exchange") + } + + var r string + r, err = d.GetDepositAddress("BiTStAmP", currency.NewCode("bTC")) + if err != nil { + t.Error("unexpected err: ", err) + } + + if r != testBTCAddress { + t.Error("unexpected BTC address: ", r) + } + + _, err = d.GetDepositAddress("BiTStAmP", currency.LTC) + if err != ErrDepositAddressNotFound { + t.Error("unexpected err: ", err) + } +} diff --git a/engine/comms_relayer.go b/engine/comms_relayer.go index d1a94309..e1a647f4 100644 --- a/engine/comms_relayer.go +++ b/engine/comms_relayer.go @@ -33,7 +33,7 @@ func (c *commsManager) Start() (err error) { } }() - log.Debugln("Communications manager starting...") + log.Debugln(log.CommunicationMgr, "Communications manager starting...") commsCfg := Bot.Config.GetCommunicationsConfig() c.comms, err = communications.NewComm(&commsCfg) if err != nil { @@ -43,7 +43,7 @@ func (c *commsManager) Start() (err error) { c.shutdown = make(chan struct{}) c.relayMsg = make(chan base.Event) go c.run() - log.Debugln("Communications manager started.") + log.Debugln(log.CommunicationMgr, "Communications manager started.") return nil } @@ -64,7 +64,7 @@ func (c *commsManager) Stop() error { } close(c.shutdown) - log.Debugln("Communications manager shutting down...") + log.Debugln(log.CommunicationMgr, "Communications manager shutting down...") return nil } @@ -80,7 +80,7 @@ func (c *commsManager) run() { // TO-DO shutdown comms connections for connected services (Slack etc) atomic.CompareAndSwapInt32(&c.stopped, 1, 0) atomic.CompareAndSwapInt32(&c.started, 1, 0) - log.Debugln("Communications manager shutdown.") + log.Debugln(log.CommunicationMgr, "Communications manager shutdown.") }() for { diff --git a/engine/connection.go b/engine/connection.go index 0b16c8e3..1f931deb 100644 --- a/engine/connection.go +++ b/engine/connection.go @@ -24,7 +24,7 @@ func (c *connectionManager) Start() error { return errors.New("connection manager already started") } - log.Debugln("Connection manager starting...") + log.Debugln(log.ConnectionMgr, "Connection manager starting...") var err error c.conn, err = connchecker.New(Bot.Config.ConnectionMonitor.DNSList, Bot.Config.ConnectionMonitor.PublicDomainList, @@ -34,7 +34,7 @@ func (c *connectionManager) Start() error { return err } - log.Debugln("Connection manager started.") + log.Debugln(log.ConnectionMgr, "Connection manager started.") return nil } @@ -47,17 +47,17 @@ func (c *connectionManager) Stop() error { return errors.New("connection manager is already stopped") } - log.Debugln("Connection manager shutting down...") + log.Debugln(log.ConnectionMgr, "Connection manager shutting down...") c.conn.Shutdown() atomic.CompareAndSwapInt32(&c.stopped, 1, 0) atomic.CompareAndSwapInt32(&c.started, 1, 0) - log.Debugln("Connection manager stopped.") + log.Debugln(log.ConnectionMgr, "Connection manager stopped.") return nil } func (c *connectionManager) IsOnline() bool { if c.conn == nil { - log.Warnf("Connection manager: IsOnline called but conn is nil") + log.Warnln(log.ConnectionMgr, "Connection manager: IsOnline called but conn is nil") return false } diff --git a/engine/engine.go b/engine/engine.go index 8c3d654e..0604aa9d 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -72,7 +72,8 @@ func NewFromSettings(settings *Settings) (*Engine, error) { var b Engine b.Config = &config.Cfg - log.Debugf("Loading config file %s...\n", settings.ConfigFile) + + log.Debugf(log.Global, "Loading config file %s..\n", settings.ConfigFile) err := b.Config.LoadConfig(settings.ConfigFile) if err != nil { return nil, fmt.Errorf("failed to load config. Err: %s", err) @@ -83,19 +84,14 @@ func NewFromSettings(settings *Settings) (*Engine, error) { return nil, fmt.Errorf("failed to open/create data directory: %s. Err: %s", settings.DataDir, err) } - err = log.SetupLogger() - if err != nil { - log.Errorf("Failed to setup logger. Err: %s", err) + if *b.Config.Logging.Enabled { + log.SetupGlobalLogger() + log.SetupSubLoggers(b.Config.Logging.SubLoggers) } b.Settings.ConfigFile = settings.ConfigFile b.Settings.DataDir = settings.DataDir - if *log.Logger.Enabled { - b.Settings.LogFile = log.LogPath - log.Debugf("Using log file: %s.\n", log.LogPath) - } - err = utils.AdjustGoMaxProcs(settings.GoMaxProcs) if err != nil { return nil, fmt.Errorf("unable to adjust runtime GOMAXPROCS value. Err: %s", err) @@ -209,100 +205,101 @@ func ValidateSettings(b *Engine, s *Settings) { // PrintSettings returns the engine settings func PrintSettings(s *Settings) { - log.Debugln() - log.Debugf("ENGINE SETTINGS") - log.Debugf("- CORE SETTINGS:") - log.Debugf("\t Verbose mode: %v", s.Verbose) - log.Debugf("\t Enable dry run mode: %v", s.EnableDryRun) - log.Debugf("\t Enable all exchanges: %v", s.EnableAllExchanges) - log.Debugf("\t Enable all pairs: %v", s.EnableAllPairs) - log.Debugf("\t Enable coinmarketcap analaysis: %v", s.EnableCoinmarketcapAnalysis) - log.Debugf("\t Enable portfolio manager: %v", s.EnablePortfolioManager) - log.Debugf("\t Enable gPRC: %v", s.EnableGRPC) - log.Debugf("\t Enable gRPC Proxy: %v", s.EnableGRPCProxy) - log.Debugf("\t Enable websocket RPC: %v", s.EnableWebsocketRPC) - log.Debugf("\t Enable deprecated RPC: %v", s.EnableDeprecatedRPC) - log.Debugf("\t Enable comms relayer: %v", s.EnableCommsRelayer) - log.Debugf("\t Enable event manager: %v", s.EnableEventManager) - log.Debugf("\t Event manager sleep delay: %v", s.EventManagerDelay) - log.Debugf("\t Enable order manager: %v", s.EnableOrderManager) - log.Debugf("\t Enable exchange sync manager: %v", s.EnableExchangeSyncManager) - log.Debugf("\t Enable deposit address manager: %v\n", s.EnableDepositAddressManager) - log.Debugf("\t Enable ticker syncing: %v", s.EnableTickerSyncing) - log.Debugf("\t Enable orderbook syncing: %v", s.EnableOrderbookSyncing) - log.Debugf("\t Enable websocket routine: %v\n", s.EnableWebsocketRoutine) - log.Debugf("\t Enable NTP client: %v", s.EnableNTPClient) - log.Debugf("- FOREX SETTINGS:") - log.Debugf("\t Enable currency conveter: %v", s.EnableCurrencyConverter) - log.Debugf("\t Enable currency layer: %v", s.EnableCurrencyLayer) - log.Debugf("\t Enable fixer: %v", s.EnableFixer) - log.Debugf("\t Enable OpenExchangeRates: %v", s.EnableOpenExchangeRates) - log.Debugf("- EXCHANGE SETTINGS:") - log.Debugf("\t Enable exchange auto pair updates: %v", s.EnableExchangeAutoPairUpdates) - log.Debugf("\t Disable all exchange auto pair updates: %v", s.DisableExchangeAutoPairUpdates) - log.Debugf("\t Enable exchange websocket support: %v", s.EnableExchangeWebsocketSupport) - log.Debugf("\t Enable exchange verbose mode: %v", s.EnableExchangeVerbose) - log.Debugf("\t Enable exchange HTTP rate limiter: %v", s.EnableExchangeHTTPRateLimiter) - log.Debugf("\t Enable exchange HTTP debugging: %v", s.EnableExchangeHTTPDebugging) - log.Debugf("\t Exchange max HTTP request jobs: %v", s.MaxHTTPRequestJobsLimit) - log.Debugf("\t Exchange HTTP request timeout retry amount: %v", s.RequestTimeoutRetryAttempts) - log.Debugf("\t Exchange HTTP timeout: %v", s.ExchangeHTTPTimeout) - log.Debugf("\t Exchange HTTP user agent: %v", s.ExchangeHTTPUserAgent) - log.Debugf("\t Exchange HTTP proxy: %v\n", s.ExchangeHTTPProxy) - log.Debugf("- COMMON SETTINGS:") - log.Debugf("\t Global HTTP timeout: %v", s.GlobalHTTPTimeout) - log.Debugf("\t Global HTTP user agent: %v", s.GlobalHTTPUserAgent) - log.Debugf("\t Global HTTP proxy: %v", s.ExchangeHTTPProxy) - log.Debugln() + log.Debugln(log.Global) + log.Debugf(log.Global, "ENGINE SETTINGS") + log.Debugf(log.Global, "- CORE SETTINGS:") + log.Debugf(log.Global, "\t Verbose mode: %v", s.Verbose) + log.Debugf(log.Global, "\t Enable dry run mode: %v", s.EnableDryRun) + log.Debugf(log.Global, "\t Enable all exchanges: %v", s.EnableAllExchanges) + log.Debugf(log.Global, "\t Enable all pairs: %v", s.EnableAllPairs) + log.Debugf(log.Global, "\t Enable coinmarketcap analaysis: %v", s.EnableCoinmarketcapAnalysis) + log.Debugf(log.Global, "\t Enable portfolio manager: %v", s.EnablePortfolioManager) + log.Debugf(log.Global, "\t Enable gPRC: %v", s.EnableGRPC) + log.Debugf(log.Global, "\t Enable gRPC Proxy: %v", s.EnableGRPCProxy) + log.Debugf(log.Global, "\t Enable websocket RPC: %v", s.EnableWebsocketRPC) + log.Debugf(log.Global, "\t Enable deprecated RPC: %v", s.EnableDeprecatedRPC) + log.Debugf(log.Global, "\t Enable comms relayer: %v", s.EnableCommsRelayer) + log.Debugf(log.Global, "\t Enable event manager: %v", s.EnableEventManager) + log.Debugf(log.Global, "\t Event manager sleep delay: %v", s.EventManagerDelay) + log.Debugf(log.Global, "\t Enable order manager: %v", s.EnableOrderManager) + log.Debugf(log.Global, "\t Enable exchange sync manager: %v", s.EnableExchangeSyncManager) + log.Debugf(log.Global, "\t Enable deposit address manager: %v\n", s.EnableDepositAddressManager) + log.Debugf(log.Global, "\t Enable ticker syncing: %v", s.EnableTickerSyncing) + log.Debugf(log.Global, "\t Enable orderbook syncing: %v", s.EnableOrderbookSyncing) + log.Debugf(log.Global, "\t Enable websocket routine: %v\n", s.EnableWebsocketRoutine) + log.Debugf(log.Global, "\t Enable NTP client: %v", s.EnableNTPClient) + log.Debugf(log.Global, "- FOREX SETTINGS:") + log.Debugf(log.Global, "\t Enable currency conveter: %v", s.EnableCurrencyConverter) + log.Debugf(log.Global, "\t Enable currency layer: %v", s.EnableCurrencyLayer) + log.Debugf(log.Global, "\t Enable fixer: %v", s.EnableFixer) + log.Debugf(log.Global, "\t Enable OpenExchangeRates: %v", s.EnableOpenExchangeRates) + log.Debugf(log.Global, "- EXCHANGE SETTINGS:") + log.Debugf(log.Global, "\t Enable exchange auto pair updates: %v", s.EnableExchangeAutoPairUpdates) + log.Debugf(log.Global, "\t Disable all exchange auto pair updates: %v", s.DisableExchangeAutoPairUpdates) + log.Debugf(log.Global, "\t Enable exchange websocket support: %v", s.EnableExchangeWebsocketSupport) + log.Debugf(log.Global, "\t Enable exchange verbose mode: %v", s.EnableExchangeVerbose) + log.Debugf(log.Global, "\t Enable exchange HTTP rate limiter: %v", s.EnableExchangeHTTPRateLimiter) + log.Debugf(log.Global, "\t Enable exchange HTTP debugging: %v", s.EnableExchangeHTTPDebugging) + log.Debugf(log.Global, "\t Exchange max HTTP request jobs: %v", s.MaxHTTPRequestJobsLimit) + log.Debugf(log.Global, "\t Exchange HTTP request timeout retry amount: %v", s.RequestTimeoutRetryAttempts) + log.Debugf(log.Global, "\t Exchange HTTP timeout: %v", s.ExchangeHTTPTimeout) + log.Debugf(log.Global, "\t Exchange HTTP user agent: %v", s.ExchangeHTTPUserAgent) + log.Debugf(log.Global, "\t Exchange HTTP proxy: %v\n", s.ExchangeHTTPProxy) + log.Debugf(log.Global, "- COMMON SETTINGS:") + log.Debugf(log.Global, "\t Global HTTP timeout: %v", s.GlobalHTTPTimeout) + log.Debugf(log.Global, "\t Global HTTP user agent: %v", s.GlobalHTTPUserAgent) + log.Debugf(log.Global, "\t Global HTTP proxy: %v", s.ExchangeHTTPProxy) + log.Debugln(log.Global) } // Start starts the engine func (e *Engine) Start() { if e == nil { - log.Fatal("Engine instance is nil") + log.Errorln(log.Global, "Engine instance is nil") + os.Exit(1) } // Sets up internet connectivity monitor if e.Settings.EnableConnectivityMonitor { if err := e.ConnectionManager.Start(); err != nil { - log.Errorf("Connection manager unable to start: %v", err) + log.Errorf(log.Global, "Connection manager unable to start: %v", err) } } if e.Settings.EnableNTPClient { if err := e.NTPManager.Start(); err != nil { - log.Errorf("NTP manager unable to start: %v", err) + log.Errorf(log.Global, "NTP manager unable to start: %v", err) } } e.Uptime = time.Now() - log.Debugf("Bot '%s' started.\n", e.Config.Name) - log.Debugf("Using data dir: %s\n", e.Settings.DataDir) + log.Debugf(log.Global, "Bot '%s' started.\n", e.Config.Name) + log.Debugf(log.Global, "Using data dir: %s\n", e.Settings.DataDir) enabledExchanges := e.Config.CountEnabledExchanges() if e.Settings.EnableAllExchanges { enabledExchanges = len(e.Config.Exchanges) } - log.Debugln() - log.Debugln("EXCHANGE COVERAGE") - log.Debugf("\t Available Exchanges: %d. Enabled Exchanges: %d.\n", + log.Debugln(log.Global, "EXCHANGE COVERAGE") + log.Debugf(log.Global, "\t Available Exchanges: %d. Enabled Exchanges: %d.\n", len(e.Config.Exchanges), enabledExchanges) if e.Settings.ExchangePurgeCredentials { - log.Debugln("Purging exchange API credentials.") + log.Debugln(log.Global, "Purging exchange API credentials.") e.Config.PurgeExchangeAPICredentials() } - log.Debugln("Setting up exchanges..") + log.Debugln(log.Global, "Setting up exchanges..") SetupExchanges() if len(e.Exchanges) == 0 { - log.Fatalf("No exchanges were able to be loaded. Exiting") + log.Errorln(log.Global, "No exchanges were able to be loaded. Exiting") + os.Exit(1) } if e.Settings.EnableCommsRelayer { if err := e.CommsManager.Start(); err != nil { - log.Errorf("Communications manager unable to start: %v", err) + log.Errorf(log.Global, "Communications manager unable to start: %v\n", err) } } @@ -329,7 +326,7 @@ func (e *Engine) Start() { e.Settings.DataDir, e.Settings.Verbose) if err != nil { - log.Warn("currency updater system failed to start", err) + log.Errorf(log.Global, "currency updater system failed to start %v", err) } if e.Settings.EnableGRPC { @@ -347,7 +344,7 @@ func (e *Engine) Start() { if e.Settings.EnablePortfolioManager { if err = e.PortfolioManager.Start(); err != nil { - log.Errorf("Fund manager unable to start: %v", err) + log.Errorf(log.Global, "Fund manager unable to start: %v", err) } } @@ -358,7 +355,7 @@ func (e *Engine) Start() { if e.Settings.EnableOrderManager { if err = e.OrderManager.Start(); err != nil { - log.Errorf("Order manager unable to start: %v", err) + log.Errorf(log.Global, "Order manager unable to start: %v", err) } } @@ -372,7 +369,7 @@ func (e *Engine) Start() { e.ExchangeCurrencyPairManager, err = NewCurrencyPairSyncer(exchangeSyncCfg) if err != nil { - log.Warnf("Unable to initialise exchange currency pair syncer. Err: %s", err) + log.Warnf(log.Global, "Unable to initialise exchange currency pair syncer. Err: %s", err) } else { go e.ExchangeCurrencyPairManager.Start() } @@ -388,7 +385,7 @@ func (e *Engine) Start() { // Stop correctly shuts down engine saving configuration files func (e *Engine) Stop() { - log.Debugln("Engine shutting down..") + log.Debugln(log.Global, "Engine shutting down..") if len(portfolio.Portfolio.Addresses) != 0 { e.Config.Portfolio = portfolio.Portfolio @@ -396,46 +393,50 @@ func (e *Engine) Stop() { if e.OrderManager.Started() { if err := e.OrderManager.Stop(); err != nil { - log.Errorf("Order manager unable to stop. Error: %v", err) + log.Errorf(log.Global, "Order manager unable to stop. Error: %v", err) } } if e.NTPManager.Started() { if err := e.NTPManager.Stop(); err != nil { - log.Errorf("NTP manager unable to stop. Error: %v", err) + log.Errorf(log.Global, "NTP manager unable to stop. Error: %v", err) } } if e.CommsManager.Started() { if err := e.CommsManager.Stop(); err != nil { - log.Errorf("Communication manager unable to stop. Error: %v", err) + log.Errorf(log.Global, "Communication manager unable to stop. Error: %v", err) } } if e.PortfolioManager.Started() { if err := e.PortfolioManager.Stop(); err != nil { - log.Errorf("Fund manager unable to stop. Error: %v", err) + log.Errorf(log.Global, "Fund manager unable to stop. Error: %v", err) } } if e.ConnectionManager.Started() { if err := e.ConnectionManager.Stop(); err != nil { - log.Errorf("Connection manager unable to stop. Error: %v", err) + log.Errorf(log.Global, "Connection manager unable to stop. Error: %v", err) } } if !e.Settings.EnableDryRun { err := e.Config.SaveConfig(e.Settings.ConfigFile) if err != nil { - log.Error("Unable to save config.") + log.Errorln(log.Global, "Unable to save config.") } else { - log.Debugln("Config file saved successfully.") + log.Debugln(log.Global, "Config file saved successfully.") } } // Wait for services to gracefully shutdown e.ServicesWG.Wait() - log.Debugln("Exiting.") - log.CloseLogFile() + log.Debugln(log.Global, "Exiting.") + err := log.CloseLogger() + if err != nil { + fmt.Printf("Failed to close logger %v", err) + } + os.Exit(0) } @@ -447,7 +448,7 @@ func (e *Engine) handleInterrupt() { signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { sig := <-c - log.Debugf("Captured %v, shutdown requested.", sig) + log.Debugf(log.Global, "Captured %v, shutdown requested.\n", sig) close(e.Shutdown) }() } diff --git a/engine/events.go b/engine/events.go index 41b2ae83..f62d1c71 100644 --- a/engine/events.go +++ b/engine/events.go @@ -126,7 +126,7 @@ func (e *Event) ExecuteAction() bool { if strings.Contains(e.Action, ",") { action := strings.Split(e.Action, ",") if action[0] == ActionSMSNotify { - message := fmt.Sprintf("Event triggered: %s", e.String()) + message := fmt.Sprintf("Event triggered: %s\n", e.String()) if action[1] == "ALL" { Bot.CommsManager.PushEvent(base.Event{ Type: "event", @@ -135,7 +135,7 @@ func (e *Event) ExecuteAction() bool { } } } else { - log.Debugf("Event triggered: %s", e.String()) + log.Debugf(log.EventMgr, "Event triggered: %s\n", e.String()) } return true } @@ -143,7 +143,7 @@ func (e *Event) ExecuteAction() bool { // String turns the structure event into a string func (e *Event) String() string { return fmt.Sprintf( - "If the %s [%s] %s on %s meets the following %v then %s.", e.Pair.String(), + "If the %s [%s] %s on %s meets the following %v then %s.\n", e.Pair.String(), strings.ToUpper(e.Asset.String()), e.Item, e.Exchange, e.Condition, e.Action, ) } @@ -152,14 +152,14 @@ func (e *Event) processTicker() bool { t, err := ticker.GetTicker(e.Exchange, e.Pair, e.Asset) if err != nil { if Bot.Settings.Verbose { - log.Debugf("Events: failed to get ticker. Err: %s", err) + log.Debugf(log.EventMgr, "Events: failed to get ticker. Err: %s\n", err) } return false } if t.Last == 0 { if Bot.Settings.Verbose { - log.Debugln("Events: ticker last price is 0") + log.Debugln(log.EventMgr, "Events: ticker last price is 0") } return false } @@ -196,7 +196,7 @@ func (e *Event) processOrderbook() bool { ob, err := orderbook.Get(e.Exchange, e.Pair, e.Asset) if err != nil { if Bot.Settings.Verbose { - log.Debugf("Events: Failed to get orderbook. Err: %s", err) + log.Debugf(log.EventMgr, "Events: Failed to get orderbook. Err: %s\n", err) } return false } @@ -208,7 +208,7 @@ func (e *Event) processOrderbook() bool { result := e.processCondition(subtotal, e.Condition.OrderbookAmount) if result { success = true - log.Debugf("Events: Bid Amount: %f Price: %v Subtotal: %v", ob.Bids[x].Amount, ob.Bids[x].Price, subtotal) + log.Debugf(log.EventMgr, "Events: Bid Amount: %f Price: %v Subtotal: %v\n", ob.Bids[x].Amount, ob.Bids[x].Price, subtotal) } } } @@ -219,7 +219,7 @@ func (e *Event) processOrderbook() bool { result := e.processCondition(subtotal, e.Condition.OrderbookAmount) if result { success = true - log.Debugf("Events: Ask Amount: %f Price: %v Subtotal: %v", ob.Asks[x].Amount, ob.Asks[x].Price, subtotal) + log.Debugf(log.EventMgr, "Events: Ask Amount: %f Price: %v Subtotal: %v\n", ob.Asks[x].Amount, ob.Asks[x].Price, subtotal) } } } @@ -281,7 +281,7 @@ func IsValidEvent(exchange, item string, condition EventConditionParams, action // EventManger is the overarching routine that will iterate through the Events // chain func EventManger() { - log.Debugf("EventManager started. SleepDelay: %v", EventSleepDelay.String()) + log.Debugf(log.EventMgr, "EventManager started. SleepDelay: %v\n", EventSleepDelay.String()) for { total, executed := GetEventCounter() @@ -289,7 +289,7 @@ func EventManger() { for _, event := range Events { if !event.Executed { if Bot.Settings.Verbose { - log.Debugf("Events: Processing event %s.", event.String()) + log.Debugf(log.EventMgr, "Events: Processing event %s.\n", event.String()) } success := event.CheckEventCondition() if success { @@ -297,7 +297,7 @@ func EventManger() { "Events: ID: %d triggered on %s successfully [%v]\n", event.ID, event.Exchange, event.String(), ) - log.Info(msg) + log.Infoln(log.EventMgr, msg) Bot.CommsManager.PushEvent(base.Event{Type: "event", Message: msg}) event.Executed = true } diff --git a/engine/exchange.go b/engine/exchange.go index 92b7aa50..eea04ed0 100644 --- a/engine/exchange.go +++ b/engine/exchange.go @@ -83,7 +83,7 @@ func ReloadExchange(name string) error { e := GetExchangeByName(name) e.Setup(exchCfg) - log.Debugf("%s exchange reloaded successfully.\n", name) + log.Debugf(log.ExchangeSys, "%s exchange reloaded successfully.\n", name) return nil } @@ -275,13 +275,13 @@ func SetupExchanges() { if CheckExchangeExists(exch.Name) { e := GetExchangeByName(exch.Name) if e == nil { - log.Errorf("%s", ErrExchangeNotFound) + log.Errorln(log.ExchangeSys, ErrExchangeNotFound) continue } err := ReloadExchange(exch.Name) if err != nil { - log.Errorf("ReloadExchange %s failed: %s", exch.Name, err) + log.Errorf(log.ExchangeSys, "ReloadExchange %s failed: %s\n", exch.Name, err) continue } @@ -293,15 +293,15 @@ func SetupExchanges() { } if !exch.Enabled && !Bot.Settings.EnableAllExchanges { - log.Debugf("%s: Exchange support: Disabled", exch.Name) + log.Debugf(log.ExchangeSys, "%s: Exchange support: Disabled\n", exch.Name) continue } err := LoadExchange(exch.Name, true, &wg) if err != nil { - log.Errorf("LoadExchange %s failed: %s", exch.Name, err) + log.Errorf(log.ExchangeSys, "LoadExchange %s failed: %s\n", exch.Name, err) continue } - log.Debugf( + log.Debugf(log.ExchangeSys, "%s: Exchange support: Enabled (Authenticated API support: %s - Verbose mode: %s).\n", exch.Name, common.IsEnabled(exch.API.AuthenticatedSupport), diff --git a/engine/helpers.go b/engine/helpers.go index ebe5ad3d..0ac7ccce 100644 --- a/engine/helpers.go +++ b/engine/helpers.go @@ -119,7 +119,7 @@ func GetExchangeOTPs() (map[string]string, error) { exchName := Bot.Config.Exchanges[x].Name o, err := totp.GenerateCode(otpSecret, time.Now()) if err != nil { - log.Errorf("Unable to generate OTP code for exchange %s. Err: %s", + log.Errorf(log.Global, "Unable to generate OTP code for exchange %s. Err: %s\n", exchName, err) continue } @@ -541,7 +541,7 @@ func SeedExchangeAccountInfo(data []exchange.AccountInfo) { continue } - log.Debugf("Portfolio: Adding new exchange address: %s, %s, %f, %s\n", + log.Debugf(log.PortfolioMgr, "Portfolio: Adding new exchange address: %s, %s, %f, %s\n", exchangeName, currencyName, total, @@ -556,7 +556,7 @@ func SeedExchangeAccountInfo(data []exchange.AccountInfo) { } else { if total <= 0 { - log.Debugf("Portfolio: Removing %s %s entry.\n", + log.Debugf(log.PortfolioMgr, "Portfolio: Removing %s %s entry.\n", exchangeName, currencyName) @@ -571,7 +571,7 @@ func SeedExchangeAccountInfo(data []exchange.AccountInfo) { } if balance != total { - log.Debugf("Portfolio: Updating %s %s entry with balance %f.\n", + log.Debugf(log.PortfolioMgr, "Portfolio: Updating %s %s entry with balance %f.\n", exchangeName, currencyName, total) @@ -668,14 +668,14 @@ func GetExchangeCryptocurrencyDepositAddresses() map[string]map[string]string { exchName := Bot.Exchanges[x].GetName() if !Bot.Exchanges[x].GetAuthenticatedAPISupport(exchange.RestAuthentication) { if Bot.Settings.Verbose { - log.Debugf("GetExchangeCryptocurrencyDepositAddresses: Skippping %s due to disabled authenticated API support.", exchName) + log.Debugf(log.ExchangeSys, "GetExchangeCryptocurrencyDepositAddresses: Skippping %s due to disabled authenticated API support.\n", exchName) } continue } cryptoCurrencies, err := GetCryptocurrenciesByExchange(exchName, true, true, asset.Spot) if err != nil { - log.Debugf("%s failed to get cryptocurrency deposit addresses. Err: %s", exchName, err) + log.Debugf(log.ExchangeSys, "%s failed to get cryptocurrency deposit addresses. Err: %s\n", exchName, err) continue } @@ -684,7 +684,7 @@ func GetExchangeCryptocurrencyDepositAddresses() map[string]map[string]string { cryptocurrency := cryptoCurrencies[y] depositAddr, err := Bot.Exchanges[x].GetDepositAddress(currency.NewCode(cryptocurrency), "") if err != nil { - log.Debugf("%s failed to get cryptocurrency deposit addresses. Err: %s", exchName, err) + log.Errorf(log.Global, "%s failed to get cryptocurrency deposit addresses. Err: %s\n", exchName, err) continue } cryptoAddr[cryptocurrency] = depositAddr @@ -748,7 +748,7 @@ func GetAllActiveTickers() []EnabledExchangeCurrencies { for z := range currencies { tp, err := exch.FetchTicker(currencies[z], assets[y]) if err != nil { - log.Debugf("Exchange %s failed to retrieve %s ticker. Err: %s", exchName, + log.Errorf(log.ExchangeSys, "Exchange %s failed to retrieve %s ticker. Err: %s\n", exchName, currencies[z].String(), err) continue @@ -768,13 +768,13 @@ func GetAllEnabledExchangeAccountInfo() AllEnabledExchangeAccounts { if individualBot != nil && individualBot.IsEnabled() { if !individualBot.GetAuthenticatedAPISupport(exchange.RestAuthentication) { if Bot.Settings.Verbose { - log.Debugf("GetAllEnabledExchangeAccountInfo: Skippping %s due to disabled authenticated API support.", individualBot.GetName()) + log.Debugf(log.ExchangeSys, "GetAllEnabledExchangeAccountInfo: Skippping %s due to disabled authenticated API support.\n", individualBot.GetName()) } continue } individualExchange, err := individualBot.GetAccountInfo() if err != nil { - log.Debugf("Error encountered retrieving exchange account info for %s. Error %s", + log.Errorf(log.ExchangeSys, "Error encountered retrieving exchange account info for %s. Error %s\n", individualBot.GetName(), err) continue } @@ -795,7 +795,7 @@ func checkCerts() error { return genCert(targetDir) } - log.Debugf("gRPC TLS certs directory already exists, will use them.") + log.Debugln(log.Global, "gRPC TLS certs directory already exists, will use them.") return nil } @@ -875,6 +875,6 @@ func genCert(targetDir string) error { return fmt.Errorf("failed to write cert.pem file %s", err) } - log.Debugf("TLS key.pem and cert.pem files written to %s", targetDir) + log.Debugf(log.Global, "TLS key.pem and cert.pem files written to %s\n", targetDir) return nil } diff --git a/engine/orders.go b/engine/orders.go index 9f6a8177..8feec650 100644 --- a/engine/orders.go +++ b/engine/orders.go @@ -62,7 +62,7 @@ func (o *orderManager) Start() error { return errors.New("order manager already started") } - log.Debugln("Order manager starting...") + log.Debugln(log.OrderBook, "Order manager starting...") o.shutdown = make(chan struct{}) o.orderStore.Orders = make(map[string][]exchange.OrderDetail) @@ -82,23 +82,23 @@ func (o *orderManager) Stop() error { atomic.CompareAndSwapInt32(&o.started, 1, 0) }() - log.Debugln("Order manager shutting down...") + log.Debugln(log.OrderBook, "Order manager shutting down...") close(o.shutdown) return nil } func (o *orderManager) gracefulShutdown() { if o.cfg.CancelOrdersOnShutdown { - log.Debug("Order manager: Cancelling any open orders...") + log.Debugln(log.OrderMgr, "Order manager: Cancelling any open orders...") orders := o.orderStore.Get() if orders == nil { return } for k, v := range orders { - log.Debugf("Order manager: Cancelling order(s) for exchange %s.", k) + log.Debugf(log.OrderMgr, "Order manager: Cancelling order(s) for exchange %s.\n", k) for y := range v { - log.Debugf("order manager: Cancelling order ID %v [%v]", + log.Debugf(log.OrderMgr, "order manager: Cancelling order ID %v [%v]", v[y].ID, v[y]) err := o.Cancel(k, &exchange.OrderCancellation{ OrderID: v[y].ID, @@ -106,7 +106,7 @@ func (o *orderManager) gracefulShutdown() { if err != nil { msg := fmt.Sprintf("Order manager: Exchange %s unable to cancel order ID=%v. Err: %s", k, v[y].ID, err) - log.Debugln(msg) + log.Debugln(log.OrderBook, msg) Bot.CommsManager.PushEvent(base.Event{ Type: "order", Message: msg, @@ -116,7 +116,7 @@ func (o *orderManager) gracefulShutdown() { msg := fmt.Sprintf("Order manager: Exchange %s order ID=%v cancelled.", k, v[y].ID) - log.Debugln(msg) + log.Debugln(log.OrderBook, msg) Bot.CommsManager.PushEvent(base.Event{ Type: "order", Message: msg, @@ -127,11 +127,11 @@ func (o *orderManager) gracefulShutdown() { } func (o *orderManager) run() { - log.Debugln("Order manager started.") + log.Debugln(log.OrderBook, "Order manager started.") tick := time.NewTicker(OrderManagerDelay) Bot.ServicesWG.Add(1) defer func() { - log.Debugf("Order manager shutdown.") + log.Debugln(log.OrderMgr, "Order manager shutdown.") tick.Stop() Bot.ServicesWG.Done() }() @@ -213,7 +213,7 @@ func (o *orderManager) Submit(exchName string, order *exchange.OrderSubmission) id, err := common.GetV4UUID() if err != nil { - log.Warnf("Order manager: Unable to generate UUID. Err: %s", err) + log.Warnf(log.OrderMgr, "Order manager: Unable to generate UUID. Err: %s\n", err) } result, err := exch.SubmitOrder(order) @@ -227,7 +227,7 @@ func (o *orderManager) Submit(exchName string, order *exchange.OrderSubmission) msg := fmt.Sprintf("Order manager: Exchange %s submitted order ID=%v [Ours: %v] pair=%v price=%v amount=%v side=%v type=%v.", exchName, result.OrderID, id.String(), order.Pair, order.Price, order.Amount, order.OrderSide, order.OrderType) - log.Debugln(msg) + log.Debugln(log.OrderMgr, msg) Bot.CommsManager.PushEvent(base.Event{ Type: "order", Message: msg, @@ -244,7 +244,7 @@ func (o *orderManager) Submit(exchName string, order *exchange.OrderSubmission) func (o *orderManager) processOrders() { authExchanges := GetAuthAPISupportedExchanges() for x := range authExchanges { - log.Debugf("Order manager: Procesing orders for exchange %v.", authExchanges[x]) + log.Debugf(log.OrderMgr, "Order manager: Procesing orders for exchange %v.\n", authExchanges[x]) exch := GetExchangeByName(authExchanges[x]) req := exchange.GetOrdersRequest{ OrderSide: exchange.AnyOrderSide, @@ -252,7 +252,7 @@ func (o *orderManager) processOrders() { } result, err := exch.GetActiveOrders(&req) if err != nil { - log.Debugf("Order manager: Unable to get active orders: %s", err) + log.Warnf(log.OrderMgr, "Order manager: Unable to get active orders: %s\n", err) continue } @@ -262,7 +262,7 @@ func (o *orderManager) processOrders() { if result != ErrOrdersAlreadyExists { msg := fmt.Sprintf("Order manager: Exchange %s added order ID=%v pair=%v price=%v amount=%v side=%v type=%v.", order.Exchange, order.ID, order.CurrencyPair, order.Price, order.Amount, order.OrderSide, order.OrderType) - log.Debug(msg) + log.Debugf(log.OrderMgr, "%v\n", msg) Bot.CommsManager.PushEvent(base.Event{ Type: "order", Message: msg, diff --git a/engine/portfolio.go b/engine/portfolio.go index 3116472f..62f6989b 100644 --- a/engine/portfolio.go +++ b/engine/portfolio.go @@ -29,7 +29,7 @@ func (p *portfolioManager) Start() error { return errors.New("portfolio manager already started") } - log.Debugln("Portfolio manager starting...") + log.Debugln(log.PortfolioMgr, "Portfolio manager starting...") Bot.Portfolio = &portfolio.Portfolio Bot.Portfolio.Seed(Bot.Config.Portfolio) p.shutdown = make(chan struct{}) @@ -41,13 +41,13 @@ func (p *portfolioManager) Stop() error { return errors.New("portfolio manager is already stopped") } - log.Debugln("Portfolio manager shutting down...") + log.Debugln(log.PortfolioMgr, "Portfolio manager shutting down...") close(p.shutdown) return nil } func (p *portfolioManager) run() { - log.Debugln("Portfolio manager started.") + log.Debugln(log.PortfolioMgr, "Portfolio manager started.") Bot.ServicesWG.Add(1) tick := time.NewTicker(PortfolioSleepDelay) defer func() { @@ -55,7 +55,7 @@ func (p *portfolioManager) run() { atomic.CompareAndSwapInt32(&p.started, 1, 0) tick.Stop() Bot.ServicesWG.Done() - log.Debugf("Portfolio manager shutdown.") + log.Debugf(log.PortfolioMgr, "Portfolio manager shutdown.") }() for { @@ -75,7 +75,7 @@ func (p *portfolioManager) processPortfolio() { for key, value := range data { success := pf.UpdatePortfolio(value, key) if success { - log.Debugf( + log.Debugf(log.PortfolioMgr, "Portfolio manager: Successfully updated address balance for %s address(es) %s\n", key, value, ) diff --git a/engine/restful_router.go b/engine/restful_router.go index 3e988597..3a3b5ce1 100644 --- a/engine/restful_router.go +++ b/engine/restful_router.go @@ -19,7 +19,7 @@ func RESTLogger(inner http.Handler, name string) http.Handler { start := time.Now() inner.ServeHTTP(w, r) - log.Debugf( + log.Debugf(log.RESTSys, "%s\t%s\t%s\t%s", r.Method, r.RequestURI, @@ -32,20 +32,24 @@ func RESTLogger(inner http.Handler, name string) http.Handler { // StartRESTServer starts a REST server func StartRESTServer() { listenAddr := Bot.Config.RemoteControl.DeprecatedRPC.ListenAddress - log.Debugf("Deprecated RPC server support enabled. Listen URL: http://%s:%d\n", common.ExtractHost(listenAddr), common.ExtractPort(listenAddr)) + log.Debugf(log.RESTSys, + "Deprecated RPC server support enabled. Listen URL: http://%s:%d\n", + common.ExtractHost(listenAddr), common.ExtractPort(listenAddr)) err := http.ListenAndServe(listenAddr, newRouter(true)) if err != nil { - log.Errorf("Failed to start deprecated RPC server. Err: %s", err) + log.Errorf(log.RESTSys, "Failed to start deprecated RPC server. Err: %s", err) } } // StartWebsocketServer starts a Websocket server func StartWebsocketServer() { listenAddr := Bot.Config.RemoteControl.WebsocketRPC.ListenAddress - log.Debugf("Websocket RPC support enabled. Listen URL: ws://%s:%d/ws\n", common.ExtractHost(listenAddr), common.ExtractPort(listenAddr)) + log.Debugf(log.RESTSys, + "Websocket RPC support enabled. Listen URL: ws://%s:%d/ws\n", + common.ExtractHost(listenAddr), common.ExtractPort(listenAddr)) err := http.ListenAndServe(listenAddr, newRouter(false)) if err != nil { - log.Errorf("Failed to start websocket RPC server. Err: %s", err) + log.Errorf(log.RESTSys, "Failed to start websocket RPC server. Err: %s", err) } } @@ -81,7 +85,9 @@ func newRouter(isREST bool) *mux.Router { } if Bot.Config.Profiler.Enabled { - log.Debugf("HTTP Go performance profiler (pprof) endpoint enabled: http://%s:%d/debug", common.ExtractHost(listenAddr), + log.Debugf(log.RESTSys, + "HTTP Go performance profiler (pprof) endpoint enabled: http://%s:%d/debug\n", + common.ExtractHost(listenAddr), common.ExtractPort(listenAddr)) router.PathPrefix("/debug").Handler(http.DefaultServeMux) } diff --git a/engine/restful_server.go b/engine/restful_server.go index 6139d3c0..d1443ede 100644 --- a/engine/restful_server.go +++ b/engine/restful_server.go @@ -18,7 +18,7 @@ func RESTfulJSONResponse(w http.ResponseWriter, response interface{}) error { // RESTfulError prints the REST method and error func RESTfulError(method string, err error) { - log.Errorf("RESTful %s: server failed to send JSON response. Error %s", + log.Errorf(log.RESTSys, "RESTful %s: server failed to send JSON response. Error %s\n", method, err) } @@ -74,7 +74,8 @@ func GetAllActiveOrderbooks() []EnabledExchangeOrderbooks { for z := range currencies { ob, err := exch.FetchOrderbook(currencies[z], assets[y]) if err != nil { - log.Errorf("Exchange %s failed to retrieve %s orderbook. Err: %s", exchName, + log.Errorf(log.RESTSys, + "Exchange %s failed to retrieve %s orderbook. Err: %s\n", exchName, currencies[z].String(), err) continue diff --git a/engine/routines.go b/engine/routines.go index e687a08f..c1e9b255 100644 --- a/engine/routines.go +++ b/engine/routines.go @@ -20,7 +20,7 @@ import ( func printCurrencyFormat(price float64) string { displaySymbol, err := currency.GetSymbolByCurrencyName(Bot.Config.Currency.FiatDisplayCurrency) if err != nil { - log.Errorf("Failed to get display symbol: %s", err) + log.Errorf(log.Global, "Failed to get display symbol: %s\n", err) } return fmt.Sprintf("%s%.8f", displaySymbol, price) @@ -32,17 +32,17 @@ func printConvertCurrencyFormat(origCurrency currency.Code, origPrice float64) s origCurrency, displayCurrency) if err != nil { - log.Errorf("Failed to convert currency: %s", err) + log.Errorf(log.Global, "Failed to convert currency: %s\n", err) } displaySymbol, err := currency.GetSymbolByCurrencyName(displayCurrency) if err != nil { - log.Errorf("Failed to get display symbol: %s", err) + log.Errorf(log.Global, "Failed to get display symbol: %s\n", err) } origSymbol, err := currency.GetSymbolByCurrencyName(origCurrency) if err != nil { - log.Errorf("Failed to get original currency symbol for %s: %s", + log.Errorf(log.Global, "Failed to get original currency symbol for %s: %s\n", origCurrency, err) } @@ -59,7 +59,7 @@ func printConvertCurrencyFormat(origCurrency currency.Code, origPrice float64) s func printTickerSummary(result *ticker.Price, p currency.Pair, assetType asset.Item, exchangeName string, err error) { if err != nil { - log.Errorf("Failed to get %s %s ticker. Error: %s", + log.Errorf(log.Ticker, "Failed to get %s %s ticker. Error: %s\n", p.String(), exchangeName, err) @@ -70,7 +70,7 @@ func printTickerSummary(result *ticker.Price, p currency.Pair, assetType asset.I if p.Quote.IsFiatCurrency() && p.Quote != Bot.Config.Currency.FiatDisplayCurrency { origCurrency := p.Quote.Upper() - log.Infof("%s %s %s: TICKER: Last %s Ask %s Bid %s High %s Low %s Volume %.8f", + log.Infof(log.Ticker, "%s %s %s: TICKER: Last %s Ask %s Bid %s High %s Low %s Volume %.8f\n", exchangeName, FormatCurrency(p).String(), assetType, @@ -83,7 +83,7 @@ func printTickerSummary(result *ticker.Price, p currency.Pair, assetType asset.I } else { if p.Quote.IsFiatCurrency() && p.Quote == Bot.Config.Currency.FiatDisplayCurrency { - log.Infof("%s %s %s: TICKER: Last %s Ask %s Bid %s High %s Low %s Volume %.8f", + log.Infof(log.Ticker, "%s %s %s: TICKER: Last %s Ask %s Bid %s High %s Low %s Volume %.8f\n", exchangeName, FormatCurrency(p).String(), assetType, @@ -94,7 +94,7 @@ func printTickerSummary(result *ticker.Price, p currency.Pair, assetType asset.I printCurrencyFormat(result.Low), result.Volume) } else { - log.Infof("%s %s %s: TICKER: Last %.8f Ask %.8f Bid %.8f High %.8f Low %.8f Volume %.8f", + log.Infof(log.Ticker, "%s %s %s: TICKER: Last %.8f Ask %.8f Bid %.8f High %.8f Low %.8f Volume %.8f\n", exchangeName, FormatCurrency(p).String(), assetType, @@ -110,7 +110,7 @@ func printTickerSummary(result *ticker.Price, p currency.Pair, assetType asset.I func printOrderbookSummary(result *orderbook.Base, p currency.Pair, assetType asset.Item, exchangeName string, err error) { if err != nil { - log.Errorf("Failed to get %s %s orderbook of type %s. Error: %s", + log.Errorf(log.OrderBook, "Failed to get %s %s orderbook of type %s. Error: %s\n", p, exchangeName, assetType, @@ -124,7 +124,7 @@ func printOrderbookSummary(result *orderbook.Base, p currency.Pair, assetType as if p.Quote.IsFiatCurrency() && p.Quote != Bot.Config.Currency.FiatDisplayCurrency { origCurrency := p.Quote.Upper() - log.Infof("%s %s %s: ORDERBOOK: Bids len: %d Amount: %f %s. Total value: %s Asks len: %d Amount: %f %s. Total value: %s", + log.Infof(log.OrderBook, "%s %s %s: ORDERBOOK: Bids len: %d Amount: %f %s. Total value: %s Asks len: %d Amount: %f %s. Total value: %s\n", exchangeName, FormatCurrency(p).String(), assetType, @@ -140,7 +140,7 @@ func printOrderbookSummary(result *orderbook.Base, p currency.Pair, assetType as } else { if p.Quote.IsFiatCurrency() && p.Quote == Bot.Config.Currency.FiatDisplayCurrency { - log.Infof("%s %s %s: ORDERBOOK: Bids len: %d Amount: %f %s. Total value: %s Asks len: %d Amount: %f %s. Total value: %s", + log.Infof(log.OrderBook, "%s %s %s: ORDERBOOK: Bids len: %d Amount: %f %s. Total value: %s Asks len: %d Amount: %f %s. Total value: %s\n", exchangeName, FormatCurrency(p).String(), assetType, @@ -154,7 +154,7 @@ func printOrderbookSummary(result *orderbook.Base, p currency.Pair, assetType as printCurrencyFormat(asksValue), ) } else { - log.Infof("%s %s %s: ORDERBOOK: Bids len: %d Amount: %f %s. Total value: %f Asks len: %d Amount: %f %s. Total value: %f", + log.Infof(log.OrderBook, "%s %s %s: ORDERBOOK: Bids len: %d Amount: %f %s. Total value: %f Asks len: %d Amount: %f %s. Total value: %f\n", exchangeName, FormatCurrency(p).String(), assetType, @@ -180,7 +180,7 @@ func relayWebsocketEvent(result interface{}, event, assetType, exchangeName stri } err := BroadcastWebsocketMessage(evt) if err != nil { - log.Errorf("Failed to broadcast websocket event %v. Error: %s", + log.Errorf(log.WebsocketMgr, "Failed to broadcast websocket event %v. Error: %s\n", event, err) } } @@ -188,7 +188,7 @@ func relayWebsocketEvent(result interface{}, event, assetType, exchangeName stri // TickerUpdaterRoutine fetches and updates the ticker for all enabled // currency pairs and exchanges func TickerUpdaterRoutine() { - log.Debugf("Starting ticker updater routine.") + log.Debugln(log.Ticker, "Starting ticker updater routine.") var wg sync.WaitGroup for { wg.Add(len(Bot.Exchanges)) @@ -233,7 +233,7 @@ func TickerUpdaterRoutine() { }(x, &wg) } wg.Wait() - log.Debugln("All enabled currency tickers fetched.") + log.Debugln(log.Ticker, "All enabled currency tickers fetched.") time.Sleep(time.Second * 10) } } @@ -241,7 +241,7 @@ func TickerUpdaterRoutine() { // OrderbookUpdaterRoutine fetches and updates the orderbooks for all enabled // currency pairs and exchanges func OrderbookUpdaterRoutine() { - log.Debugln("Starting orderbook updater routine.") + log.Debugln(log.OrderBook, "Starting orderbook updater routine.") var wg sync.WaitGroup for { wg.Add(len(Bot.Exchanges)) @@ -275,7 +275,7 @@ func OrderbookUpdaterRoutine() { }(x, &wg) } wg.Wait() - log.Debugln("All enabled currency orderbooks fetched.") + log.Debugln(log.OrderBook, "All enabled currency orderbooks fetched.") time.Sleep(time.Second * 10) } } @@ -283,14 +283,14 @@ func OrderbookUpdaterRoutine() { // WebsocketRoutine Initial routine management system for websocket func WebsocketRoutine() { if Bot.Settings.Verbose { - log.Debugln("Connecting exchange websocket services...") + log.Debugln(log.WebsocketMgr, "Connecting exchange websocket services...") } for i := range Bot.Exchanges { go func(i int) { if Bot.Exchanges[i].SupportsWebsocket() { if Bot.Settings.Verbose { - log.Debugf("Exchange %s websocket support: Yes Enabled: %v", Bot.Exchanges[i].GetName(), + log.Debugf(log.WebsocketMgr, "Exchange %s websocket support: Yes Enabled: %v\n", Bot.Exchanges[i].GetName(), common.IsEnabled(Bot.Exchanges[i].IsWebsocketEnabled())) } @@ -304,11 +304,11 @@ func WebsocketRoutine() { err = ws.Connect() if err != nil { - log.Println(err) + log.Errorf(log.WebsocketMgr, "%v\n", err) } } } else if Bot.Settings.Verbose { - log.Debugf("Exchange %s websocket support: No", Bot.Exchanges[i].GetName()) + log.Debugf(log.WebsocketMgr, "Exchange %s websocket support: No\n", Bot.Exchanges[i].GetName()) } }(i) } @@ -322,7 +322,7 @@ var wg sync.WaitGroup func Websocketshutdown(ws *exchange.Websocket) error { err := ws.Shutdown() // shutdown routines on the exchange if err != nil { - log.Errorf("routines.go error - failed to shutdown %s", err) + log.Errorf(log.WebsocketMgr, "routines.go error - failed to shutdown %s\n", err) } timer := time.NewTimer(5 * time.Second) @@ -356,12 +356,12 @@ func streamDiversion(ws *exchange.Websocket) { case <-ws.Connected: if Bot.Settings.Verbose { - log.Debugf("exchange %s websocket feed connected", ws.GetName()) + log.Debugf(log.WebsocketMgr, "exchange %s websocket feed connected\n", ws.GetName()) } case <-ws.Disconnected: if Bot.Settings.Verbose { - log.Debugf("exchange %s websocket feed disconnected, switching to REST functionality", + log.Debugf(log.WebsocketMgr, "exchange %s websocket feed disconnected, switching to REST functionality\n", ws.GetName()) } } @@ -387,12 +387,12 @@ func WebsocketDataHandler(ws *exchange.Websocket) { switch d { case exchange.WebsocketNotEnabled: if Bot.Settings.Verbose { - log.Warnf("routines.go warning - exchange %s weboscket not enabled", + log.Warnf(log.WebsocketMgr, "routines.go warning - exchange %s weboscket not enabled\n", ws.GetName()) } default: - log.Infof(d) + log.Info(log.WebsocketMgr, d) } case error: @@ -401,7 +401,7 @@ func WebsocketDataHandler(ws *exchange.Websocket) { go ws.WebsocketReset() continue default: - log.Errorf("routines.go exchange %s websocket error - %s", ws.GetName(), data) + log.Errorf(log.WebsocketMgr, "routines.go exchange %s websocket error - %s", ws.GetName(), data) } case exchange.TradeData: @@ -433,7 +433,7 @@ func WebsocketDataHandler(ws *exchange.Websocket) { case exchange.KlineData: // Kline data if Bot.Settings.Verbose { - log.Infoln("Websocket Kline Updated: ", d) + log.Infof(log.WebsocketMgr, "Websocket Kline Updated: %v\n", d) } case exchange.WebsocketOrderbookUpdate: // Orderbook data @@ -443,10 +443,13 @@ func WebsocketDataHandler(ws *exchange.Websocket) { result.Pair, result.Asset, SyncItemOrderbook, nil) } // TO-DO: printOrderbookSummary - //nolint:gocritic log.Infof("Websocket %s %s orderbook updated", ws.GetName(), result.Pair.Pair().String()) + //nolint:gocritic + if Bot.Settings.Verbose { + log.Infof(log.WebsocketMgr, "Websocket %s %s orderbook updated\n", ws.GetName(), result.Pair.String()) + } default: if Bot.Settings.Verbose { - log.Warnf("Websocket Unknown type: %s", d) + log.Warnf(log.WebsocketMgr, "Websocket Unknown type: %s\n", d) } } } diff --git a/engine/rpcserver.go b/engine/rpcserver.go index ea0ed348..8de40aed 100644 --- a/engine/rpcserver.go +++ b/engine/rpcserver.go @@ -64,21 +64,21 @@ func authenticateClient(ctx context.Context) (context.Context, error) { func StartRPCServer() { err := checkCerts() if err != nil { - log.Errorf("gRPC checkCerts failed. err: %s", err) + log.Errorf(log.GRPCSys, "gRPC checkCerts failed. err: %s\n", err) return } - log.Debugf("gRPC server support enabled. Starting gRPC server on https://%v.", Bot.Config.RemoteControl.GRPC.ListenAddress) + log.Debugf(log.GRPCSys, "gRPC server support enabled. Starting gRPC server on https://%v.\n", Bot.Config.RemoteControl.GRPC.ListenAddress) lis, err := net.Listen("tcp", Bot.Config.RemoteControl.GRPC.ListenAddress) if err != nil { - log.Errorf("gRPC server failed to bind to port: %s", err) + log.Errorf(log.GRPCSys, "gRPC server failed to bind to port: %s", err) return } targetDir := utils.GetTLSDir(Bot.Settings.DataDir) creds, err := credentials.NewServerTLSFromFile(filepath.Join(targetDir, "cert.pem"), filepath.Join(targetDir, "key.pem")) if err != nil { - log.Errorf("gRPC server could not load TLS keys: %s", err) + log.Errorf(log.GRPCSys, "gRPC server could not load TLS keys: %s\n", err) return } @@ -92,12 +92,12 @@ func StartRPCServer() { go func() { if err := server.Serve(lis); err != nil { - log.Errorf("gRPC server failed to serve: %s", err) + log.Errorf(log.GRPCSys, "gRPC server failed to serve: %s\n", err) return } }() - log.Debugf("gRPC server started!") + log.Debugln(log.GRPCSys, "gRPC server started!") if Bot.Settings.EnableGRPCProxy { StartRPCRESTProxy() @@ -106,7 +106,7 @@ func StartRPCServer() { // StartRPCRESTProxy starts a gRPC proxy func StartRPCRESTProxy() { - log.Debugf("gRPC proxy server support enabled. Starting gRPC proxy server on http://%v.", Bot.Config.RemoteControl.GRPC.GRPCProxyListenAddress) + log.Debugf(log.GRPCSys, "gRPC proxy server support enabled. Starting gRPC proxy server on http://%v.\n", Bot.Config.RemoteControl.GRPC.GRPCProxyListenAddress) ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -114,7 +114,7 @@ func StartRPCRESTProxy() { targetDir := utils.GetTLSDir(Bot.Settings.DataDir) creds, err := credentials.NewClientTLSFromFile(filepath.Join(targetDir, "cert.pem"), "") if err != nil { - log.Errorf("Unabled to start gRPC proxy. Err: %s", err) + log.Errorf(log.GRPCSys, "Unabled to start gRPC proxy. Err: %s\n", err) return } @@ -127,17 +127,17 @@ func StartRPCRESTProxy() { } err = gctrpc.RegisterGoCryptoTraderHandlerFromEndpoint(ctx, mux, Bot.Config.RemoteControl.GRPC.ListenAddress, opts) if err != nil { - log.Errorf("Failed to register gRPC proxy. Err: %s", err) + log.Errorf(log.GRPCSys, "Failed to register gRPC proxy. Err: %s\n", err) } go func() { if err := http.ListenAndServe(Bot.Config.RemoteControl.GRPC.GRPCProxyListenAddress, mux); err != nil { - log.Errorf("gRPC proxy failed to server: %s", err) + log.Errorf(log.GRPCSys, "gRPC proxy failed to server: %s\n", err) return } }() - log.Debugf("gRPC proxy server started!") + log.Debugln(log.GRPCSys, "gRPC proxy server started!") select {} } @@ -606,7 +606,7 @@ func (s *RPCServer) GetForexRates(ctx context.Context, r *gctrpc.GetForexRatesRe func (s *RPCServer) GetOrders(ctx context.Context, r *gctrpc.GetOrdersRequest) (*gctrpc.GetOrdersResponse, error) { exch := GetExchangeByName(r.Exchange) if exch == nil { - log.Debugln(exch) + log.Debugln(log.GRPCSys, exch) return nil, errors.New("exchange is not loaded/doesn't exist") } @@ -827,3 +827,31 @@ func (s *RPCServer) WithdrawCryptocurrencyFunds(ctx context.Context, r *gctrpc.W func (s *RPCServer) WithdrawFiatFunds(ctx context.Context, r *gctrpc.WithdrawCurrencyRequest) (*gctrpc.WithdrawResponse, error) { return &gctrpc.WithdrawResponse{}, common.ErrNotYetImplemented } + +func (s *RPCServer) GetLoggerDetails(ctx context.Context, r *gctrpc.GetLoggerDetailsRequest) (*gctrpc.GetLoggerDetailsResponse, error) { + levels, err := log.Level(r.Logger) + if err != nil { + return nil, err + } + + return &gctrpc.GetLoggerDetailsResponse{ + Info: levels.Info, + Debug: levels.Debug, + Warn: levels.Warn, + Error: levels.Error, + }, nil +} + +func (s *RPCServer) SetLoggerDetails(ctx context.Context, r *gctrpc.SetLoggerDetailsRequest) (*gctrpc.GetLoggerDetailsResponse, error) { + levels, err := log.SetLevel(r.Logger, r.Level) + if err != nil { + return nil, err + } + + return &gctrpc.GetLoggerDetailsResponse{ + Info: levels.Info, + Debug: levels.Debug, + Warn: levels.Warn, + Error: levels.Error, + }, nil +} diff --git a/engine/syncer.go b/engine/syncer.go index 7c164b31..bebe1721 100644 --- a/engine/syncer.go +++ b/engine/syncer.go @@ -48,12 +48,12 @@ func NewCurrencyPairSyncer(c CurrencyPairSyncerConfig) (*ExchangeCurrencyPairSyn s.tickerBatchLastRequested = make(map[string]time.Time) - log.Debugf("Exchange currency pair syncer config:") - log.Debugf("SyncContinuously: %v", s.Cfg.SyncContinuously) - log.Debugf("SyncTicker: %v", s.Cfg.SyncTicker) - log.Debugf("SyncOrderbook: %v", s.Cfg.SyncOrderbook) - log.Debugf("SyncTrades: %v", s.Cfg.SyncTrades) - log.Debugf("NumWorkers: %v", s.Cfg.NumWorkers) + log.Debugln(log.SyncMgr, "Exchange currency pair syncer config:") + log.Debugf(log.SyncMgr, "SyncContinuously: %v\n", s.Cfg.SyncContinuously) + log.Debugf(log.SyncMgr, "SyncTicker: %v\n", s.Cfg.SyncTicker) + log.Debugf(log.SyncMgr, "SyncOrderbook: %v\n", s.Cfg.SyncOrderbook) + log.Debugf(log.SyncMgr, "SyncTrades: %v\n", s.Cfg.SyncTrades) + log.Debugf(log.SyncMgr, "NumWorkers: %v\n", s.Cfg.NumWorkers) return &s, nil } @@ -92,7 +92,7 @@ func (e *ExchangeCurrencyPairSyncer) add(c *CurrencyPairSyncAgent) { defer e.mux.Unlock() if e.Cfg.SyncTicker { - log.Debugf("%s: Added ticker sync item %v: using websocket: %v using REST: %v", c.Exchange, c.Pair.String(), + log.Debugf(log.SyncMgr, "%s: Added ticker sync item %v: using websocket: %v using REST: %v\n", c.Exchange, c.Pair.String(), c.Ticker.IsUsingWebsocket, c.Ticker.IsUsingREST) if atomic.LoadInt32(&e.initSyncCompleted) != 1 { e.initSyncWG.Add(1) @@ -101,7 +101,7 @@ func (e *ExchangeCurrencyPairSyncer) add(c *CurrencyPairSyncAgent) { } if e.Cfg.SyncOrderbook { - log.Debugf("%s: Added orderbook sync item %v: using websocket: %v using REST: %v", c.Exchange, c.Pair.String(), + log.Debugf(log.SyncMgr, "%s: Added orderbook sync item %v: using websocket: %v using REST: %v\n", c.Exchange, c.Pair.String(), c.Orderbook.IsUsingWebsocket, c.Orderbook.IsUsingREST) if atomic.LoadInt32(&e.initSyncCompleted) != 1 { e.initSyncWG.Add(1) @@ -110,7 +110,7 @@ func (e *ExchangeCurrencyPairSyncer) add(c *CurrencyPairSyncAgent) { } if e.Cfg.SyncTrades { - log.Debugf("%s: Added trade sync item %v: using websocket: %v using REST: %v", c.Exchange, c.Pair.String(), + log.Debugf(log.SyncMgr, "%s: Added trade sync item %v: using websocket: %v using REST: %v\n", c.Exchange, c.Pair.String(), c.Trade.IsUsingWebsocket, c.Trade.IsUsingREST) if atomic.LoadInt32(&e.initSyncCompleted) != 1 { e.initSyncWG.Add(1) @@ -197,7 +197,7 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair return } default: - log.Warnf("ExchangeCurrencyPairSyncer: unknown sync item %v", syncType) + log.Warnf(log.SyncMgr, "ExchangeCurrencyPairSyncer: unknown sync item %v\n", syncType) return } @@ -218,7 +218,7 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair e.CurrencyPairs[x].Ticker.HaveData = true e.CurrencyPairs[x].Ticker.IsProcessing = false if atomic.LoadInt32(&e.initSyncCompleted) != 1 && !origHadData { - log.Debugf("%s ticker sync complete %v [%d/%d].", exchangeName, p, removedCounter, createdCounter) + log.Debugf(log.SyncMgr, "%s ticker sync complete %v [%d/%d].\n", exchangeName, p, removedCounter, createdCounter) removedCounter++ e.initSyncWG.Done() } @@ -232,7 +232,7 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair e.CurrencyPairs[x].Orderbook.HaveData = true e.CurrencyPairs[x].Orderbook.IsProcessing = false if atomic.LoadInt32(&e.initSyncCompleted) != 1 && !origHadData { - log.Debugf("%s orderbook sync complete %v [%d/%d].", exchangeName, p, removedCounter, createdCounter) + log.Debugf(log.SyncMgr, "%s orderbook sync complete %v [%d/%d].\n", exchangeName, p, removedCounter, createdCounter) removedCounter++ e.initSyncWG.Done() } @@ -246,7 +246,7 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair e.CurrencyPairs[x].Trade.HaveData = true e.CurrencyPairs[x].Trade.IsProcessing = false if atomic.LoadInt32(&e.initSyncCompleted) != 1 && !origHadData { - log.Debugf("%s trade sync complete %v [%d/%d].", exchangeName, p, removedCounter, createdCounter) + log.Debugf(log.SyncMgr, "%s trade sync complete %v [%d/%d].\n", exchangeName, p, removedCounter, createdCounter) removedCounter++ e.initSyncWG.Done() } @@ -257,7 +257,7 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair func (e *ExchangeCurrencyPairSyncer) worker() { cleanup := func() { - log.Debugf("Exchange CurrencyPairSyncer worker shutting down.") + log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer worker shutting down.") } defer cleanup() @@ -277,7 +277,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() { if Bot.Exchanges[x].SupportsWebsocket() && Bot.Exchanges[x].IsWebsocketEnabled() { ws, err := Bot.Exchanges[x].GetWebsocket() if err != nil { - log.Debugf("%s unable to get websocket pointer. Err: %s", exchangeName, err) + log.Errorf(log.SyncMgr, "%s unable to get websocket pointer. Err: %s\n", exchangeName, err) usingREST = true } @@ -329,7 +329,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() { c, err := e.get(exchangeName, p, assetTypes[y]) if err != nil { - log.Errorf("failed to get item. Err: %s", err) + log.Errorf(log.SyncMgr, "failed to get item. Err: %s\n", err) continue } @@ -345,7 +345,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() { e.setProcessing(c.Exchange, c.Pair, c.AssetType, SyncItemTicker, true) c.Ticker.IsUsingWebsocket = false c.Ticker.IsUsingREST = true - log.Warnf("%s %s: No ticker update after 10 seconds, switching from websocket to rest", + log.Warnf(log.SyncMgr, "%s %s: No ticker update after 10 seconds, switching from websocket to rest\n", c.Exchange, c.Pair.String()) e.setProcessing(c.Exchange, c.Pair, c.AssetType, SyncItemTicker, false) } @@ -367,14 +367,14 @@ func (e *ExchangeCurrencyPairSyncer) worker() { if batchLastDone.IsZero() || time.Since(batchLastDone) > defaultSyncerTimeout { e.mux.Lock() if e.Cfg.Verbose { - log.Debugf("%s Init'ing REST ticker batching", exchangeName) + log.Debugf(log.SyncMgr, "%s Init'ing REST ticker batching\n", exchangeName) } result, err = Bot.Exchanges[x].UpdateTicker(c.Pair, c.AssetType) e.tickerBatchLastRequested[exchangeName] = time.Now() e.mux.Unlock() } else { if e.Cfg.Verbose { - log.Debugf("%s Using recent batching cache", exchangeName) + log.Debugf(log.OrderMgr, "%s Using recent batching cache\n", exchangeName) } result, err = Bot.Exchanges[x].FetchTicker(c.Pair, c.AssetType) } @@ -407,7 +407,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() { e.setProcessing(c.Exchange, c.Pair, c.AssetType, SyncItemOrderbook, true) c.Orderbook.IsUsingWebsocket = false c.Orderbook.IsUsingREST = true - log.Warnf("%s %s: No orderbook update after 15 seconds, switching from websocket to rest", + log.Warnf(log.SyncMgr, "%s %s: No orderbook update after 15 seconds, switching from websocket to rest\n", c.Exchange, c.Pair.String()) e.setProcessing(c.Exchange, c.Pair, c.AssetType, SyncItemOrderbook, false) } @@ -445,7 +445,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() { // Start starts an exchange currency pair syncer func (e *ExchangeCurrencyPairSyncer) Start() { - log.Debugf("Exchange CurrencyPairSyncer started.") + log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer started.") for x := range Bot.Exchanges { if !Bot.Exchanges[x].IsEnabled() { @@ -458,7 +458,7 @@ func (e *ExchangeCurrencyPairSyncer) Start() { supportsREST := Bot.Exchanges[x].SupportsREST() if !supportsREST && !supportsWebsocket { - log.Warnf("Loaded exchange %s does not support REST or Websocket.", exchangeName) + log.Warnf(log.SyncMgr, "Loaded exchange %s does not support REST or Websocket.\n", exchangeName) continue } @@ -468,7 +468,7 @@ func (e *ExchangeCurrencyPairSyncer) Start() { if supportsWebsocket { ws, err := Bot.Exchanges[x].GetWebsocket() if err != nil { - log.Errorf("%s failed to get websocket. Err: %s", exchangeName, err) + log.Errorf(log.SyncMgr, "%s failed to get websocket. Err: %s\n", exchangeName, err) usingREST = true } @@ -481,7 +481,7 @@ func (e *ExchangeCurrencyPairSyncer) Start() { err = ws.Connect() if err != nil { - log.Errorf("%s websocket failed to connect. Err: %s", exchangeName, err) + log.Errorf(log.SyncMgr, "%s websocket failed to connect. Err: %s\n", exchangeName, err) usingREST = true } else { usingWebsocket = true @@ -529,21 +529,21 @@ func (e *ExchangeCurrencyPairSyncer) Start() { } if atomic.CompareAndSwapInt32(&e.initSyncStarted, 0, 1) { - log.Debugln("Exchange CurrencyPairSyncer initial sync started.") + log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer initial sync started.") e.initSyncStartTime = time.Now() - log.Debugln(createdCounter) - log.Debugln(removedCounter) + log.Debugln(log.SyncMgr, createdCounter) + log.Debugln(log.SyncMgr, removedCounter) } go func() { e.initSyncWG.Wait() if atomic.CompareAndSwapInt32(&e.initSyncCompleted, 0, 1) { - log.Debugf("Exchange CurrencyPairSyncer initial sync is complete.") + log.Debugf(log.SyncMgr, "Exchange CurrencyPairSyncer initial sync is complete.\n") completedTime := time.Now() - log.Debugf("Exchange CurrencyPairSyncer initiial sync took %v [%v sync items].", completedTime.Sub(e.initSyncStartTime), createdCounter) + log.Debugf(log.SyncMgr, "Exchange CurrencyPairSyncer initiial sync took %v [%v sync items].\n", completedTime.Sub(e.initSyncStartTime), createdCounter) if !e.Cfg.SyncContinuously { - log.Debugf("Exchange CurrencyPairSyncer stopping.") + log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer stopping.") e.Stop() Bot.Stop() return @@ -564,6 +564,6 @@ func (e *ExchangeCurrencyPairSyncer) Start() { func (e *ExchangeCurrencyPairSyncer) Stop() { stopped := atomic.CompareAndSwapInt32(&e.shutdown, 0, 1) if stopped { - log.Debugf("Exchange CurrencyPairSyncer stopped.") + log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer stopped.") } } diff --git a/engine/syncer_test.go b/engine/syncer_test.go index ad846564..832f0575 100644 --- a/engine/syncer_test.go +++ b/engine/syncer_test.go @@ -5,7 +5,6 @@ import ( "time" "github.com/thrasher-/gocryptotrader/config" - log "github.com/thrasher-/gocryptotrader/logger" ) func TestNewCurrencyPairSyncer(t *testing.T) { @@ -27,7 +26,7 @@ func TestNewCurrencyPairSyncer(t *testing.T) { SetupExchanges() if err != nil { - log.Printf("failed to start exchange syncer") + t.Log("failed to start exchange syncer") } Bot.ExchangeCurrencyPairManager, err = NewCurrencyPairSyncer(CurrencyPairSyncerConfig{ diff --git a/engine/timekeeper.go b/engine/timekeeper.go index b42fbd1c..3e9d1a83 100644 --- a/engine/timekeeper.go +++ b/engine/timekeeper.go @@ -42,7 +42,7 @@ func (n *ntpManager) Start() (err error) { } }() - log.Debugln("NTP manager starting...") + log.Debugln(log.TimeMgr, "NTP manager starting...") if Bot.Config.NTPClient.Level == 0 { // Initial NTP check (prompts user on how we should proceed) n.inititalCheck = true @@ -55,7 +55,7 @@ func (n *ntpManager) Start() (err error) { case nil: break case errNTPDisabled: - log.Debugf("NTP manager: User disabled NTP prompts. Exiting.") + log.Debugln(log.TimeMgr, "NTP manager: User disabled NTP prompts. Exiting.") disable = true err = nil return @@ -68,7 +68,7 @@ func (n *ntpManager) Start() (err error) { } n.shutdown = make(chan struct{}) go n.run() - log.Debugln("NTP manager started.") + log.Debugln(log.TimeMgr, "NTP manager started.") return nil } @@ -82,7 +82,7 @@ func (n *ntpManager) Stop() error { } close(n.shutdown) - log.Debugln("NTP manager shutting down...") + log.Debugln(log.TimeMgr, "NTP manager shutting down...") return nil } @@ -92,7 +92,7 @@ func (n *ntpManager) run() { t.Stop() atomic.CompareAndSwapInt32(&n.stopped, 1, 0) atomic.CompareAndSwapInt32(&n.started, 1, 0) - log.Debugln("NTP manager shutdown.") + log.Debugln(log.TimeMgr, "NTP manager shutdown.") }() for { @@ -123,14 +123,14 @@ func (n *ntpManager) processTime() error { configNTPTime := *Bot.Config.NTPClient.AllowedDifference configNTPNegativeTime := (*Bot.Config.NTPClient.AllowedNegativeDifference - (*Bot.Config.NTPClient.AllowedNegativeDifference * 2)) if NTPcurrentTimeDifference > configNTPTime || NTPcurrentTimeDifference < configNTPNegativeTime { - log.Warnf("NTP manager: Time out of sync (NTP): %v | (time.Now()): %v | (Difference): %v | (Allowed): +%v / %v", NTPTime, currentTime, NTPcurrentTimeDifference, configNTPTime, configNTPNegativeTime) + log.Warnf(log.TimeMgr, "NTP manager: Time out of sync (NTP): %v | (time.Now()): %v | (Difference): %v | (Allowed): +%v / %v\n", NTPTime, currentTime, NTPcurrentTimeDifference, configNTPTime, configNTPNegativeTime) if n.inititalCheck { n.inititalCheck = false disable, err := Bot.Config.DisableNTPCheck(os.Stdin) if err != nil { return fmt.Errorf("unable to disable NTP check: %s", err) } - log.Info(disable) + log.Infoln(log.TimeMgr, disable) if Bot.Config.NTPClient.Level == -1 { return errNTPDisabled } diff --git a/engine/websocket.go b/engine/websocket.go index af8b2210..67c62580 100644 --- a/engine/websocket.go +++ b/engine/websocket.go @@ -59,7 +59,7 @@ func (h *WebsocketHub) run() { h.Clients[client] = true case client := <-h.Unregister: if _, ok := h.Clients[client]; ok { - log.Debugln("websocket: disconnected client") + log.Debugln(log.WebsocketMgr, "websocket: disconnected client") delete(h.Clients, client) close(client.Send) } @@ -68,7 +68,7 @@ func (h *WebsocketHub) run() { select { case client.Send <- message: default: - log.Debugln("websocket: disconnected client") + log.Debugln(log.WebsocketMgr, "websocket: disconnected client") close(client.Send) delete(h.Clients, client) } @@ -81,7 +81,7 @@ func (h *WebsocketHub) run() { func (c *WebsocketClient) SendWebsocketMessage(evt interface{}) error { data, err := common.JSONEncode(evt) if err != nil { - log.Errorf("websocket: failed to send message: %s", err) + log.Errorf(log.WebsocketMgr, "websocket: failed to send message: %s\n", err) return err } @@ -99,7 +99,7 @@ func (c *WebsocketClient) read() { msgType, message, err := c.Conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { - log.Errorf("websocket: client disconnected, err: %s", err) + log.Errorf(log.WebsocketMgr, "websocket: client disconnected, err: %s\n", err) } break } @@ -108,39 +108,39 @@ func (c *WebsocketClient) read() { var evt WebsocketEvent err := common.JSONDecode(message, &evt) if err != nil { - log.Errorf("websocket: failed to decode JSON sent from client %s", err) + log.Errorf(log.WebsocketMgr, "websocket: failed to decode JSON sent from client %s\n", err) continue } if evt.Event == "" { - log.Warnf("websocket: client sent a blank event, disconnecting") + log.Warnln(log.WebsocketMgr, "websocket: client sent a blank event, disconnecting") continue } dataJSON, err := common.JSONEncode(evt.Data) if err != nil { - log.Errorf("websocket: client sent data we couldn't JSON decode") + log.Errorln(log.WebsocketMgr, "websocket: client sent data we couldn't JSON decode") break } req := strings.ToLower(evt.Event) - log.Debugf("websocket: request received: %s", req) + log.Debugf(log.WebsocketMgr, "websocket: request received: %s\n", req) result, ok := wsHandlers[req] if !ok { - log.Debugln("websocket: unsupported event") + log.Debugln(log.WebsocketMgr, "websocket: unsupported event") continue } if result.authRequired && !c.Authenticated { - log.Warnf("Websocket: request %s failed due to unauthenticated request on an authenticated API", evt.Event) + log.Warnf(log.WebsocketMgr, "Websocket: request %s failed due to unauthenticated request on an authenticated API\n", evt.Event) c.SendWebsocketMessage(WebsocketEventResponse{Event: evt.Event, Error: "unauthorised request on authenticated API"}) continue } err = result.handler(c, dataJSON) if err != nil { - log.Errorf("websocket: request %s failed. Error %s", evt.Event, err) + log.Errorf(log.WebsocketMgr, "websocket: request %s failed. Error %s\n", evt.Event, err) continue } } @@ -156,13 +156,13 @@ func (c *WebsocketClient) write() { case message, ok := <-c.Send: if !ok { c.Conn.WriteMessage(websocket.CloseMessage, []byte{}) - log.Debugln("websocket: hub closed the channel") + log.Debugln(log.WebsocketMgr, "websocket: hub closed the channel") return } w, err := c.Conn.NextWriter(websocket.TextMessage) if err != nil { - log.Errorf("websocket: failed to create new io.writeCloser: %s", err) + log.Errorf(log.WebsocketMgr, "websocket: failed to create new io.writeCloser: %s\n", err) return } w.Write(message) @@ -174,7 +174,7 @@ func (c *WebsocketClient) write() { } if err := w.Close(); err != nil { - log.Errorf("websocket: failed to close io.WriteCloser: %s", err) + log.Errorf(log.WebsocketMgr, "websocket: failed to close io.WriteCloser: %s\n", err) return } } @@ -217,7 +217,8 @@ func WebsocketClientHandler(w http.ResponseWriter, r *http.Request) { numClients := len(wsHub.Clients) if numClients >= connectionLimit { - log.Warnf("websocket: client rejected due to websocket client limit reached. Number of clients %d. Limit %d.", + log.Warnf(log.WebsocketMgr, + "websocket: client rejected due to websocket client limit reached. Number of clients %d. Limit %d.\n", numClients, connectionLimit) w.WriteHeader(http.StatusForbidden) return @@ -236,13 +237,14 @@ func WebsocketClientHandler(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - log.Error(err) + log.Error(log.WebsocketMgr, err) return } client := &WebsocketClient{Hub: wsHub, Conn: conn, Send: make(chan []byte, 1024)} client.Hub.Register <- client - log.Debugf("websocket: client connected. Connected clients: %d. Limit %d.", + log.Debugf(log.WebsocketMgr, + "websocket: client connected. Connected clients: %d. Limit %d.\n", numClients+1, connectionLimit) go client.read() @@ -266,7 +268,8 @@ func wsAuth(client *WebsocketClient, data interface{}) error { if auth.Username == Bot.Config.RemoteControl.Username && auth.Password == hashPW { client.Authenticated = true wsResp.Data = WebsocketResponseSuccess - log.Debugf("websocket: client authenticated successfully") + log.Debugln(log.WebsocketMgr, + "websocket: client authenticated successfully") return client.SendWebsocketMessage(wsResp) } @@ -274,13 +277,15 @@ func wsAuth(client *WebsocketClient, data interface{}) error { client.authFailures++ client.SendWebsocketMessage(wsResp) if client.authFailures >= Bot.Config.RemoteControl.WebsocketRPC.MaxAuthFailures { - log.Debugf("websocket: disconnecting client, maximum auth failures threshold reached (failures: %d limit: %d)", + log.Debugf(log.WebsocketMgr, + "websocket: disconnecting client, maximum auth failures threshold reached (failures: %d limit: %d)\n", client.authFailures, Bot.Config.RemoteControl.WebsocketRPC.MaxAuthFailures) wsHub.Unregister <- client return nil } - log.Debugf("websocket: client sent wrong username/password (failures: %d limit: %d)", + log.Debugf(log.WebsocketMgr, + "websocket: client sent wrong username/password (failures: %d limit: %d)\n", client.authFailures, Bot.Config.RemoteControl.WebsocketRPC.MaxAuthFailures) return nil } diff --git a/exchanges/alphapoint/alphapoint_websocket.go b/exchanges/alphapoint/alphapoint_websocket.go index 88b023e5..a75d745b 100644 --- a/exchanges/alphapoint/alphapoint_websocket.go +++ b/exchanges/alphapoint/alphapoint_websocket.go @@ -20,25 +20,25 @@ func (a *Alphapoint) WebsocketClient() { a.WebsocketConn, _, err = Dialer.Dial(a.API.Endpoints.WebsocketURL, http.Header{}) if err != nil { - log.Errorf("%s Unable to connect to Websocket. Error: %s\n", a.Name, err) + log.Errorf(log.ExchangeSys, "%s Unable to connect to Websocket. Error: %s\n", a.Name, err) continue } if a.Verbose { - log.Debugf("%s Connected to Websocket.\n", a.Name) + log.Debugf(log.ExchangeSys, "%s Connected to Websocket.\n", a.Name) } err = a.WebsocketConn.WriteMessage(websocket.TextMessage, []byte(`{"messageType": "logon"}`)) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) return } for a.Enabled { msgType, resp, err := a.WebsocketConn.ReadMessage() if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) break } @@ -50,7 +50,7 @@ func (a *Alphapoint) WebsocketClient() { msgType := MsgType{} err := common.JSONDecode(resp, &msgType) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } @@ -58,13 +58,13 @@ func (a *Alphapoint) WebsocketClient() { ticker := WebsocketTicker{} err = common.JSONDecode(resp, &ticker) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } } } } a.WebsocketConn.Close() - log.Debugf("%s Websocket client disconnected.", a.Name) + log.Debugf(log.ExchangeSys, "%s Websocket client disconnected.", a.Name) } } diff --git a/exchanges/anx/anx.go b/exchanges/anx/anx.go index 0fd32314..66939779 100644 --- a/exchanges/anx/anx.go +++ b/exchanges/anx/anx.go @@ -206,7 +206,7 @@ func (a *ANX) GetOrderList(isActiveOrdersOnly bool) ([]OrderResponse, error) { } if response.ResultCode != "OK" { - log.Errorf("Response code is not OK: %s\n", response.ResultCode) + log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode) return nil, errors.New(response.ResultCode) } @@ -232,7 +232,7 @@ func (a *ANX) OrderInfo(orderID string) (OrderResponse, error) { } if response.ResultCode != "OK" { - log.Errorf("Response code is not OK: %s\n", response.ResultCode) + log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode) return OrderResponse{}, errors.New(response.ResultCode) } return response.Order, nil @@ -263,7 +263,7 @@ func (a *ANX) Send(currency, address, otp, amount string) (string, error) { } if response.ResultCode != "OK" { - log.Errorf("Response code is not OK: %s\n", response.ResultCode) + log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode) return "", errors.New(response.ResultCode) } return response.TransactionID, nil @@ -289,7 +289,7 @@ func (a *ANX) CreateNewSubAccount(currency, name string) (string, error) { } if response.ResultCode != "OK" { - log.Errorf("Response code is not OK: %s\n", response.ResultCode) + log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode) return "", errors.New(response.ResultCode) } return response.SubAccount, nil @@ -323,7 +323,7 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) ( } if response.ResultCode != "OK" { - log.Errorf("Response code is not OK: %s\n", response.ResultCode) + log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode) return "", errors.New(response.ResultCode) } @@ -356,7 +356,7 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf } if a.Verbose { - log.Debugf("Request JSON: %s\n", PayloadJSON) + log.Debugf(log.ExchangeSys, "Request JSON: %s\n", PayloadJSON) } hmac := crypto.GetHMAC(crypto.HashSHA512, []byte(path+string("\x00")+string(PayloadJSON)), []byte(a.API.Credentials.Secret)) @@ -430,7 +430,7 @@ func (a *ANX) GetAccountInformation() (AccountInformation, error) { } if response.ResultCode != "OK" { - log.Errorf("Response code is not OK: %s\n", response.ResultCode) + log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode) return response, errors.New(response.ResultCode) } return response, nil @@ -453,7 +453,7 @@ func (a *ANX) CheckAPIWithdrawPermission() (bool, error) { } if !apiAllowsWithdraw { - log.Warn("API key is missing withdrawal permissions") + log.Warn(log.ExchangeSys, "API key is missing withdrawal permissions") } return apiAllowsWithdraw, nil diff --git a/exchanges/anx/anx_wrapper.go b/exchanges/anx/anx_wrapper.go index e0472ab8..9cd16ef5 100644 --- a/exchanges/anx/anx_wrapper.go +++ b/exchanges/anx/anx_wrapper.go @@ -130,12 +130,13 @@ func (a *ANX) Run() { if !common.StringDataContains(a.GetEnabledPairs(asset.Spot).Strings(), "_") || !common.StringDataContains(a.GetAvailablePairs(asset.Spot).Strings(), "_") { enabledPairs := currency.NewPairsFromStrings([]string{"BTC_USD,BTC_HKD,BTC_EUR,BTC_CAD,BTC_AUD,BTC_SGD,BTC_JPY,BTC_GBP,BTC_NZD,LTC_BTC,DOG_EBTC,STR_BTC,XRP_BTC"}) - log.Warn("WARNING: Enabled pairs for ANX reset due to config upgrade, please enable the ones you would like again.") + log.Warn(log.ExchangeSys, + "Enabled pairs for ANX reset due to config upgrade, please enable the ones you would like again.") forceUpdate = true err := a.UpdatePairs(enabledPairs, asset.Spot, true, true) if err != nil { - log.Errorf("%s failed to update currencies.\n", a.GetName()) + log.Errorf(log.ExchangeSys, "%s failed to update currencies.\n", a.GetName()) return } } @@ -146,7 +147,7 @@ func (a *ANX) Run() { err := a.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", a.GetName(), err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", a.GetName(), err) } } diff --git a/exchanges/binance/binance.go b/exchanges/binance/binance.go index 8c753b60..574ac2ec 100644 --- a/exchanges/binance/binance.go +++ b/exchanges/binance/binance.go @@ -499,7 +499,7 @@ func (b *Binance) SendAuthHTTPRequest(method, path string, params url.Values, re headers["X-MBX-APIKEY"] = b.API.Credentials.Key if b.Verbose { - log.Debugf("sent path: %s", path) + log.Debugf(log.ExchangeSys, "sent path: %s", path) } path = common.EncodeURLValues(path, params) diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 275f89bc..2ca56073 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -131,7 +131,8 @@ func (b *Binance) Start(wg *sync.WaitGroup) { // Run implements the Binance wrapper func (b *Binance) Run() { if b.Verbose { - log.Debugf("%s Websocket: %s. (url: %s).\n", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()), b.Websocket.GetWebsocketURL()) + log.Debugf(log.ExchangeSys, + "%s Websocket: %s. (url: %s).\n", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()), b.Websocket.GetWebsocketURL()) b.PrintEnabledPairs() } @@ -139,12 +140,13 @@ func (b *Binance) Run() { if !common.StringDataContains(b.GetEnabledPairs(asset.Spot).Strings(), "-") || !common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), "-") { enabledPairs := currency.NewPairsFromStrings([]string{"BTC-USDT"}) - log.Warn("WARNING: Available pairs for Binance reset due to config upgrade, please enable the ones you would like again") + log.Warn(log.ExchangeSys, + "Available pairs for Binance reset due to config upgrade, please enable the ones you would like again") forceUpdate = true err := b.UpdatePairs(enabledPairs, asset.Spot, true, true) if err != nil { - log.Errorf("%s failed to update currencies. Err: %s\n", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err: %s\n", b.Name, err) } } @@ -154,7 +156,7 @@ func (b *Binance) Run() { err := b.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } diff --git a/exchanges/bitfinex/bitfinex.go b/exchanges/bitfinex/bitfinex.go index e4836dad..710dc492 100644 --- a/exchanges/bitfinex/bitfinex.go +++ b/exchanges/bitfinex/bitfinex.go @@ -951,7 +951,7 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[ } if b.Verbose { - log.Debugf("Request JSON: %s\n", PayloadJSON) + log.Debugf(log.ExchangeSys, "Request JSON: %s\n", PayloadJSON) } PayloadBase64 := crypto.Base64Encode(PayloadJSON) diff --git a/exchanges/bitfinex/bitfinex_websocket.go b/exchanges/bitfinex/bitfinex_websocket.go index b535a63c..5a19acb7 100644 --- a/exchanges/bitfinex/bitfinex_websocket.go +++ b/exchanges/bitfinex/bitfinex_websocket.go @@ -73,7 +73,7 @@ func (b *Bitfinex) wsSend(data interface{}) error { return err } if b.Verbose { - log.Debugf("%v sending message to websocket %v", b.Name, data) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", b.Name, data) } return b.WebsocketConn.WriteMessage(websocket.TextMessage, json) } @@ -119,7 +119,7 @@ func (b *Bitfinex) WsAddSubscriptionChannel(chanID int, channel, pair string) { b.WebsocketSubdChannels[chanID] = chanInfo if b.Verbose { - log.Debugf("%s Subscribed to Channel: %s Pair: %s ChannelID: %d\n", + log.Debugf(log.ExchangeSys, "%s Subscribed to Channel: %s Pair: %s ChannelID: %d\n", b.GetName(), channel, pair, @@ -163,13 +163,13 @@ func (b *Bitfinex) WsConnect() error { err = b.WsSendAuth() if err != nil { - log.Errorf("%v - authentication failed: %v", b.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", b.Name, err) } b.GenerateDefaultSubscriptions() if hs.Event == "info" { if b.Verbose { - log.Debugf("%s Connected to Websocket.\n", b.GetName()) + log.Debugf(log.ExchangeSys, "%s Connected to Websocket.\n", b.GetName()) } } @@ -224,7 +224,7 @@ func (b *Bitfinex) WsDataHandler() { eventData := result.(map[string]interface{}) event := eventData["event"] if b.Verbose { - log.Debugf("%v Received message. Type '%v' Message: %v", b.Name, event, eventData) + log.Debugf(log.ExchangeSys, "%v Received message. Type '%v' Message: %v", b.Name, event, eventData) } switch event { case "subscribed": diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index c1cb0e4c..e464154d 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -131,7 +131,8 @@ func (b *Bitfinex) Start(wg *sync.WaitGroup) { // Run implements the Bitfinex wrapper func (b *Bitfinex) Run() { if b.Verbose { - log.Debugf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled())) + log.Debugf(log.ExchangeSys, + "%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled())) b.PrintEnabledPairs() } @@ -141,7 +142,8 @@ func (b *Bitfinex) Run() { err := b.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, + "%s failed to update tradable pairs. Err: %s", b.Name, err) } } @@ -462,7 +464,7 @@ func (b *Bitfinex) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) orderSide := exchange.OrderSide(strings.ToUpper(resp[i].Side)) timestamp, err := strconv.ParseInt(resp[i].Timestamp, 10, 64) if err != nil { - log.Warnf("Unable to convert timestamp '%v', leaving blank", resp[i].Timestamp) + log.Warnf(log.ExchangeSys, "Unable to convert timestamp '%v', leaving blank", resp[i].Timestamp) } orderDate := time.Unix(timestamp, 0) @@ -521,7 +523,7 @@ func (b *Bitfinex) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) orderSide := exchange.OrderSide(strings.ToUpper(resp[i].Side)) timestamp, err := strconv.ParseInt(resp[i].Timestamp, 10, 64) if err != nil { - log.Warnf("Unable to convert timestamp '%v', leaving blank", resp[i].Timestamp) + log.Warnf(log.ExchangeSys, "Unable to convert timestamp '%v', leaving blank", resp[i].Timestamp) } orderDate := time.Unix(timestamp, 0) diff --git a/exchanges/bitflyer/bitflyer_test.go b/exchanges/bitflyer/bitflyer_test.go index fb669997..6fb47030 100644 --- a/exchanges/bitflyer/bitflyer_test.go +++ b/exchanges/bitflyer/bitflyer_test.go @@ -78,7 +78,7 @@ func TestGetAddressInfoCA(t *testing.T) { t.Error("test failed - Bitflyer - GetAddressInfoCA() error:", err) } if v.UnconfirmedBalance == 0 || v.ConfirmedBalance == 0 { - log.Warn("Donation wallet is empty :( - please consider donating") + log.Warn(log.ExchangeSys, "Donation wallet is empty :( - please consider donating") } } diff --git a/exchanges/bitflyer/bitflyer_wrapper.go b/exchanges/bitflyer/bitflyer_wrapper.go index 4f254ffc..73236a6c 100644 --- a/exchanges/bitflyer/bitflyer_wrapper.go +++ b/exchanges/bitflyer/bitflyer_wrapper.go @@ -122,7 +122,7 @@ func (b *Bitflyer) Run() { err := b.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index e84c4cd2..0620587a 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -121,7 +121,7 @@ func (b *Bithumb) Run() { err := b.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } diff --git a/exchanges/bitmex/bitmex_websocket.go b/exchanges/bitmex/bitmex_websocket.go index ea4df7f3..7e4938f5 100644 --- a/exchanges/bitmex/bitmex_websocket.go +++ b/exchanges/bitmex/bitmex_websocket.go @@ -101,7 +101,7 @@ func (b *Bitmex) WsConnector() error { } if b.Verbose { - log.Debugf("Successfully connected to Bitmex %s at time: %s Limit: %d", + log.Debugf(log.ExchangeSys, "Successfully connected to Bitmex %s at time: %s Limit: %d", welcomeResp.Info, welcomeResp.Timestamp, welcomeResp.Limit.Remaining) @@ -112,7 +112,7 @@ func (b *Bitmex) WsConnector() error { err = b.websocketSendAuth() if err != nil { - log.Errorf("%v - authentication failed: %v", b.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", b.Name, err) } b.GenerateAuthenticatedSubscriptions() return nil @@ -195,13 +195,13 @@ func (b *Bitmex) wsHandleIncomingData() { b.Websocket.DataHandler <- decodedResp if len(quickCapture) == 3 { if b.Verbose { - log.Debugf("%s websocket: Successfully subscribed to %s", + log.Debugf(log.ExchangeSys, "%s websocket: Successfully subscribed to %s", b.Name, decodedResp.Subscribe) } } else { b.Websocket.SetCanUseAuthenticatedEndpoints(true) if b.Verbose { - log.Debugf("%s websocket: Successfully authenticated websocket connection", + log.Debugf(log.ExchangeSys, "%s websocket: Successfully authenticated websocket connection", b.Name) } } @@ -561,7 +561,7 @@ func (b *Bitmex) wsSend(data interface{}) error { b.wsRequestMtx.Lock() defer b.wsRequestMtx.Unlock() if b.Verbose { - log.Debugf("%v sending message to websocket %v", b.Name, data) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", b.Name, data) } return b.WebsocketConn.WriteJSON(data) } diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 4e1daabe..dc74e474 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -153,7 +153,7 @@ func (b *Bitmex) Start(wg *sync.WaitGroup) { // Run implements the Bitmex wrapper func (b *Bitmex) Run() { if b.Verbose { - log.Debugf("%s Websocket: %s. (url: %s).\n", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()), b.API.Endpoints.WebsocketURL) + log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()), b.API.Endpoints.WebsocketURL) b.PrintEnabledPairs() } @@ -163,7 +163,7 @@ func (b *Bitmex) Run() { err := b.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } @@ -221,7 +221,7 @@ func (b *Bitmex) UpdateTradablePairs(forceUpdate bool) error { err = b.UpdatePairs(currency.NewPairsFromStrings(assetPairs), b.CurrencyPairs.AssetTypes[x], false, false) if err != nil { - log.Warnf("%s failed to update available pairs. Err: %v", b.Name, err) + log.Warnf(log.ExchangeSys, "%s failed to update available pairs. Err: %v", b.Name, err) } assetPairs = nil } diff --git a/exchanges/bitstamp/bitstamp.go b/exchanges/bitstamp/bitstamp.go index 6787ff52..d5d6c437 100644 --- a/exchanges/bitstamp/bitstamp.go +++ b/exchanges/bitstamp/bitstamp.go @@ -192,12 +192,12 @@ func (b *Bitstamp) GetOrderbook(currency string) (Orderbook, error) { for _, x := range resp.Bids { price, err := strconv.ParseFloat(x[0], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } amount, err := strconv.ParseFloat(x[1], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } orderbook.Bids = append(orderbook.Bids, OrderbookBase{price, amount}) @@ -206,12 +206,12 @@ func (b *Bitstamp) GetOrderbook(currency string) (Orderbook, error) { for _, x := range resp.Asks { price, err := strconv.ParseFloat(x[0], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } amount, err := strconv.ParseFloat(x[1], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } orderbook.Asks = append(orderbook.Asks, OrderbookBase{price, amount}) @@ -598,7 +598,7 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url } if b.Verbose { - log.Debugf("Sending POST request to " + path) + log.Debugf(log.ExchangeSys, "Sending POST request to "+path) } headers := make(map[string]string) diff --git a/exchanges/bitstamp/bitstamp_websocket.go b/exchanges/bitstamp/bitstamp_websocket.go index 7d97743b..f6cde5a4 100644 --- a/exchanges/bitstamp/bitstamp_websocket.go +++ b/exchanges/bitstamp/bitstamp_websocket.go @@ -46,7 +46,7 @@ func (b *Bitstamp) WsConnect() error { } if b.Verbose { - log.Debugf("%s Connected to Websocket.\n", b.GetName()) + log.Debugf(log.ExchangeSys, "%s Connected to Websocket.\n", b.GetName()) } err = b.seedOrderBook() @@ -69,7 +69,7 @@ func (b *Bitstamp) WsReadData() (exchange.WebsocketResponse, error) { } if b.Verbose { - log.Debugf("%s websocket raw response: %s", b.GetName(), resp) + log.Debugf(log.ExchangeSys, "%s websocket raw response: %s", b.GetName(), resp) } b.Websocket.TrafficAlert <- struct{}{} @@ -106,7 +106,7 @@ func (b *Bitstamp) WsHandleData() { switch wsResponse.Event { case "bts:request_reconnect": if b.Verbose { - log.Debugf("%v - Websocket reconnection request received", b.GetName()) + log.Debugf(log.ExchangeSys, "%v - Websocket reconnection request received", b.GetName()) } go b.Websocket.WebsocketReset() diff --git a/exchanges/bitstamp/bitstamp_wrapper.go b/exchanges/bitstamp/bitstamp_wrapper.go index 686e778e..6ad69992 100644 --- a/exchanges/bitstamp/bitstamp_wrapper.go +++ b/exchanges/bitstamp/bitstamp_wrapper.go @@ -129,7 +129,7 @@ func (b *Bitstamp) Start(wg *sync.WaitGroup) { // Run implements the Bitstamp wrapper func (b *Bitstamp) Run() { if b.Verbose { - log.Debugf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled())) + log.Debugf(log.ExchangeSys, "%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled())) b.PrintEnabledPairs() } @@ -139,7 +139,7 @@ func (b *Bitstamp) Run() { err := b.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } @@ -489,7 +489,7 @@ func (b *Bitstamp) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) case order.XRP > 0: baseCurrency = currency.XRP default: - log.Warnf("no base currency found for OrderID '%v'", order.OrderID) + log.Warnf(log.ExchangeSys, "no base currency found for OrderID '%v'", order.OrderID) } switch { @@ -498,7 +498,7 @@ func (b *Bitstamp) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) case order.EUR > 0: quoteCurrency = currency.EUR default: - log.Warnf("no quote currency found for orderID '%v'", order.OrderID) + log.Warnf(log.ExchangeSys, "no quote currency found for orderID '%v'", order.OrderID) } var currPair currency.Pair diff --git a/exchanges/bittrex/bittrex_wrapper.go b/exchanges/bittrex/bittrex_wrapper.go index 579fa626..47b375d1 100644 --- a/exchanges/bittrex/bittrex_wrapper.go +++ b/exchanges/bittrex/bittrex_wrapper.go @@ -119,11 +119,11 @@ func (b *Bittrex) Run() { !common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), "-") { forceUpdate = true enabledPairs := []string{"USDT-BTC"} - log.Warn("WARNING: Available pairs for Bittrex reset due to config upgrade, please enable the ones you would like again") + log.Warn(log.ExchangeSys, "Available pairs for Bittrex reset due to config upgrade, please enable the ones you would like again") err := b.UpdatePairs(currency.NewPairsFromStrings(enabledPairs), asset.Spot, true, true) if err != nil { - log.Errorf("%s failed to update currencies. Err: %s\n", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err: %s\n", b.Name, err) } } @@ -133,7 +133,7 @@ func (b *Bittrex) Run() { err := b.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } @@ -424,7 +424,7 @@ func (b *Bittrex) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ( for i := range resp.Result { orderDate, err := time.Parse(time.RFC3339, resp.Result[i].Opened) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", b.Name, "GetActiveOrders", resp.Result[i].OrderUUID, resp.Result[i].Opened) } @@ -468,7 +468,7 @@ func (b *Bittrex) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ( for i := range resp.Result { orderDate, err := time.Parse(time.RFC3339, resp.Result[i].TimeStamp) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", b.Name, "GetActiveOrders", resp.Result[i].OrderUUID, resp.Result[i].Opened) } diff --git a/exchanges/btcmarkets/btcmarkets.go b/exchanges/btcmarkets/btcmarkets.go index 84fa534a..cd196840 100644 --- a/exchanges/btcmarkets/btcmarkets.go +++ b/exchanges/btcmarkets/btcmarkets.go @@ -393,7 +393,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result []byte(req), []byte(b.API.Credentials.Secret)) if b.Verbose { - log.Debugf("Sending %s request to URL %s with params %s\n", + log.Debugf(log.ExchangeSys, "Sending %s request to URL %s with params %s\n", reqType, b.API.Endpoints.URL+path, req) diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index ab76f7ba..65abbea8 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -118,12 +118,12 @@ func (b *BTCMarkets) Run() { if !common.StringDataContains(b.GetEnabledPairs(asset.Spot).Strings(), "-") || !common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), "-") { enabledPairs := []string{"BTC-AUD"} - log.Println("WARNING: Available pairs for BTC Makrets reset due to config upgrade, please enable the pairs you would like again.") + log.Warnln(log.ExchangeSys, "Available pairs for BTC Markets reset due to config upgrade, please enable the pairs you would like again.") forceUpdate = true err := b.UpdatePairs(currency.NewPairsFromStrings(enabledPairs), asset.Spot, true, true) if err != nil { - log.Errorf("%s failed to update currencies. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err: %s", b.Name, err) } } @@ -133,7 +133,7 @@ func (b *BTCMarkets) Run() { err := b.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } diff --git a/exchanges/btse/btse.go b/exchanges/btse/btse.go index 78f0fc4d..ca5fd25b 100644 --- a/exchanges/btse/btse.go +++ b/exchanges/btse/btse.go @@ -203,7 +203,7 @@ func (b *BTSE) SendAuthenticatedHTTPRequest(method, endpoint string, req map[str p := fmt.Sprintf("%s/%s", b.API.Endpoints.URL, endpoint) if b.Verbose { - log.Debugf("Sending %s request to URL %s with params %s\n", method, p, string(payload)) + log.Debugf(log.ExchangeSys, "Sending %s request to URL %s with params %s\n", method, p, string(payload)) } return b.SendPayload(method, p, headers, strings.NewReader(string(payload)), &result, true, false, b.Verbose, b.HTTPDebugging) diff --git a/exchanges/btse/btse_websocket.go b/exchanges/btse/btse_websocket.go index 66c44252..6193aa09 100644 --- a/exchanges/btse/btse_websocket.go +++ b/exchanges/btse/btse_websocket.go @@ -93,7 +93,7 @@ func (b *BTSE) WsHandleData() { if strings.Contains(string(resp.Raw), "Welcome to BTSE") { if b.Verbose { - log.Debugf("%s websocket client successfully connected to %s", + log.Debugf(log.ExchangeSys, "%s websocket client successfully connected to %s", b.Name, b.Websocket.GetWebsocketURL()) } continue @@ -252,7 +252,7 @@ func (b *BTSE) wsSend(data interface{}) error { b.wsRequestMtx.Lock() defer b.wsRequestMtx.Unlock() if b.Verbose { - log.Debugf("%v sending message to websocket %v", b.Name, data) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", b.Name, data) } json, err := common.JSONEncode(data) if err != nil { diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 081740b5..cb4750b4 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -135,7 +135,7 @@ func (b *BTSE) Run() { err := b.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", b.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", b.Name, err) } } @@ -445,7 +445,7 @@ func (b *BTSE) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]e fills, err := b.GetFills(order.ID, "", "", "", "") if err != nil { - log.Errorf("unable to get order fills for orderID %s", order.ID) + log.Errorf(log.ExchangeSys, "unable to get order fills for orderID %s", order.ID) continue } diff --git a/exchanges/coinbasepro/coinbasepro.go b/exchanges/coinbasepro/coinbasepro.go index 569a4646..5cbb9ec1 100644 --- a/exchanges/coinbasepro/coinbasepro.go +++ b/exchanges/coinbasepro/coinbasepro.go @@ -731,7 +731,7 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m } if c.Verbose { - log.Debugf("Request JSON: %s\n", payload) + log.Debugf(log.ExchangeSys, "Request JSON: %s\n", payload) } } diff --git a/exchanges/coinbasepro/coinbasepro_websocket.go b/exchanges/coinbasepro/coinbasepro_websocket.go index 212311fc..511ad307 100644 --- a/exchanges/coinbasepro/coinbasepro_websocket.go +++ b/exchanges/coinbasepro/coinbasepro_websocket.go @@ -354,7 +354,7 @@ func (c *CoinbasePro) wsSend(data interface{}) error { c.wsRequestMtx.Lock() defer c.wsRequestMtx.Unlock() if c.Verbose { - log.Debugf("%v sending message to websocket %v", c.Name, data) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", c.Name, data) } json, err := common.JSONEncode(data) if err != nil { diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index 893ab333..88c2a91d 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -130,7 +130,7 @@ func (c *CoinbasePro) Start(wg *sync.WaitGroup) { // Run implements the coinbasepro wrapper func (c *CoinbasePro) Run() { if c.Verbose { - log.Debugf("%s Websocket: %s. (url: %s).\n", c.GetName(), common.IsEnabled(c.Websocket.IsEnabled()), coinbaseproWebsocketURL) + log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", c.GetName(), common.IsEnabled(c.Websocket.IsEnabled()), coinbaseproWebsocketURL) c.PrintEnabledPairs() } @@ -140,7 +140,7 @@ func (c *CoinbasePro) Run() { err := c.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", c.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", c.Name, err) } } @@ -434,7 +434,7 @@ func (c *CoinbasePro) GetActiveOrders(getOrdersRequest *exchange.GetOrdersReques orderType := exchange.OrderType(strings.ToUpper(respOrders[i].Type)) orderDate, err := time.Parse(time.RFC3339, respOrders[i].CreatedAt) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", c.Name, "GetActiveOrders", respOrders[i].ID, respOrders[i].CreatedAt) } @@ -477,7 +477,7 @@ func (c *CoinbasePro) GetOrderHistory(getOrdersRequest *exchange.GetOrdersReques orderType := exchange.OrderType(strings.ToUpper(respOrders[i].Type)) orderDate, err := time.Parse(time.RFC3339, respOrders[i].CreatedAt) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", c.Name, "GetActiveOrders", respOrders[i].ID, respOrders[i].CreatedAt) } diff --git a/exchanges/coinut/coinut.go b/exchanges/coinut/coinut.go index 28f646d3..dc8741f1 100644 --- a/exchanges/coinut/coinut.go +++ b/exchanges/coinut/coinut.go @@ -276,7 +276,7 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{ } if c.Verbose { - log.Debugf("Request JSON: %s", payload) + log.Debugf(log.ExchangeSys, "Request JSON: %s", payload) } headers := make(map[string]string) diff --git a/exchanges/coinut/coinut_websocket.go b/exchanges/coinut/coinut_websocket.go index 44b8f4d4..ce09a3b8 100644 --- a/exchanges/coinut/coinut_websocket.go +++ b/exchanges/coinut/coinut_websocket.go @@ -459,7 +459,7 @@ func (c *COINUT) wsSend(data interface{}) error { return err } if c.Verbose { - log.Debugf("%v sending message to websocket %v", c.Name, string(json)) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", c.Name, string(json)) } // Basic rate limiter time.Sleep(coinutWebsocketRateLimit) diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index cf971dc8..cf650a04 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -128,7 +128,7 @@ func (c *COINUT) Start(wg *sync.WaitGroup) { // Run implements the COINUT wrapper func (c *COINUT) Run() { if c.Verbose { - log.Debugf("%s Websocket: %s. (url: %s).\n", c.GetName(), common.IsEnabled(c.Websocket.IsEnabled()), coinutWebsocketURL) + log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", c.GetName(), common.IsEnabled(c.Websocket.IsEnabled()), coinutWebsocketURL) c.PrintEnabledPairs() } @@ -138,7 +138,7 @@ func (c *COINUT) Run() { err := c.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", c.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", c.Name, err) } } diff --git a/exchanges/exchange.go b/exchanges/exchange.go index f050beb3..3cb31f64 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -395,7 +395,7 @@ func (e *Base) SetAPIKeys(apiKey, apiSecret, clientID string) { if err != nil { e.API.AuthenticatedSupport = false e.API.AuthenticatedWebsocketSupport = false - log.Warnf(warningBase64DecryptSecretKeyFailed, e.Name) + log.Warnf(log.ExchangeSys, warningBase64DecryptSecretKeyFailed, e.Name) } e.API.Credentials.Secret = string(result) } else { @@ -482,7 +482,8 @@ func (e *Base) ValidateAPICredentials() bool { if e.API.CredentialsValidator.RequiresKey { if e.API.Credentials.Key == "" || e.API.Credentials.Key == config.DefaultAPIKey { - log.Warnf("exchange %s requires API key but default/empty one set", + log.Warnf(log.ExchangeSys, + "exchange %s requires API key but default/empty one set", e.Name) return false } @@ -491,7 +492,8 @@ func (e *Base) ValidateAPICredentials() bool { if e.API.CredentialsValidator.RequiresSecret { if e.API.Credentials.Secret == "" || e.API.Credentials.Secret == config.DefaultAPISecret { - log.Warnf("exchange %s requires API secret but default/empty one set", + log.Warnf(log.ExchangeSys, + "exchange %s requires API secret but default/empty one set", e.Name) return false } @@ -500,7 +502,8 @@ func (e *Base) ValidateAPICredentials() bool { if e.API.CredentialsValidator.RequiresPEM { if e.API.Credentials.PEMKey == "" || strings.Contains(e.API.Credentials.PEMKey, "JUSTADUMMY") { - log.Warnf("exchange %s requires API PEM key but default/empty one set", + log.Warnf(log.ExchangeSys, + "exchange %s requires API PEM key but default/empty one set", e.Name) return false } @@ -509,7 +512,8 @@ func (e *Base) ValidateAPICredentials() bool { if e.API.CredentialsValidator.RequiresClientID { if e.API.Credentials.ClientID == "" || e.API.Credentials.ClientID == config.DefaultAPIClientID { - log.Warnf("exchange %s requires API ClientID but default/empty one set", + log.Warnf(log.ExchangeSys, + "exchange %s requires API ClientID but default/empty one set", e.Name) return false } @@ -518,7 +522,8 @@ func (e *Base) ValidateAPICredentials() bool { if e.API.CredentialsValidator.RequiresBase64DecodeSecret && !e.LoadedByConfig { _, err := crypto.Base64Decode(e.API.Credentials.Secret) if err != nil { - log.Warnf("exchange %s API secret base64 decode failed: %s", + log.Warnf(log.ExchangeSys, + "exchange %s API secret base64 decode failed: %s", e.Name, err) return false } @@ -575,15 +580,18 @@ func (e *Base) UpdatePairs(exchangeProducts currency.Pairs, assetType asset.Item if force || len(newPairs) > 0 || len(removedPairs) > 0 { if force { - log.Debugf("%s forced update of %s [%v] pairs.", e.Name, updateType, + log.Debugf(log.ExchangeSys, + "%s forced update of %s [%v] pairs.", e.Name, updateType, strings.ToUpper(assetType.String())) } else { if len(newPairs) > 0 { - log.Debugf("%s Updating pairs [%v] - New: %s.\n", e.Name, + log.Debugf(log.ExchangeSys, + "%s Updating pairs [%v] - New: %s.\n", e.Name, strings.ToUpper(assetType.String()), newPairs) } if len(removedPairs) > 0 { - log.Debugf("%s Updating pairs [%v] - Removed: %s.\n", e.Name, + log.Debugf(log.ExchangeSys, + "%s Updating pairs [%v] - Removed: %s.\n", e.Name, strings.ToUpper(assetType.String()), removedPairs) } } @@ -725,7 +733,7 @@ func (e *Base) IsAssetTypeSupported(asset asset.Item) bool { // PrintEnabledPairs prints the exchanges enabled asset pairs func (e *Base) PrintEnabledPairs() { for k, v := range e.CurrencyPairs.Pairs { - log.Infof("%s Asset type %v:\n\t Enabled pairs: %v", + log.Infof(log.ExchangeSys, "%s Asset type %v:\n\t Enabled pairs: %v", e.Name, strings.ToUpper(k.String()), v.Enabled) } } diff --git a/exchanges/exmo/exmo.go b/exchanges/exmo/exmo.go index de89512b..81002d26 100644 --- a/exchanges/exmo/exmo.go +++ b/exchanges/exmo/exmo.go @@ -321,7 +321,7 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va []byte(e.API.Credentials.Secret)) if e.Verbose { - log.Debugf("Sending %s request to %s with params %s\n", + log.Debugf(log.ExchangeSys, "Sending %s request to %s with params %s\n", method, endpoint, payload) diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index d8731a2e..120a679a 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -122,7 +122,7 @@ func (e *EXMO) Run() { err := e.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", e.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", e.Name, err) } } diff --git a/exchanges/gateio/gateio_websocket.go b/exchanges/gateio/gateio_websocket.go index 48d25700..665a2b26 100644 --- a/exchanges/gateio/gateio_websocket.go +++ b/exchanges/gateio/gateio_websocket.go @@ -52,7 +52,7 @@ func (g *Gateio) WsConnect() error { err = g.wsServerSignIn() if err != nil { - log.Errorf("%v - authentication failed: %v", g.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", g.Name, err) } g.GenerateAuthenticatedSubscriptions() g.GenerateDefaultSubscriptions() @@ -456,7 +456,7 @@ func (g *Gateio) wsSend(data interface{}) error { g.wsRequestMtx.Lock() defer g.wsRequestMtx.Unlock() if g.Verbose { - log.Debugf("%v sending message to websocket %v", g.Name, data) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", g.Name, data) } // Basic rate limiter time.Sleep(gateioWebsocketRateLimit) diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index ae9940f7..afe171c8 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -142,7 +142,7 @@ func (g *Gateio) Run() { err := g.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", g.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", g.Name, err) } } diff --git a/exchanges/gemini/gemini.go b/exchanges/gemini/gemini.go index 423124ba..7800fb47 100644 --- a/exchanges/gemini/gemini.go +++ b/exchanges/gemini/gemini.go @@ -433,7 +433,7 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st } if g.Verbose { - log.Debugf("Request JSON: %s", PayloadJSON) + log.Debugf(log.ExchangeSys, "Request JSON: %s", PayloadJSON) } PayloadBase64 := crypto.Base64Encode(PayloadJSON) diff --git a/exchanges/gemini/gemini_websocket.go b/exchanges/gemini/gemini_websocket.go index 661e1ef4..c545f839 100644 --- a/exchanges/gemini/gemini_websocket.go +++ b/exchanges/gemini/gemini_websocket.go @@ -48,7 +48,7 @@ func (g *Gemini) WsConnect() error { go g.WsHandleData() err := g.WsSecureSubscribe(&dialer, geminiWsOrderEvents) if err != nil { - log.Errorf("%v - authentication failed: %v", g.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", g.Name, err) } return g.WsSubscribe(&dialer) } diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index 05ff5f9c..1bd4366c 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -140,7 +140,7 @@ func (g *Gemini) Run() { err := g.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", g.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", g.Name, err) } } diff --git a/exchanges/hitbtc/hitbtc_websocket.go b/exchanges/hitbtc/hitbtc_websocket.go index d4e4590a..4fca1fe2 100644 --- a/exchanges/hitbtc/hitbtc_websocket.go +++ b/exchanges/hitbtc/hitbtc_websocket.go @@ -52,7 +52,7 @@ func (h *HitBTC) WsConnect() error { go h.WsHandleData() err = h.wsLogin() if err != nil { - log.Errorf("%v - authentication failed: %v", h.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", h.Name, err) } h.GenerateDefaultSubscriptions() @@ -391,7 +391,7 @@ func (h *HitBTC) wsSend(data interface{}) error { return err } if h.Verbose { - log.Debugf("%v sending message to websocket %v", h.Name, string(json)) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", h.Name, string(json)) } return h.WebsocketConn.WriteMessage(websocket.TextMessage, json) } diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index 0cbf9af8..e7355350 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -127,7 +127,7 @@ func (h *HitBTC) Start(wg *sync.WaitGroup) { // Run implements the HitBTC wrapper func (h *HitBTC) Run() { if h.Verbose { - log.Debugf("%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket.IsEnabled()), hitbtcWebsocketAddress) + log.Debugf(log.ExchangeSys, "%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket.IsEnabled()), hitbtcWebsocketAddress) h.PrintEnabledPairs() } @@ -135,12 +135,12 @@ func (h *HitBTC) Run() { if !common.StringDataContains(h.GetEnabledPairs(asset.Spot).Strings(), "-") || !common.StringDataContains(h.GetAvailablePairs(asset.Spot).Strings(), "-") { enabledPairs := []string{"BTC-USD"} - log.Warn("WARNING: Available pairs for HitBTC reset due to config upgrade, please enable the ones you would like again.") + log.Warn(log.ExchangeSys, "Available pairs for HitBTC reset due to config upgrade, please enable the ones you would like again.") forceUpdate = true err := h.UpdatePairs(currency.NewPairsFromStrings(enabledPairs), asset.Spot, true, true) if err != nil { - log.Errorf("%s failed to update enabled currencies.\n", h.GetName()) + log.Errorf(log.ExchangeSys, "%s failed to update enabled currencies.\n", h.GetName()) } } @@ -150,7 +150,7 @@ func (h *HitBTC) Run() { err := h.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", h.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", h.Name, err) } } diff --git a/exchanges/huobi/huobi_websocket.go b/exchanges/huobi/huobi_websocket.go index 702bdf44..4eff4899 100644 --- a/exchanges/huobi/huobi_websocket.go +++ b/exchanges/huobi/huobi_websocket.go @@ -72,11 +72,11 @@ func (h *HUOBI) WsConnect() error { } err = h.wsAuthenticatedDial(&dialer) if err != nil { - log.Errorf("%v - authenticated dial failed: %v", h.Name, err) + log.Errorf(log.ExchangeSys, "%v - authenticated dial failed: %v\n", h.Name, err) } err = h.wsLogin() if err != nil { - log.Errorf("%v - authentication failed: %v", h.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", h.Name, err) } go h.WsHandleData() @@ -156,7 +156,7 @@ func (h *HUOBI) WsHandleData() { return case resp := <-comms: if h.Verbose { - log.Debugf("%v: %v: %v", h.Name, resp.URL, string(resp.Raw)) + log.Debugf(log.ExchangeSys, "%v: %v: %v", h.Name, resp.URL, string(resp.Raw)) } switch resp.URL { case wsMarketURL: @@ -189,14 +189,14 @@ func (h *HUOBI) wsHandleAuthenticatedData(resp WsMessage) { if init.Ping != 0 { err = h.WebsocketConn.WriteJSON(`{"pong":1337}`) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) } return } if init.Op == "sub" { if h.Verbose { - log.Debugf("%v: %v: Successfully subscribed to %v", h.Name, resp.URL, init.Topic) + log.Debugf(log.ExchangeSys, "%v: %v: Successfully subscribed to %v", h.Name, resp.URL, init.Topic) } return } @@ -277,7 +277,7 @@ func (h *HUOBI) wsHandleMarketData(resp WsMessage) { if init.Ping != 0 { err = h.WebsocketConn.WriteJSON(`{"pong":1337}`) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) } return } @@ -420,7 +420,7 @@ func (h *HUOBI) wsSend(data []byte) error { h.wsRequestMtx.Lock() defer h.wsRequestMtx.Unlock() if h.Verbose { - log.Debugf("%v sending message to websocket %s", h.Name, string(data)) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %s", h.Name, string(data)) } return h.WebsocketConn.WriteMessage(websocket.TextMessage, data) } @@ -456,7 +456,7 @@ func (h *HUOBI) wsAuthenticatedSend(request interface{}) error { return err } if h.Verbose { - log.Debugf("%v sending Authenticated message to websocket %s", h.Name, string(encodedRequest)) + log.Debugf(log.ExchangeSys, "%v sending Authenticated message to websocket %s", h.Name, string(encodedRequest)) } return h.AuthenticatedWebsocketConn.WriteMessage(websocket.TextMessage, encodedRequest) } diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 571b2b9f..4a25341d 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -134,7 +134,7 @@ func (h *HUOBI) Start(wg *sync.WaitGroup) { // Run implements the HUOBI wrapper func (h *HUOBI) Run() { if h.Verbose { - log.Debugf("%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket.IsEnabled()), wsMarketURL) + log.Debugf(log.ExchangeSys, "%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket.IsEnabled()), wsMarketURL) h.PrintEnabledPairs() } @@ -148,7 +148,7 @@ func (h *HUOBI) Run() { cfg := config.GetConfig() exchCfg, err := cfg.GetExchangeConfig(h.Name) if err != nil { - log.Errorf("%s failed to get exchange config. %s\n", h.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to get exchange config. %s\n", h.Name, err) return } exchCfg.BaseCurrencies = currency.Currencies{currency.USD} @@ -162,11 +162,11 @@ func (h *HUOBI) Run() { Delimiter: "-", }, } - log.Warn("WARNING: Available and enabled pairs for Huobi reset due to config upgrade, please enable the ones you would like again") + log.Warn(log.ExchangeSys, "Available and enabled pairs for Huobi reset due to config upgrade, please enable the ones you would like again") err := h.UpdatePairs(enabledPairs, asset.Spot, true, true) if err != nil { - log.Errorf("%s Failed to update enabled currencies.\n", h.GetName()) + log.Errorf(log.ExchangeSys, "%s Failed to update enabled currencies.\n", h.GetName()) } } @@ -176,7 +176,7 @@ func (h *HUOBI) Run() { err := h.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", h.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", h.Name, err) } } diff --git a/exchanges/huobihadax/huobihadax.go b/exchanges/huobihadax/huobihadax.go index 23f5a7bf..835b0070 100644 --- a/exchanges/huobihadax/huobihadax.go +++ b/exchanges/huobihadax/huobihadax.go @@ -17,6 +17,7 @@ import ( "github.com/thrasher-/gocryptotrader/common/crypto" "github.com/thrasher-/gocryptotrader/currency" exchange "github.com/thrasher-/gocryptotrader/exchanges" + log "github.com/thrasher-/gocryptotrader/logger" ) const ( @@ -330,7 +331,7 @@ func (h *HUOBIHADAX) SpotNewOrder(arg SpotNewOrderRequestParams) (int64, error) bytesParams, _ := json.Marshal(vals) postBodyParams := string(bytesParams) if h.Verbose { - fmt.Println("Post params:", postBodyParams) + log.Debugf(log.ExchangeSys, "Post params: %v", postBodyParams) } var result response diff --git a/exchanges/huobihadax/huobihadax_test.go b/exchanges/huobihadax/huobihadax_test.go index b2990155..ae3294d4 100644 --- a/exchanges/huobihadax/huobihadax_test.go +++ b/exchanges/huobihadax/huobihadax_test.go @@ -1,7 +1,6 @@ package huobihadax import ( - "fmt" "strconv" "testing" "time" @@ -276,7 +275,7 @@ func TestSpotNewOrder(t *testing.T) { if err != nil { t.Errorf("Test failed - Huobi SpotNewOrder: %s", err) } else { - fmt.Println(newOrderID) + t.Log(newOrderID) } } diff --git a/exchanges/huobihadax/huobihadax_websocket.go b/exchanges/huobihadax/huobihadax_websocket.go index 2747a081..004a48da 100644 --- a/exchanges/huobihadax/huobihadax_websocket.go +++ b/exchanges/huobihadax/huobihadax_websocket.go @@ -72,11 +72,11 @@ func (h *HUOBIHADAX) WsConnect() error { } err = h.wsAuthenticatedDial(&dialer) if err != nil { - log.Errorf("%v - authenticated dial failed: %v", h.Name, err) + log.Errorf(log.ExchangeSys, "%v - authenticated dial failed: %v\n", h.Name, err) } err = h.wsLogin() if err != nil { - log.Errorf("%v - authentication failed: %v", h.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", h.Name, err) } go h.WsHandleData() @@ -156,7 +156,7 @@ func (h *HUOBIHADAX) WsHandleData() { return case resp := <-comms: if h.Verbose { - log.Debugf("%v: %v: %v", h.Name, resp.URL, string(resp.Raw)) + log.Debugf(log.ExchangeSys, "%v: %v: %v", h.Name, resp.URL, string(resp.Raw)) } switch resp.URL { case HuobiHadaxSocketIOAddress: @@ -189,14 +189,14 @@ func (h *HUOBIHADAX) wsHandleAuthenticatedData(resp WsMessage) { if init.Ping != 0 { err = h.WebsocketConn.WriteJSON(`{"pong":1337}`) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) } return } if init.Op == "sub" { if h.Verbose { - log.Debugf("%v: %v: Successfully subscribed to %v", h.Name, resp.URL, init.Topic) + log.Debugf(log.ExchangeSys, "%v: %v: Successfully subscribed to %v", h.Name, resp.URL, init.Topic) } return } @@ -277,7 +277,7 @@ func (h *HUOBIHADAX) wsHandleMarketData(resp WsMessage) { if init.Ping != 0 { err = h.WebsocketConn.WriteJSON(`{"pong":1337}`) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) } return } @@ -420,7 +420,7 @@ func (h *HUOBIHADAX) wsSend(data []byte) error { h.wsRequestMtx.Lock() defer h.wsRequestMtx.Unlock() if h.Verbose { - log.Debugf("%v sending message to websocket %s", h.Name, string(data)) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %s", h.Name, string(data)) } return h.WebsocketConn.WriteMessage(websocket.TextMessage, data) } @@ -456,7 +456,7 @@ func (h *HUOBIHADAX) wsAuthenticatedSend(request interface{}) error { return err } if h.Verbose { - log.Debugf("%v sending Authenticated message to websocket %s", h.Name, string(encodedRequest)) + log.Debugf(log.ExchangeSys, "%v sending Authenticated message to websocket %s", h.Name, string(encodedRequest)) } return h.AuthenticatedWebsocketConn.WriteMessage(websocket.TextMessage, encodedRequest) } diff --git a/exchanges/huobihadax/huobihadax_wrapper.go b/exchanges/huobihadax/huobihadax_wrapper.go index d39637c3..77e9529e 100644 --- a/exchanges/huobihadax/huobihadax_wrapper.go +++ b/exchanges/huobihadax/huobihadax_wrapper.go @@ -139,7 +139,7 @@ func (h *HUOBIHADAX) Run() { err := h.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", h.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", h.Name, err) } } diff --git a/exchanges/itbit/itbit.go b/exchanges/itbit/itbit.go index a0a5d707..7d4258f8 100644 --- a/exchanges/itbit/itbit.go +++ b/exchanges/itbit/itbit.go @@ -302,7 +302,7 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method, path string, params map[str } if i.Verbose { - log.Debugf("Request JSON: %s\n", PayloadJSON) + log.Debugf(log.ExchangeSys, "Request JSON: %s\n", PayloadJSON) } } diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index d59f5dac..a033256f 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -424,7 +424,7 @@ func (i *ItBit) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([] side := exchange.OrderSide(strings.ToUpper(allOrders[j].Side)) orderDate, err := time.Parse(time.RFC3339, allOrders[j].CreatedTime) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", i.Name, "GetActiveOrders", allOrders[j].ID, allOrders[j].CreatedTime) } @@ -475,7 +475,7 @@ func (i *ItBit) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([] side := exchange.OrderSide(strings.ToUpper(allOrders[j].Side)) orderDate, err := time.Parse(time.RFC3339, allOrders[j].CreatedTime) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", i.Name, "GetActiveOrders", allOrders[j].ID, allOrders[j].CreatedTime) } diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index 153ec417..854062ef 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -835,7 +835,7 @@ func GetError(apiErrors []string) error { for _, e := range apiErrors { switch e[0] { case 'W': - log.Warnf("%s API warning: %v\n", exchangeName, e[1:]) + log.Warnf(log.ExchangeSys, "%s API warning: %v\n", exchangeName, e[1:]) default: return fmt.Errorf("%s API error: %v", exchangeName, e[1:]) } @@ -865,7 +865,7 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values, append([]byte(path), shasum...), []byte(k.API.Credentials.Secret))) if k.Verbose { - log.Debugf("Sending POST request to %s, path: %s, params: %s", + log.Debugf(log.ExchangeSys, "Sending POST request to %s, path: %s, params: %s", k.API.Endpoints.URL, path, encoded) diff --git a/exchanges/kraken/kraken_websocket.go b/exchanges/kraken/kraken_websocket.go index 662306ea..7dc4dbda 100644 --- a/exchanges/kraken/kraken_websocket.go +++ b/exchanges/kraken/kraken_websocket.go @@ -72,7 +72,7 @@ func (k *Kraken) writeToWebsocket(message []byte) error { k.wsRequestMtx.Lock() defer k.wsRequestMtx.Unlock() if k.Verbose { - log.Debugf("Sending message to WS: %v", + log.Debugf(log.ExchangeSys, "Sending message to WS: %v", string(message)) } // Really basic WS rate limit @@ -98,7 +98,7 @@ func (k *Kraken) WsConnect() error { var err error if k.Verbose { - log.Debugf("Attempting to connect to %v", + log.Debugf(log.ExchangeSys, "Attempting to connect to %v", k.Websocket.GetWebsocketURL()) } k.WebsocketConn, _, err = dialer.Dial(k.Websocket.GetWebsocketURL(), @@ -109,7 +109,7 @@ func (k *Kraken) WsConnect() error { err) } if k.Verbose { - log.Debugf("Successful connection to %v", + log.Debugf(log.ExchangeSys, "Successful connection to %v", k.Websocket.GetWebsocketURL()) } go k.WsHandleData() @@ -142,7 +142,7 @@ func (k *Kraken) WsReadData() (exchange.WebsocketResponse, error) { } } if k.Verbose { - log.Debugf("%v Websocket message received: %v", + log.Debugf(log.ExchangeSys, "%v Websocket message received: %v", k.Name, string(standardMessage)) } @@ -165,7 +165,7 @@ func (k *Kraken) wsPingHandler() { case <-ticker.C: pingEvent := fmt.Sprintf("{\"event\":\"%v\"}", krakenWsPing) if k.Verbose { - log.Debugf("%v sending ping", + log.Debugf(log.ExchangeSys, "%v sending ping", k.GetName()) } err := k.writeToWebsocket([]byte(pingEvent)) @@ -221,36 +221,36 @@ func (k *Kraken) WsHandleDataResponse(response WebsocketDataResponse) { switch channelData.Subscription { case krakenWsTicker: if k.Verbose { - log.Debugf("%v Websocket ticker data received", + log.Debugf(log.ExchangeSys, "%v Websocket ticker data received", k.GetName()) } k.wsProcessTickers(&channelData, response[1]) case krakenWsOHLC: if k.Verbose { - log.Debugf("%v Websocket OHLC data received", + log.Debugf(log.ExchangeSys, "%v Websocket OHLC data received", k.GetName()) } k.wsProcessCandles(&channelData, response[1]) case krakenWsOrderbook: if k.Verbose { - log.Debugf("%v Websocket Orderbook data received", + log.Debugf(log.ExchangeSys, "%v Websocket Orderbook data received", k.GetName()) } k.wsProcessOrderBook(&channelData, response[1]) case krakenWsSpread: if k.Verbose { - log.Debugf("%v Websocket Spread data received", + log.Debugf(log.ExchangeSys, "%v Websocket Spread data received", k.GetName()) } k.wsProcessSpread(&channelData, response[1]) case krakenWsTrade: if k.Verbose { - log.Debugf("%v Websocket Trade data received", + log.Debugf(log.ExchangeSys, "%v Websocket Trade data received", k.GetName()) } k.wsProcessTrades(&channelData, response[1]) default: - log.Errorf("%v Unidentified websocket data received: %v", + log.Errorf(log.ExchangeSys, "%v Unidentified websocket data received: %v", k.GetName(), response) } } @@ -260,17 +260,17 @@ func (k *Kraken) WsHandleEventResponse(response *WebsocketEventResponse) { switch response.Event { case krakenWsHeartbeat: if k.Verbose { - log.Debugf("%v Websocket heartbeat data received", + log.Debugf(log.ExchangeSys, "%v Websocket heartbeat data received", k.GetName()) } case krakenWsPong: if k.Verbose { - log.Debugf("%v Websocket pong data received", + log.Debugf(log.ExchangeSys, "%v Websocket pong data received", k.GetName()) } case krakenWsSystemStatus: if k.Verbose { - log.Debugf("%v Websocket status data received", + log.Debugf(log.ExchangeSys, "%v Websocket status data received", k.GetName()) } if response.Status != "online" { @@ -278,12 +278,12 @@ func (k *Kraken) WsHandleEventResponse(response *WebsocketEventResponse) { k.GetName(), response.Status) } if response.WebsocketStatusResponse.Version != krakenWSSupportedVersion { - log.Warnf("%v New version of Websocket API released. Was %v Now %v", + log.Warnf(log.ExchangeSys, "%v New version of Websocket API released. Was %v Now %v", k.GetName(), krakenWSSupportedVersion, response.WebsocketStatusResponse.Version) } case krakenWsSubscriptionStatus: if k.Verbose { - log.Debugf("%v Websocket subscription status data received", + log.Debugf(log.ExchangeSys, "%v Websocket subscription status data received", k.GetName()) } if response.Status != "subscribed" { @@ -296,7 +296,7 @@ func (k *Kraken) WsHandleEventResponse(response *WebsocketEventResponse) { } addNewSubscriptionChannelData(response) default: - log.Errorf("%v Unidentified websocket data received: %v", k.GetName(), response) + log.Errorf(log.ExchangeSys, "%v Unidentified websocket data received: %v", k.GetName(), response) } } @@ -374,7 +374,7 @@ func (k *Kraken) wsProcessSpread(channelData *WebsocketChannelData, data interfa sec, dec := math.Modf(timeData) spreadTimestamp := time.Unix(int64(sec), int64(dec*(1e9))) if k.Verbose { - log.Debugf("Spread data for '%v' received. Best bid: '%v' Best ask: '%v' Time: '%v'", + log.Debugf(log.ExchangeSys, "Spread data for '%v' received. Best bid: '%v' Best ask: '%v' Time: '%v'", channelData.Pair, bestBid, bestAsk, @@ -550,7 +550,7 @@ func (k *Kraken) wsProcessOrderBookBuffer(channelData *WebsocketChannelData, obD } orderbookBuffer[channelData.ChannelID] = append(orderbookBuffer[channelData.ChannelID], ob) if k.Verbose { - log.Debugf("Adding orderbook to buffer for channel %v. Lastupdated: %v. %v / %v", + log.Debugf(log.ExchangeSys, "Adding orderbook to buffer for channel %v. Lastupdated: %v. %v / %v", channelData.ChannelID, ob.LastUpdated, len(orderbookBuffer[channelData.ChannelID]), @@ -561,12 +561,12 @@ func (k *Kraken) wsProcessOrderBookBuffer(channelData *WebsocketChannelData, obD // wsProcessOrderBookUpdate updates an orderbook entry for a given currency pair func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData) error { if k.Verbose { - log.Debugf("Current orderbook 'LastUpdated': %v", + log.Debugf(log.ExchangeSys, "Current orderbook 'LastUpdated': %v", krakenOrderBooks[channelData.ChannelID].LastUpdated) } lowestLastUpdated := orderbookBuffer[channelData.ChannelID][0].LastUpdated if k.Verbose { - log.Debugf("Sorting orderbook. Earliest 'LastUpdated' entry: %v", + log.Debugf(log.ExchangeSys, "Sorting orderbook. Earliest 'LastUpdated' entry: %v", lowestLastUpdated) } sort.Slice(orderbookBuffer[channelData.ChannelID], func(i, j int) bool { @@ -575,7 +575,7 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData) err lowestLastUpdated = orderbookBuffer[channelData.ChannelID][0].LastUpdated if k.Verbose { - log.Debugf("Sorted orderbook. Earliest 'LastUpdated' entry: %v", + log.Debugf(log.ExchangeSys, "Sorted orderbook. Earliest 'LastUpdated' entry: %v", lowestLastUpdated) } // The earliest update has to be after the previously stored orderbook @@ -590,7 +590,7 @@ func (k *Kraken) wsProcessOrderBookUpdate(channelData *WebsocketChannelData) err k.updateChannelOrderbookEntries(channelData) highestLastUpdate := orderbookBuffer[channelData.ChannelID][len(orderbookBuffer[channelData.ChannelID])-1].LastUpdated if k.Verbose { - log.Debugf("Saving orderbook. Lastupdated: %v", + log.Debugf(log.ExchangeSys, "Saving orderbook. Lastupdated: %v", highestLastUpdate) } @@ -627,7 +627,7 @@ func (k *Kraken) updateChannelOrderbookAsks(i, j int, channelData *WebsocketChan askFound := k.updateChannelOrderbookAsk(i, j, channelData) if !askFound { if k.Verbose { - log.Debugf("Adding Ask for channel %v. Price %v. Amount %v", + log.Debugf(log.ExchangeSys, "Adding Ask for channel %v. Price %v. Amount %v", channelData.ChannelID, orderbookBuffer[channelData.ChannelID][i].Asks[j].Price, orderbookBuffer[channelData.ChannelID][i].Asks[j].Amount) @@ -646,7 +646,7 @@ func (k *Kraken) updateChannelOrderbookAsk(i, j int, channelData *WebsocketChann if orderbookBuffer[channelData.ChannelID][i].Asks[j].Amount == 0 { // Remove existing entry if k.Verbose { - log.Debugf("Removing Ask for channel %v. Price %v. Old amount %v. Buffer %v", + log.Debugf(log.ExchangeSys, "Removing Ask for channel %v. Price %v. Old amount %v. Buffer %v", channelData.ChannelID, orderbookBuffer[channelData.ChannelID][i].Asks[j].Price, krakenOrderBooks[channelData.ChannelID].Asks[l].Amount, i) @@ -657,7 +657,7 @@ func (k *Kraken) updateChannelOrderbookAsk(i, j int, channelData *WebsocketChann l-- } else if krakenOrderBooks[channelData.ChannelID].Asks[l].Amount != orderbookBuffer[channelData.ChannelID][i].Asks[j].Amount { if k.Verbose { - log.Debugf("Updating Ask for channel %v. Price %v. Old amount %v, New Amount %v", + log.Debugf(log.ExchangeSys, "Updating Ask for channel %v. Price %v. Old amount %v, New Amount %v", channelData.ChannelID, orderbookBuffer[channelData.ChannelID][i].Asks[j].Price, krakenOrderBooks[channelData.ChannelID].Asks[l].Amount, @@ -675,7 +675,7 @@ func (k *Kraken) updateChannelOrderbookBids(i, j int, channelData *WebsocketChan bidFound := k.updateChannelOrderbookBid(i, j, channelData) if !bidFound { if k.Verbose { - log.Debugf("Adding Bid for channel %v. Price %v. Amount %v", + log.Debugf(log.ExchangeSys, "Adding Bid for channel %v. Price %v. Amount %v", channelData.ChannelID, orderbookBuffer[channelData.ChannelID][i].Bids[j].Price, orderbookBuffer[channelData.ChannelID][i].Bids[j].Amount) @@ -694,7 +694,7 @@ func (k *Kraken) updateChannelOrderbookBid(i, j int, channelData *WebsocketChann if orderbookBuffer[channelData.ChannelID][i].Bids[j].Amount == 0 { // Remove existing entry if k.Verbose { - log.Debugf("Removing Bid for channel %v. Price %v. Old amount %v. Buffer %v", + log.Debugf(log.ExchangeSys, "Removing Bid for channel %v. Price %v. Old amount %v. Buffer %v", channelData.ChannelID, orderbookBuffer[channelData.ChannelID][i].Bids[j].Price, krakenOrderBooks[channelData.ChannelID].Bids[l].Amount, i) @@ -705,7 +705,7 @@ func (k *Kraken) updateChannelOrderbookBid(i, j int, channelData *WebsocketChann l-- } else if krakenOrderBooks[channelData.ChannelID].Bids[l].Amount != orderbookBuffer[channelData.ChannelID][i].Bids[j].Amount { if k.Verbose { - log.Debugf("Updating Bid for channel %v. Price %v. Old amount %v, New Amount %v", + log.Debugf(log.ExchangeSys, "Updating Bid for channel %v. Price %v. Old amount %v, New Amount %v", channelData.ChannelID, orderbookBuffer[channelData.ChannelID][i].Bids[j].Price, krakenOrderBooks[channelData.ChannelID].Bids[l].Amount, @@ -777,7 +777,7 @@ func (k *Kraken) Subscribe(channelToSubscribe exchange.WebsocketChannelSubscript json, err := common.JSONEncode(resp) if err != nil { if k.Verbose { - log.Debugf("%v subscribe error: %v", k.Name, err) + log.Errorf(log.ExchangeSys, "%v subscribe error: %v", k.Name, err) } return err } @@ -796,7 +796,7 @@ func (k *Kraken) Unsubscribe(channelToSubscribe exchange.WebsocketChannelSubscri json, err := common.JSONEncode(resp) if err != nil { if k.Verbose { - log.Debugf("%v unsubscribe error: %v", k.Name, err) + log.Errorf(log.ExchangeSys, "%v unsubscribe error: %v", k.Name, err) } return err } diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 3fa3f282..4302ec8d 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -143,12 +143,12 @@ func (k *Kraken) Run() { if !common.StringDataContains(k.GetEnabledPairs(asset.Spot).Strings(), "-") || !common.StringDataContains(k.GetAvailablePairs(asset.Spot).Strings(), "-") { enabledPairs := currency.NewPairsFromStrings([]string{"XBT-USD"}) - log.Warn("WARNING: Available pairs for Kraken reset due to config upgrade, please enable the ones you would like again") + log.Warn(log.ExchangeSys, "Available pairs for Kraken reset due to config upgrade, please enable the ones you would like again") forceUpdate = true err := k.UpdatePairs(enabledPairs, asset.Spot, true, true) if err != nil { - log.Errorf("%s failed to update currencies. Err: %s\n", k.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err: %s\n", k.Name, err) } } @@ -158,7 +158,7 @@ func (k *Kraken) Run() { err := k.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", k.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", k.Name, err) } } diff --git a/exchanges/lakebtc/lakebtc.go b/exchanges/lakebtc/lakebtc.go index 8fec64cc..6d82855d 100644 --- a/exchanges/lakebtc/lakebtc.go +++ b/exchanges/lakebtc/lakebtc.go @@ -93,12 +93,12 @@ func (l *LakeBTC) GetOrderBook(currency string) (Orderbook, error) { for _, x := range resp.Bids { price, err := strconv.ParseFloat(x[0], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } amount, err := strconv.ParseFloat(x[1], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } orderbook.Bids = append(orderbook.Bids, OrderbookStructure{price, amount}) @@ -107,12 +107,12 @@ func (l *LakeBTC) GetOrderBook(currency string) (Orderbook, error) { for _, x := range resp.Asks { price, err := strconv.ParseFloat(x[0], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } amount, err := strconv.ParseFloat(x[1], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } orderbook.Asks = append(orderbook.Asks, OrderbookStructure{price, amount}) @@ -265,7 +265,7 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int hmac := crypto.GetHMAC(crypto.HashSHA1, []byte(req), []byte(l.API.Credentials.Secret)) if l.Verbose { - log.Debugf("Sending POST request to %s calling method %s with params %s\n", l.API.Endpoints.URL, method, req) + log.Debugf(log.ExchangeSys, "Sending POST request to %s calling method %s with params %s\n", l.API.Endpoints.URL, method, req) } postData := make(map[string]interface{}) diff --git a/exchanges/lakebtc/lakebtc_wrapper.go b/exchanges/lakebtc/lakebtc_wrapper.go index 0101c816..1b737b4b 100644 --- a/exchanges/lakebtc/lakebtc_wrapper.go +++ b/exchanges/lakebtc/lakebtc_wrapper.go @@ -120,7 +120,7 @@ func (l *LakeBTC) Run() { err := l.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", l.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", l.Name, err) } } diff --git a/exchanges/localbitcoins/localbitcoins.go b/exchanges/localbitcoins/localbitcoins.go index 5a34882b..54e00269 100644 --- a/exchanges/localbitcoins/localbitcoins.go +++ b/exchanges/localbitcoins/localbitcoins.go @@ -635,12 +635,12 @@ func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) { for _, x := range resp.Bids { price, err := strconv.ParseFloat(x[0], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } amount, err := strconv.ParseFloat(x[1], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } orderbook.Bids = append(orderbook.Bids, Price{price, amount}) @@ -649,12 +649,12 @@ func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) { for _, x := range resp.Asks { price, err := strconv.ParseFloat(x[0], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } amount, err := strconv.ParseFloat(x[1], 64) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) continue } orderbook.Asks = append(orderbook.Asks, Price{price, amount}) @@ -688,7 +688,7 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, params headers["Content-Type"] = "application/x-www-form-urlencoded" if l.Verbose { - log.Debugf("Sending POST request to `%s`, path: `%s`, params: `%s`.", l.API.Endpoints.URL, path, encoded) + log.Debugf(log.ExchangeSys, "Sending POST request to `%s`, path: `%s`, params: `%s`.", l.API.Endpoints.URL, path, encoded) } if method == http.MethodGet && len(encoded) > 0 { diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index b977c30a..7f2a3f4d 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -121,7 +121,7 @@ func (l *LocalBitcoins) Run() { err := l.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", l.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", l.Name, err) } } @@ -420,7 +420,7 @@ func (l *LocalBitcoins) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequ for i := range resp { orderDate, err := time.Parse(time.RFC3339, resp[i].Data.CreatedAt) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", l.Name, "GetActiveOrders", resp[i].Data.Advertisement.ID, @@ -481,7 +481,7 @@ func (l *LocalBitcoins) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequ for i := range allTrades { orderDate, err := time.Parse(time.RFC3339, allTrades[i].Data.CreatedAt) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", l.Name, "GetActiveOrders", allTrades[i].Data.Advertisement.ID, diff --git a/exchanges/okcoin/okcoin_wrapper.go b/exchanges/okcoin/okcoin_wrapper.go index 0c94dc04..7cf27e72 100644 --- a/exchanges/okcoin/okcoin_wrapper.go +++ b/exchanges/okcoin/okcoin_wrapper.go @@ -113,7 +113,7 @@ func (o *OKCoin) Start(wg *sync.WaitGroup) { // Run implements the OKEX wrapper func (o *OKCoin) Run() { if o.Verbose { - log.Debugf("%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket.IsEnabled()), o.WebsocketURL) + log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket.IsEnabled()), o.WebsocketURL) } if !o.GetEnabledFeatures().AutoPairUpdates { @@ -122,7 +122,7 @@ func (o *OKCoin) Run() { err := o.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", o.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", o.Name, err) } } diff --git a/exchanges/okex/okex_wrapper.go b/exchanges/okex/okex_wrapper.go index 92a9cbb1..c31d391e 100644 --- a/exchanges/okex/okex_wrapper.go +++ b/exchanges/okex/okex_wrapper.go @@ -113,7 +113,7 @@ func (o *OKEX) Start(wg *sync.WaitGroup) { // Run implements the OKEX wrapper func (o *OKEX) Run() { if o.Verbose { - log.Debugf("%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket.IsEnabled()), o.API.Endpoints.WebsocketURL) + log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket.IsEnabled()), o.API.Endpoints.WebsocketURL) } if !o.GetEnabledFeatures().AutoPairUpdates { @@ -122,7 +122,7 @@ func (o *OKEX) Run() { err := o.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", o.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", o.Name, err) } } diff --git a/exchanges/okgroup/okgroup.go b/exchanges/okgroup/okgroup.go index ee606771..9147f8c3 100644 --- a/exchanges/okgroup/okgroup.go +++ b/exchanges/okgroup/okgroup.go @@ -495,7 +495,7 @@ func (o *OKGroup) GetMarginTransactionDetails(request GetSpotTransactionDetailsR func FormatParameters(request interface{}) (parameters string) { v, err := query.Values(request) if err != nil { - log.Errorf("Could not parse %v to URL values. Check that the type has url fields", reflect.TypeOf(request).Name()) + log.Errorf(log.ExchangeSys, "Could not parse %v to URL values. Check that the type has url fields", reflect.TypeOf(request).Name()) return } urlEncodedValues := v.Encode() @@ -546,13 +546,13 @@ func (o *OKGroup) SendHTTPRequest(httpMethod, requestType, requestPath string, d } if o.Verbose { - log.Debugf("Request JSON: %s\n", payload) + log.Debugf(log.ExchangeSys, "Request JSON: %s\n", payload) } } path := o.API.Endpoints.URL + requestType + o.APIVersion + requestPath if o.Verbose { - log.Debugf("Sending %v request to %s \n", requestType, path) + log.Debugf(log.ExchangeSys, "Sending %v request to %s \n", requestType, path) } headers := make(map[string]string) diff --git a/exchanges/okgroup/okgroup_websocket.go b/exchanges/okgroup/okgroup_websocket.go index b00e849d..79efb391 100644 --- a/exchanges/okgroup/okgroup_websocket.go +++ b/exchanges/okgroup/okgroup_websocket.go @@ -159,7 +159,7 @@ func (o *OKGroup) writeToWebsocket(message string) error { o.wsRequestMtx.Lock() defer o.wsRequestMtx.Unlock() if o.Verbose { - log.Debugf("%v sending message to WS: %v", o.Name, message) + log.Debugf(log.ExchangeSys, "%v sending message to WS: %v", o.Name, message) } // Really basic WS rate limit time.Sleep(okGroupWsRateLimit) @@ -183,7 +183,7 @@ func (o *OKGroup) WsConnect() error { var err error if o.Verbose { - log.Debugf("Attempting to connect to %v", o.Websocket.GetWebsocketURL()) + log.Debugf(log.ExchangeSys, "Attempting to connect to %v", o.Websocket.GetWebsocketURL()) } o.WebsocketConn, _, err = dialer.Dial(o.Websocket.GetWebsocketURL(), http.Header{}) @@ -193,7 +193,7 @@ func (o *OKGroup) WsConnect() error { err) } if o.Verbose { - log.Debugf("Successful connection to %v", + log.Debugf(log.ExchangeSys, "Successful connection to %v\n", o.Websocket.GetWebsocketURL()) } wg := sync.WaitGroup{} @@ -203,7 +203,7 @@ func (o *OKGroup) WsConnect() error { if o.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) { err = o.WsLogin() if err != nil { - log.Errorf("%v - authentication failed: %v", o.Name, err) + log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", o.Name, err) } } @@ -235,7 +235,7 @@ func (o *OKGroup) WsReadData() (exchange.WebsocketResponse, error) { } } if o.Verbose { - log.Debugf("%v Websocket message received: %v", o.Name, string(standardMessage)) + log.Debugf(log.ExchangeSys, "%v Websocket message received: %v", o.Name, string(standardMessage)) } return exchange.WebsocketResponse{Raw: standardMessage}, nil @@ -259,7 +259,7 @@ func (o *OKGroup) wsPingHandler(wg *sync.WaitGroup) { case <-ticker.C: err := o.writeToWebsocket("ping") if o.Verbose { - log.Debugf("%v sending ping", o.GetName()) + log.Debugf(log.ExchangeSys, "%v sending ping", o.GetName()) } if err != nil { o.Websocket.DataHandler <- err @@ -300,7 +300,7 @@ func (o *OKGroup) WsHandleData(wg *sync.WaitGroup) { err = common.JSONDecode(resp.Raw, &errorResponse) if err == nil && errorResponse.ErrorCode > 0 { if o.Verbose { - log.Debugf("WS Error Event: %v Message: %v", errorResponse.Event, errorResponse.Message) + log.Debugf(log.ExchangeSys, "WS Error Event: %v Message: %v", errorResponse.Event, errorResponse.Message) } o.WsHandleErrorResponse(errorResponse) continue @@ -312,7 +312,7 @@ func (o *OKGroup) WsHandleData(wg *sync.WaitGroup) { o.Websocket.SetCanUseAuthenticatedEndpoints(eventResponse.Success) } if o.Verbose { - log.Debugf("WS Event: %v on Channel: %v", eventResponse.Event, eventResponse.Channel) + log.Debugf(log.ExchangeSys, "WS Event: %v on Channel: %v", eventResponse.Event, eventResponse.Channel) } o.Websocket.DataHandler <- eventResponse continue @@ -352,7 +352,7 @@ func (o *OKGroup) WsHandleErrorResponse(event WebsocketErrorResponse) { errorMessage := fmt.Sprintf("%v error - %v message: %s ", o.GetName(), event.ErrorCode, event.Message) if o.Verbose { - log.Error(errorMessage) + log.Error(log.ExchangeSys, errorMessage) } o.Websocket.DataHandler <- fmt.Errorf(errorMessage) } @@ -389,12 +389,12 @@ func (o *OKGroup) WsHandleDataResponse(response *WebsocketDataResponse) { okGroupWsCandle1800s, okGroupWsCandle3600s, okGroupWsCandle7200s, okGroupWsCandle14400s, okGroupWsCandle21600s, okGroupWsCandle43200s, okGroupWsCandle86400s, okGroupWsCandle604900s: if o.Verbose { - log.Debugf("%v Websocket candle data received", o.GetName()) + log.Debugf(log.ExchangeSys, "%v Websocket candle data received", o.GetName()) } o.wsProcessCandles(response) case okGroupWsDepth, okGroupWsDepth5: if o.Verbose { - log.Debugf("%v Websocket orderbook data received", o.GetName()) + log.Debugf(log.ExchangeSys, "%v Websocket orderbook data received", o.GetName()) } // Locking, orderbooks cannot be processed out of order orderbookMutex.Lock() @@ -410,12 +410,12 @@ func (o *OKGroup) WsHandleDataResponse(response *WebsocketDataResponse) { orderbookMutex.Unlock() case okGroupWsTicker: if o.Verbose { - log.Debugf("%v Websocket ticker data received", o.GetName()) + log.Debugf(log.ExchangeSys, "%v Websocket ticker data received", o.GetName()) } o.wsProcessTickers(response) case okGroupWsTrade: if o.Verbose { - log.Debugf("%v Websocket trade data received", o.GetName()) + log.Debugf(log.ExchangeSys, "%v Websocket trade data received", o.GetName()) } o.wsProcessTrades(response) default: @@ -427,7 +427,7 @@ func (o *OKGroup) WsHandleDataResponse(response *WebsocketDataResponse) { // where there is no websocket datahandler for it func logDataResponse(response *WebsocketDataResponse) { for i := range response.Data { - log.Errorf("Unhandled channel: '%v'. Instrument '%v' Timestamp '%v', Data '%v", + log.Errorf(log.ExchangeSys, "Unhandled channel: '%v'. Instrument '%v' Timestamp '%v', Data '%v", response.Table, response.Data[i].InstrumentID, response.Data[i].Timestamp, @@ -474,7 +474,7 @@ func (o *OKGroup) wsProcessCandles(response *WebsocketDataResponse) { instrument := currency.NewPairDelimiter(response.Data[i].InstrumentID, "-") timeData, err := time.Parse(time.RFC3339Nano, response.Data[i].WebsocketCandleResponse.Candle[0]) if err != nil { - log.Warnf("%v Time data could not be parsed: %v", o.GetName(), response.Data[i].Candle[0]) + log.Warnf(log.ExchangeSys, "%v Time data could not be parsed: %v", o.GetName(), response.Data[i].Candle[0]) } candleIndex := strings.LastIndex(response.Table, okGroupWsCandle) @@ -535,7 +535,7 @@ func (o *OKGroup) WsProcessPartialOrderBook(wsEventData *WebsocketDataWrapper, i return fmt.Errorf("channel: %v. Orderbook partial for %v checksum invalid", tableName, instrument) } if o.Verbose { - log.Debug("Passed checksum!") + log.Debug(log.ExchangeSys, "Passed checksum!") } asks := o.AppendWsOrderbookItems(wsEventData.Asks) bids := o.AppendWsOrderbookItems(wsEventData.Bids) @@ -569,7 +569,7 @@ func (o *OKGroup) WsProcessUpdateOrderbook(wsEventData *WebsocketDataWrapper, in } if internalOrderbook.LastUpdated.After(wsEventData.Timestamp) { if o.Verbose { - log.Errorf("Orderbook update out of order. Existing: %v, Attempted: %v", internalOrderbook.LastUpdated.Unix(), wsEventData.Timestamp.Unix()) + log.Errorf(log.ExchangeSys, "Orderbook update out of order. Existing: %v, Attempted: %v", internalOrderbook.LastUpdated.Unix(), wsEventData.Timestamp.Unix()) } return errors.New("updated orderbook is older than existing") } @@ -584,16 +584,16 @@ func (o *OKGroup) WsProcessUpdateOrderbook(wsEventData *WebsocketDataWrapper, in checksum := o.CalculateUpdateOrderbookChecksum(&internalOrderbook) if checksum == wsEventData.Checksum { if o.Verbose { - log.Debug("Orderbook valid") + log.Debug(log.ExchangeSys, "Orderbook valid") } internalOrderbook.LastUpdated = wsEventData.Timestamp if o.Verbose { - log.Debug("Internalising orderbook") + log.Debug(log.ExchangeSys, "Internalising orderbook") } err := o.Websocket.Orderbook.LoadSnapshot(&internalOrderbook, o.GetName(), true) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) } o.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{ Exchange: o.GetName(), @@ -602,7 +602,7 @@ func (o *OKGroup) WsProcessUpdateOrderbook(wsEventData *WebsocketDataWrapper, in } } else { if o.Verbose { - log.Debug("Orderbook invalid") + log.Warnln(log.ExchangeSys, "Orderbook invalid") } return fmt.Errorf("channel: %v. Orderbook update for %v checksum invalid. Received %v Calculated %v", tableName, instrument, wsEventData.Checksum, checksum) } @@ -727,7 +727,7 @@ func (o *OKGroup) Subscribe(channelToSubscribe exchange.WebsocketChannelSubscrip json, err := common.JSONEncode(resp) if err != nil { if o.Verbose { - log.Debugf("%v subscribe error: %v", o.Name, err) + log.Errorf(log.ExchangeSys, "%v subscribe error: %v", o.Name, err) } return err } @@ -743,7 +743,7 @@ func (o *OKGroup) Unsubscribe(channelToSubscribe exchange.WebsocketChannelSubscr json, err := common.JSONEncode(resp) if err != nil { if o.Verbose { - log.Debugf("%v unsubscribe error: %v", o.Name, err) + log.Errorf(log.ExchangeSys, "%v unsubscribe error: %v", o.Name, err) } return err } diff --git a/exchanges/okgroup/okgroup_wrapper.go b/exchanges/okgroup/okgroup_wrapper.go index 616b62fe..3dccb0b1 100644 --- a/exchanges/okgroup/okgroup_wrapper.go +++ b/exchanges/okgroup/okgroup_wrapper.go @@ -92,11 +92,11 @@ func (o *OKGroup) UpdateOrderbook(p currency.Pair, assetType asset.Item) (resp o for x := range orderbookNew.Bids { amount, convErr := strconv.ParseFloat(orderbookNew.Bids[x][1], 64) if convErr != nil { - log.Errorf("Could not convert %v to float64", orderbookNew.Bids[x][1]) + log.Errorf(log.ExchangeSys, "Could not convert %v to float64", orderbookNew.Bids[x][1]) } price, convErr := strconv.ParseFloat(orderbookNew.Bids[x][0], 64) if convErr != nil { - log.Errorf("Could not convert %v to float64", orderbookNew.Bids[x][0]) + log.Errorf(log.ExchangeSys, "Could not convert %v to float64", orderbookNew.Bids[x][0]) } resp.Bids = append(resp.Bids, orderbook.Item{ Amount: amount, @@ -107,11 +107,11 @@ func (o *OKGroup) UpdateOrderbook(p currency.Pair, assetType asset.Item) (resp o for x := range orderbookNew.Asks { amount, convErr := strconv.ParseFloat(orderbookNew.Asks[x][1], 64) if convErr != nil { - log.Errorf("Could not convert %v to float64", orderbookNew.Asks[x][1]) + log.Errorf(log.ExchangeSys, "Could not convert %v to float64", orderbookNew.Asks[x][1]) } price, convErr := strconv.ParseFloat(orderbookNew.Asks[x][0], 64) if convErr != nil { - log.Errorf("Could not convert %v to float64", orderbookNew.Asks[x][0]) + log.Errorf(log.ExchangeSys, "Could not convert %v to float64", orderbookNew.Asks[x][0]) } resp.Asks = append(resp.Asks, orderbook.Item{ Amount: amount, @@ -140,11 +140,11 @@ func (o *OKGroup) GetAccountInfo() (resp exchange.AccountInfo, err error) { for _, curr := range currencies { hold, err := strconv.ParseFloat(curr.Hold, 64) if err != nil { - log.Errorf("Could not convert %v to float64", curr.Hold) + log.Errorf(log.ExchangeSys, "Could not convert %v to float64", curr.Hold) } totalValue, err := strconv.ParseFloat(curr.Balance, 64) if err != nil { - log.Errorf("Could not convert %v to float64", curr.Balance) + log.Errorf(log.ExchangeSys, "Could not convert %v to float64", curr.Balance) } currencyAccount.Currencies = append(currencyAccount.Currencies, exchange.AccountCurrencyInfo{ CurrencyName: currency.NewCode(curr.Currency), diff --git a/exchanges/orderbook/calculator.go b/exchanges/orderbook/calculator.go index dbe0099a..88655138 100644 --- a/exchanges/orderbook/calculator.go +++ b/exchanges/orderbook/calculator.go @@ -1,227 +1,227 @@ -package orderbook - -import ( - "errors" - "fmt" - "sort" - - math "github.com/thrasher-/gocryptotrader/common/math" - log "github.com/thrasher-/gocryptotrader/logger" -) - -// WhaleBombResult returns the whale bomb result -type WhaleBombResult struct { - Amount float64 - MinimumPrice float64 - MaximumPrice float64 - PercentageGainOrLoss float64 - Orders orderSummary - Status string -} - -// WhaleBomb finds the amount required to target a price -func (o *Base) WhaleBomb(priceTarget float64, buy bool) (*WhaleBombResult, error) { - if priceTarget < 0 { - return nil, errors.New("price target is invalid") - } - if buy { - a, orders := o.findAmount(priceTarget, true) - min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) - var err error - if max < priceTarget { - err = errors.New("unable to hit price target due to insufficient orderbook items") - } - status := fmt.Sprintf("Buying %.2f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", - a, o.Pair.Quote.String(), o.Pair.Base.String(), min, max, - math.CalculatePercentageGainOrLoss(max, min), len(orders)) - return &WhaleBombResult{ - Amount: a, - Orders: orders, - MinimumPrice: min, - MaximumPrice: max, - Status: status, - }, err - } - - a, orders := o.findAmount(priceTarget, false) - min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) - var err error - if min > priceTarget { - err = errors.New("unable to hit price target due to insufficient orderbook items") - } - status := fmt.Sprintf("Selling %.2f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", - a, o.Pair.Base.String(), o.Pair.Quote.String(), max, min, - math.CalculatePercentageGainOrLoss(min, max), len(orders)) - return &WhaleBombResult{ - Amount: a, - Orders: orders, - MinimumPrice: min, - MaximumPrice: max, - Status: status, - }, err -} - -// OrderSimulationResult returns the order simulation result -type OrderSimulationResult WhaleBombResult - -// SimulateOrder simulates an order -func (o *Base) SimulateOrder(amount float64, buy bool) *OrderSimulationResult { - if buy { - orders, amt := o.buy(amount) - min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) - pct := math.CalculatePercentageGainOrLoss(max, min) - status := fmt.Sprintf("Buying %.2f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", - amount, o.Pair.Quote.String(), o.Pair.Base.String(), min, max, - pct, len(orders)) - return &OrderSimulationResult{ - Orders: orders, - Amount: amt, - MinimumPrice: min, - MaximumPrice: max, - PercentageGainOrLoss: pct, - Status: status, - } - } - orders, amt := o.sell(amount) - min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) - pct := math.CalculatePercentageGainOrLoss(min, max) - status := fmt.Sprintf("Selling %f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", - amount, o.Pair.Base.String(), o.Pair.Quote.String(), max, min, - pct, len(orders)) - return &OrderSimulationResult{ - Orders: orders, - Amount: amt, - MinimumPrice: min, - MaximumPrice: max, - PercentageGainOrLoss: pct, - Status: status, - } -} - -type orderSummary []Item - -func (o orderSummary) Print() { - for x := range o { - log.Debugf("Order: Price: %f Amount: %f", o[x].Price, o[x].Amount) - } -} - -func (o orderSummary) MinimumPrice(reverse bool) float64 { - if len(o) != 0 { - sortOrdersByPrice(&o, reverse) - return o[0].Price - } - return 0 -} - -func (o orderSummary) MaximumPrice(reverse bool) float64 { - if len(o) != 0 { - sortOrdersByPrice(&o, reverse) - return o[0].Price - } - return 0 -} - -// ByPrice used for sorting orders by order date -type ByPrice orderSummary - -func (b ByPrice) Len() int { return len(b) } -func (b ByPrice) Less(i, j int) bool { return b[i].Price < b[j].Price } -func (b ByPrice) Swap(i, j int) { b[i], b[j] = b[j], b[i] } - -// sortOrdersByPrice the caller function to sort orders -func sortOrdersByPrice(o *orderSummary, reverse bool) { - if reverse { - sort.Sort(sort.Reverse(ByPrice(*o))) - } else { - sort.Sort(ByPrice(*o)) - } -} - -func (o *Base) findAmount(price float64, buy bool) (float64, orderSummary) { - var orders orderSummary - var amt float64 - - if buy { - asks := o.Asks - for x := range asks { - if asks[x].Price >= price { - amt += asks[x].Price * asks[x].Amount - orders = append(orders, Item{ - Price: asks[x].Price, - Amount: asks[x].Amount, - }) - return amt, orders - } - orders = append(orders, Item{ - Price: asks[x].Price, - Amount: asks[x].Amount, - }) - amt += asks[x].Price * asks[x].Amount - } - return amt, orders - } - - for x := range o.Bids { - if o.Bids[x].Price <= price { - amt += o.Bids[x].Amount - orders = append(orders, Item{ - Price: o.Bids[x].Price, - Amount: o.Bids[x].Amount, - }) - break - } - orders = append(orders, Item{ - Price: o.Bids[x].Price, - Amount: o.Bids[x].Amount, - }) - amt += o.Bids[x].Amount - } - return amt, orders -} - -func (o *Base) buy(amount float64) (orders orderSummary, baseAmount float64) { - var processedAmt float64 - for x := range o.Asks { - subtotal := o.Asks[x].Price * o.Asks[x].Amount - if processedAmt+subtotal >= amount { - diff := amount - processedAmt - subAmt := diff / o.Asks[x].Price - orders = append(orders, Item{ - Price: o.Asks[x].Price, - Amount: subAmt, - }) - baseAmount += subAmt - break - } - processedAmt += subtotal - baseAmount += o.Asks[x].Amount - orders = append(orders, Item{ - Price: o.Asks[x].Price, - Amount: o.Asks[x].Amount, - }) - } - return -} - -func (o *Base) sell(amount float64) (orders orderSummary, quoteAmount float64) { - var processedAmt float64 - for x := range o.Bids { - if processedAmt+o.Bids[x].Amount >= amount { - diff := amount - processedAmt - orders = append(orders, Item{ - Price: o.Bids[x].Price, - Amount: diff, - }) - quoteAmount += diff * o.Bids[x].Price - break - } - processedAmt += o.Bids[x].Amount - quoteAmount += o.Bids[x].Amount * o.Bids[x].Price - orders = append(orders, Item{ - Price: o.Bids[x].Price, - Amount: o.Bids[x].Amount, - }) - } - return -} +package orderbook + +import ( + "errors" + "fmt" + "sort" + + math "github.com/thrasher-/gocryptotrader/common/math" + log "github.com/thrasher-/gocryptotrader/logger" +) + +// WhaleBombResult returns the whale bomb result +type WhaleBombResult struct { + Amount float64 + MinimumPrice float64 + MaximumPrice float64 + PercentageGainOrLoss float64 + Orders orderSummary + Status string +} + +// WhaleBomb finds the amount required to target a price +func (o *Base) WhaleBomb(priceTarget float64, buy bool) (*WhaleBombResult, error) { + if priceTarget < 0 { + return nil, errors.New("price target is invalid") + } + if buy { + a, orders := o.findAmount(priceTarget, true) + min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) + var err error + if max < priceTarget { + err = errors.New("unable to hit price target due to insufficient orderbook items") + } + status := fmt.Sprintf("Buying %.2f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", + a, o.Pair.Quote.String(), o.Pair.Base.String(), min, max, + math.CalculatePercentageGainOrLoss(max, min), len(orders)) + return &WhaleBombResult{ + Amount: a, + Orders: orders, + MinimumPrice: min, + MaximumPrice: max, + Status: status, + }, err + } + + a, orders := o.findAmount(priceTarget, false) + min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) + var err error + if min > priceTarget { + err = errors.New("unable to hit price target due to insufficient orderbook items") + } + status := fmt.Sprintf("Selling %.2f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", + a, o.Pair.Base.String(), o.Pair.Quote.String(), max, min, + math.CalculatePercentageGainOrLoss(min, max), len(orders)) + return &WhaleBombResult{ + Amount: a, + Orders: orders, + MinimumPrice: min, + MaximumPrice: max, + Status: status, + }, err +} + +// OrderSimulationResult returns the order simulation result +type OrderSimulationResult WhaleBombResult + +// SimulateOrder simulates an order +func (o *Base) SimulateOrder(amount float64, buy bool) *OrderSimulationResult { + if buy { + orders, amt := o.buy(amount) + min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) + pct := math.CalculatePercentageGainOrLoss(max, min) + status := fmt.Sprintf("Buying %.2f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", + amount, o.Pair.Quote.String(), o.Pair.Base.String(), min, max, + pct, len(orders)) + return &OrderSimulationResult{ + Orders: orders, + Amount: amt, + MinimumPrice: min, + MaximumPrice: max, + PercentageGainOrLoss: pct, + Status: status, + } + } + orders, amt := o.sell(amount) + min, max := orders.MinimumPrice(false), orders.MaximumPrice(true) + pct := math.CalculatePercentageGainOrLoss(min, max) + status := fmt.Sprintf("Selling %f %v worth of %v will send the price from %v to %v [%.2f%%] and take %v orders.", + amount, o.Pair.Base.String(), o.Pair.Quote.String(), max, min, + pct, len(orders)) + return &OrderSimulationResult{ + Orders: orders, + Amount: amt, + MinimumPrice: min, + MaximumPrice: max, + PercentageGainOrLoss: pct, + Status: status, + } +} + +type orderSummary []Item + +func (o orderSummary) Print() { + for x := range o { + log.Debugf(log.OrderBook, "Order: Price: %f Amount: %f", o[x].Price, o[x].Amount) + } +} + +func (o orderSummary) MinimumPrice(reverse bool) float64 { + if len(o) != 0 { + sortOrdersByPrice(&o, reverse) + return o[0].Price + } + return 0 +} + +func (o orderSummary) MaximumPrice(reverse bool) float64 { + if len(o) != 0 { + sortOrdersByPrice(&o, reverse) + return o[0].Price + } + return 0 +} + +// ByPrice used for sorting orders by order date +type ByPrice orderSummary + +func (b ByPrice) Len() int { return len(b) } +func (b ByPrice) Less(i, j int) bool { return b[i].Price < b[j].Price } +func (b ByPrice) Swap(i, j int) { b[i], b[j] = b[j], b[i] } + +// sortOrdersByPrice the caller function to sort orders +func sortOrdersByPrice(o *orderSummary, reverse bool) { + if reverse { + sort.Sort(sort.Reverse(ByPrice(*o))) + } else { + sort.Sort(ByPrice(*o)) + } +} + +func (o *Base) findAmount(price float64, buy bool) (float64, orderSummary) { + var orders orderSummary + var amt float64 + + if buy { + asks := o.Asks + for x := range asks { + if asks[x].Price >= price { + amt += asks[x].Price * asks[x].Amount + orders = append(orders, Item{ + Price: asks[x].Price, + Amount: asks[x].Amount, + }) + return amt, orders + } + orders = append(orders, Item{ + Price: asks[x].Price, + Amount: asks[x].Amount, + }) + amt += asks[x].Price * asks[x].Amount + } + return amt, orders + } + + for x := range o.Bids { + if o.Bids[x].Price <= price { + amt += o.Bids[x].Amount + orders = append(orders, Item{ + Price: o.Bids[x].Price, + Amount: o.Bids[x].Amount, + }) + break + } + orders = append(orders, Item{ + Price: o.Bids[x].Price, + Amount: o.Bids[x].Amount, + }) + amt += o.Bids[x].Amount + } + return amt, orders +} + +func (o *Base) buy(amount float64) (orders orderSummary, baseAmount float64) { + var processedAmt float64 + for x := range o.Asks { + subtotal := o.Asks[x].Price * o.Asks[x].Amount + if processedAmt+subtotal >= amount { + diff := amount - processedAmt + subAmt := diff / o.Asks[x].Price + orders = append(orders, Item{ + Price: o.Asks[x].Price, + Amount: subAmt, + }) + baseAmount += subAmt + break + } + processedAmt += subtotal + baseAmount += o.Asks[x].Amount + orders = append(orders, Item{ + Price: o.Asks[x].Price, + Amount: o.Asks[x].Amount, + }) + } + return +} + +func (o *Base) sell(amount float64) (orders orderSummary, quoteAmount float64) { + var processedAmt float64 + for x := range o.Bids { + if processedAmt+o.Bids[x].Amount >= amount { + diff := amount - processedAmt + orders = append(orders, Item{ + Price: o.Bids[x].Price, + Amount: diff, + }) + quoteAmount += diff * o.Bids[x].Price + break + } + processedAmt += o.Bids[x].Amount + quoteAmount += o.Bids[x].Amount * o.Bids[x].Price + orders = append(orders, Item{ + Price: o.Bids[x].Price, + Amount: o.Bids[x].Amount, + }) + } + return +} diff --git a/exchanges/orderbook/calculator_test.go b/exchanges/orderbook/calculator_test.go index 484fe838..d7373afb 100644 --- a/exchanges/orderbook/calculator_test.go +++ b/exchanges/orderbook/calculator_test.go @@ -1,79 +1,79 @@ -package orderbook - -import ( - "testing" - - "github.com/thrasher-/gocryptotrader/currency" -) - -func testSetup() Base { - return Base{ - ExchangeName: "a", - Pair: currency.NewPair(currency.BTC, currency.USD), - Asks: []Item{ - {Price: 7000, Amount: 1}, - {Price: 7001, Amount: 2}, - }, - Bids: []Item{ - {Price: 6999, Amount: 1}, - {Price: 6998, Amount: 2}, - }, - } -} - -func TestWhaleBomb(t *testing.T) { - t.Parallel() - b := testSetup() - - // invalid price amout - _, err := b.WhaleBomb(-1, true) - if err == nil { - t.Error("unexpected result") - } - - // valid - b.WhaleBomb(7001, true) - // invalid - b.WhaleBomb(7002, true) - - // valid - b.WhaleBomb(6998, false) - // invalid - b.WhaleBomb(6997, false) -} - -func TestSimulateOrder(t *testing.T) { - t.Parallel() - b := testSetup() - b.SimulateOrder(8000, true) - b.SimulateOrder(1.5, false) -} - -func TestOrderSummary(t *testing.T) { - var o orderSummary - if p := o.MaximumPrice(false); p != 0 { - t.Error("unexpected result") - } - if p := o.MinimumPrice(false); p != 0 { - t.Error("unexpected result") - } - - o = orderSummary{ - {Price: 1337, Amount: 1}, - {Price: 9001, Amount: 1}, - } - if p := o.MaximumPrice(false); p != 1337 { - t.Error("unexpected result") - } - if p := o.MaximumPrice(true); p != 9001 { - t.Error("unexpected result") - } - if p := o.MinimumPrice(false); p != 1337 { - t.Error("unexpected result") - } - if p := o.MinimumPrice(true); p != 9001 { - t.Error("unexpected result") - } - - o.Print() -} +package orderbook + +import ( + "testing" + + "github.com/thrasher-/gocryptotrader/currency" +) + +func testSetup() Base { + return Base{ + ExchangeName: "a", + Pair: currency.NewPair(currency.BTC, currency.USD), + Asks: []Item{ + {Price: 7000, Amount: 1}, + {Price: 7001, Amount: 2}, + }, + Bids: []Item{ + {Price: 6999, Amount: 1}, + {Price: 6998, Amount: 2}, + }, + } +} + +func TestWhaleBomb(t *testing.T) { + t.Parallel() + b := testSetup() + + // invalid price amout + _, err := b.WhaleBomb(-1, true) + if err == nil { + t.Error("unexpected result") + } + + // valid + b.WhaleBomb(7001, true) + // invalid + b.WhaleBomb(7002, true) + + // valid + b.WhaleBomb(6998, false) + // invalid + b.WhaleBomb(6997, false) +} + +func TestSimulateOrder(t *testing.T) { + t.Parallel() + b := testSetup() + b.SimulateOrder(8000, true) + b.SimulateOrder(1.5, false) +} + +func TestOrderSummary(t *testing.T) { + var o orderSummary + if p := o.MaximumPrice(false); p != 0 { + t.Error("unexpected result") + } + if p := o.MinimumPrice(false); p != 0 { + t.Error("unexpected result") + } + + o = orderSummary{ + {Price: 1337, Amount: 1}, + {Price: 9001, Amount: 1}, + } + if p := o.MaximumPrice(false); p != 1337 { + t.Error("unexpected result") + } + if p := o.MaximumPrice(true); p != 9001 { + t.Error("unexpected result") + } + if p := o.MinimumPrice(false); p != 1337 { + t.Error("unexpected result") + } + if p := o.MinimumPrice(true); p != 9001 { + t.Error("unexpected result") + } + + o.Print() +} diff --git a/exchanges/orderbook/orderbook_test.go b/exchanges/orderbook/orderbook_test.go index 72c16f3e..b7e53623 100644 --- a/exchanges/orderbook/orderbook_test.go +++ b/exchanges/orderbook/orderbook_test.go @@ -9,7 +9,6 @@ import ( "github.com/thrasher-/gocryptotrader/currency" "github.com/thrasher-/gocryptotrader/exchanges/asset" - log "github.com/thrasher-/gocryptotrader/logger" ) func TestVerify(t *testing.T) { @@ -364,7 +363,7 @@ func TestProcessOrderbook(t *testing.T) { m.Lock() err = base.Process() if err != nil { - log.Error(err) + t.Error(err) catastrophicFailure = true return } diff --git a/exchanges/orderbook/simulator/simulator_test.go b/exchanges/orderbook/simulator/simulator_test.go index 7751a8a7..967e8d84 100644 --- a/exchanges/orderbook/simulator/simulator_test.go +++ b/exchanges/orderbook/simulator/simulator_test.go @@ -1,24 +1,24 @@ -package simulator - -import ( - "testing" - - "github.com/thrasher-/gocryptotrader/currency" - "github.com/thrasher-/gocryptotrader/exchanges/asset" - "github.com/thrasher-/gocryptotrader/exchanges/bitstamp" -) - -func TestSimulate(t *testing.T) { - b := bitstamp.Bitstamp{} - b.SetDefaults() - b.Verbose = false - o, err := b.FetchOrderbook(currency.NewPair(currency.BTC, currency.USD), asset.Spot) - if err != nil { - t.Error(err) - } - - r := o.SimulateOrder(10000000, true) - t.Log(r.Status) - r = o.SimulateOrder(2171, false) - t.Log(r.Status) -} +package simulator + +import ( + "testing" + + "github.com/thrasher-/gocryptotrader/currency" + "github.com/thrasher-/gocryptotrader/exchanges/asset" + "github.com/thrasher-/gocryptotrader/exchanges/bitstamp" +) + +func TestSimulate(t *testing.T) { + b := bitstamp.Bitstamp{} + b.SetDefaults() + b.Verbose = false + o, err := b.FetchOrderbook(currency.NewPair(currency.BTC, currency.USD), asset.Spot) + if err != nil { + t.Error(err) + } + + r := o.SimulateOrder(10000000, true) + t.Log(r.Status) + r = o.SimulateOrder(2171, false) + t.Log(r.Status) +} diff --git a/exchanges/poloniex/poloniex_websocket.go b/exchanges/poloniex/poloniex_websocket.go index e81b05a6..023c506a 100644 --- a/exchanges/poloniex/poloniex_websocket.go +++ b/exchanges/poloniex/poloniex_websocket.go @@ -129,7 +129,7 @@ func (p *Poloniex) WsHandleData() { if len(data) == 2 && chanID != wsHeartbeat { if checkSubscriptionSuccess(data) { if p.Verbose { - log.Debugf("poloniex websocket subscribed to channel successfully. %d", chanID) + log.Debugf(log.ExchangeSys, "poloniex websocket subscribed to channel successfully. %d", chanID) } } else { p.Websocket.DataHandler <- fmt.Errorf("poloniex websocket subscription to channel failed. %d", chanID) @@ -456,7 +456,7 @@ func (p *Poloniex) wsSend(data interface{}) error { return err } if p.Verbose { - log.Debugf("%v sending message to websocket %v", p.Name, data) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", p.Name, data) } return p.WebsocketConn.WriteMessage(websocket.TextMessage, json) } diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index 92e86861..7591c28c 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -130,13 +130,13 @@ func (p *Poloniex) Start(wg *sync.WaitGroup) { // Run implements the Poloniex wrapper func (p *Poloniex) Run() { if p.Verbose { - log.Debugf("%s Websocket: %s (url: %s).\n", p.GetName(), common.IsEnabled(p.Websocket.IsEnabled()), poloniexWebsocketAddress) + log.Debugf(log.ExchangeSys, "%s Websocket: %s (url: %s).\n", p.GetName(), common.IsEnabled(p.Websocket.IsEnabled()), poloniexWebsocketAddress) p.PrintEnabledPairs() } forceUpdate := false if common.StringDataCompare(p.GetAvailablePairs(asset.Spot).Strings(), "BTC_USDT") { - log.Warnf("%s contains invalid pair, forcing upgrade of available currencies.\n", + log.Warnf(log.ExchangeSys, "%s contains invalid pair, forcing upgrade of available currencies.\n", p.Name) forceUpdate = true } @@ -147,7 +147,7 @@ func (p *Poloniex) Run() { err := p.UpdateTradablePairs(forceUpdate) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", p.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", p.Name, err) } } @@ -453,7 +453,7 @@ func (p *Poloniex) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) orderSide := exchange.OrderSide(strings.ToUpper(order.Type)) orderDate, err := time.Parse(poloniexDateLayout, order.Date) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", p.Name, "GetActiveOrders", order.OrderNumber, order.Date) } @@ -495,7 +495,7 @@ func (p *Poloniex) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) orderSide := exchange.OrderSide(strings.ToUpper(order.Type)) orderDate, err := time.Parse(poloniexDateLayout, order.Date) if err != nil { - log.Warnf("Exchange %v Func %v Order %v Could not parse date to unix with value of %v", + log.Warnf(log.ExchangeSys, "Exchange %v Func %v Order %v Could not parse date to unix with value of %v", p.Name, "GetActiveOrders", order.OrderNumber, order.Date) } diff --git a/exchanges/request/request.go b/exchanges/request/request.go index 93c9a5f9..197c7097 100644 --- a/exchanges/request/request.go +++ b/exchanges/request/request.go @@ -281,11 +281,12 @@ func (r *Requester) checkRequest(method, path string, body io.Reader, headers ma // DoRequest performs a HTTP/HTTPS request with the supplied params func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, result interface{}, authRequest, verbose, httpDebug bool) error { if verbose { - log.Debugf("%s exchange request path: %s requires rate limiter: %v", r.Name, path, r.RequiresRateLimiter()) + log.Debugf(log.Global, + "%s exchange request path: %s requires rate limiter: %v", r.Name, path, r.RequiresRateLimiter()) for k, d := range req.Header { - log.Debugf("%s exchange request header [%s]: %s", r.Name, k, d) + log.Debugf(log.Global, "%s exchange request header [%s]: %s", r.Name, k, d) } - log.Debug(body) + log.Debugln(log.Global, body) } var timeoutError error @@ -294,7 +295,7 @@ func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, re if err != nil { if timeoutErr, ok := err.(net.Error); ok && timeoutErr.Timeout() { if verbose { - log.Errorf("%s request has timed-out retrying request, count %d", + log.Errorf(log.ExchangeSys, "%s request has timed-out retrying request, count %d", r.Name, i) } @@ -332,7 +333,7 @@ func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, re reader = resp.Body default: - log.Warnf("%s request response content type differs from JSON; received %v [path: %s]", + log.Warnf(log.ExchangeSys, "%s request response content type differs from JSON; received %v [path: %s]\n", r.Name, resp.Header.Get("Content-Type"), path) reader = resp.Body } @@ -356,17 +357,17 @@ func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, re if httpDebug { dump, err := httputil.DumpResponse(resp, false) if err != nil { - log.Errorf("DumpResponse invalid response: %v:", err) + log.Errorf(log.Global, "DumpResponse invalid response: %v:", err) } - log.Debugf("DumpResponse Headers (%v):\n%s", path, dump) - log.Debugf("DumpResponse Body (%v):\n %s", path, string(contents)) + log.Debugf(log.Global, "DumpResponse Headers (%v):\n%s", path, dump) + log.Debugf(log.Global, "DumpResponse Body (%v):\n %s", path, string(contents)) } resp.Body.Close() if verbose { - log.Debugf("HTTP status: %s, Code: %v", resp.Status, resp.StatusCode) + log.Debugf(log.ExchangeSys, "HTTP status: %s, Code: %v", resp.Status, resp.StatusCode) if !httpDebug { - log.Debugf("%s exchange raw response: %s", r.Name, string(contents)) + log.Debugf(log.ExchangeSys, "%s exchange raw response: %s", r.Name, string(contents)) } } @@ -395,7 +396,7 @@ func (r *Requester) worker() { limit := r.GetRateLimit(x.AuthRequest) diff := limit.GetDuration() - time.Since(r.Cycle) if x.Verbose { - log.Debugf("%s request. Rate limited! Sleeping for %v", r.Name, diff) + log.Debugf(log.ExchangeSys, "%s request. Rate limited! Sleeping for %v", r.Name, diff) } time.Sleep(diff) @@ -407,7 +408,7 @@ func (r *Requester) worker() { r.IncrementRequests(x.AuthRequest) if x.Verbose { - log.Debugf("%s request. No longer rate limited! Doing request", r.Name) + log.Debugf(log.ExchangeSys, "%s request. No longer rate limited! Doing request", r.Name) } err := r.DoRequest(x.Request, x.Path, x.Body, x.Result, x.AuthRequest, x.Verbose, x.HTTPDebugging) @@ -452,9 +453,11 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string, if httpDebugging { dump, err := httputil.DumpRequestOut(req, true) if err != nil { - log.Errorf("DumpRequest invalid response %v:", err) + log.Errorf(log.Global, + "DumpRequest invalid response %v:", err) } - log.Debugf("DumpRequest:\n%s", dump) + log.Debugf(log.Global, + "DumpRequest:\n%s", dump) } if !r.RequiresRateLimiter() { @@ -491,18 +494,18 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string, } if verbose { - log.Debugf("%s request. Attaching new job.", r.Name) + log.Debugf(log.ExchangeSys, "%s request. Attaching new job.", r.Name) } r.Jobs <- newJob r.unlock() if verbose { - log.Debugf("%s request. Waiting for job to complete.", r.Name) + log.Debugf(log.ExchangeSys, "%s request. Waiting for job to complete.", r.Name) } resp := <-newJob.JobResult if verbose { - log.Debugf("%s request. Job complete.", r.Name) + log.Debugf(log.ExchangeSys, "%s request. Job complete.", r.Name) } return resp.Error @@ -563,7 +566,7 @@ func (r *Requester) lock() { wg.Done() select { case <-timer.C: - log.Errorf("Unlocking due to possible error for %s", r.Name) + log.Errorf(log.ExchangeSys, "Unlocking due to possible error for %s", r.Name) r.fifoLock.Unlock() case <-r.disengage: diff --git a/exchanges/ticker/ticker_test.go b/exchanges/ticker/ticker_test.go index d459b677..45b0d206 100644 --- a/exchanges/ticker/ticker_test.go +++ b/exchanges/ticker/ticker_test.go @@ -10,7 +10,6 @@ import ( "github.com/thrasher-/gocryptotrader/currency" "github.com/thrasher-/gocryptotrader/exchanges/asset" - log "github.com/thrasher-/gocryptotrader/logger" ) func TestPriceToString(t *testing.T) { @@ -351,7 +350,7 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers sm.Lock() err = ProcessTicker(newName, &tp, asset.Spot) if err != nil { - log.Error(err) + t.Error(err) catastrophicFailure = true return } diff --git a/exchanges/websocket.go b/exchanges/websocket.go index 0095bb2b..6ff5671f 100644 --- a/exchanges/websocket.go +++ b/exchanges/websocket.go @@ -119,17 +119,17 @@ func (w *Websocket) wsConnectionMonitor() { w.DataHandler <- fmt.Errorf("%v WsConnectionMonitor: websocket disabled, shutting down", w.exchangeName) err := w.Shutdown() if err != nil { - log.Error(err) + log.Error(log.WebsocketMgr, err) } if w.verbose { - log.Debugf("%v WsConnectionMonitor exiting", w.exchangeName) + log.Debugf(log.WebsocketMgr, "%v WsConnectionMonitor exiting", w.exchangeName) } return } w.m.Unlock() err := w.checkConnection() if err != nil { - log.Error(err) + log.Error(log.WebsocketMgr, err) } } } @@ -138,18 +138,18 @@ func (w *Websocket) wsConnectionMonitor() { // Will reconnect on disconnect func (w *Websocket) checkConnection() error { if w.verbose { - log.Debugf("%v checking connection", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v checking connection", w.exchangeName) } switch { case !w.IsConnected() && !w.IsConnecting(): w.m.Lock() defer w.m.Unlock() if w.verbose { - log.Debugf("%v no connection. Attempt %v/%v", w.exchangeName, w.noConnectionChecks, w.noConnectionCheckLimit) + log.Debugf(log.ExchangeSys, "%v no connection. Attempt %v/%v", w.exchangeName, w.noConnectionChecks, w.noConnectionCheckLimit) } if w.noConnectionChecks >= w.noConnectionCheckLimit { if w.verbose { - log.Debugf("%v resetting connection", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v resetting connection", w.exchangeName) } w.connecting = true go w.WebsocketReset() @@ -163,7 +163,7 @@ func (w *Websocket) checkConnection() error { w.reconnectionLimit*int(connectionMonitorDelay.Seconds())) } if w.verbose { - log.Debugf("%v Busy reconnecting", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v Busy reconnecting", w.exchangeName) } w.reconnectionChecks++ default: @@ -200,7 +200,7 @@ func (w *Websocket) Shutdown() error { } if w.verbose { - log.Debugf("%v shutting down websocket channels", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v shutting down websocket channels", w.exchangeName) } timer := time.NewTimer(15 * time.Second) c := make(chan struct{}, 1) @@ -209,7 +209,7 @@ func (w *Websocket) Shutdown() error { close(w.ShutdownC) w.Wg.Wait() if w.verbose { - log.Debugf("%v completed websocket channel shutdown", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v completed websocket channel shutdown", w.exchangeName) } c <- struct{}{} }(c) @@ -229,15 +229,15 @@ func (w *Websocket) WebsocketReset() error { err := w.Shutdown() if err != nil { // does not return here to allow connection to be made if already shut down - log.Errorf("%v shutdown error: %v", w.exchangeName, err) + log.Errorf(log.ExchangeSys, "%v shutdown error: %v", w.exchangeName, err) } - log.Infof("%v reconnecting to websocket", w.exchangeName) + log.Infof(log.WebsocketMgr, "%v reconnecting to websocket", w.exchangeName) w.m.Lock() w.init = true w.m.Unlock() err = w.Connect() if err != nil { - log.Errorf("%v connection error: %v", w.exchangeName, err) + log.Errorf(log.ExchangeSys, "%v connection error: %v", w.exchangeName, err) } return err } @@ -260,7 +260,7 @@ func (w *Websocket) trafficMonitor(wg *sync.WaitGroup) { select { case <-w.ShutdownC: // Returns on shutdown channel close if w.verbose { - log.Debugf("%v trafficMonitor shutdown message received", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v trafficMonitor shutdown message received", w.exchangeName) } return case <-w.TrafficAlert: // Resets timer on traffic @@ -271,13 +271,13 @@ func (w *Websocket) trafficMonitor(wg *sync.WaitGroup) { } w.m.Unlock() if w.verbose { - log.Debugf("%v received a traffic alert", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v received a traffic alert", w.exchangeName) } trafficTimer.Reset(WebsocketTrafficLimitTime) case <-trafficTimer.C: // Falls through when timer runs out newtimer := time.NewTimer(10 * time.Second) // New secondary timer set if w.verbose { - log.Debugf("%v has not received a traffic alert in 5 seconds.", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v has not received a traffic alert in 5 seconds.", w.exchangeName) } w.m.Lock() if w.connected { @@ -296,7 +296,7 @@ func (w *Websocket) trafficMonitor(wg *sync.WaitGroup) { case <-newtimer.C: // If secondary timer runs state timeout is sent to the data handler if w.verbose { - log.Debugf("%v has not received a traffic alert in 15 seconds, exiting", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v has not received a traffic alert in 15 seconds, exiting", w.exchangeName) } w.DataHandler <- fmt.Errorf("trafficMonitor %v", WebsocketStateTimeout) return @@ -308,7 +308,7 @@ func (w *Websocket) trafficMonitor(wg *sync.WaitGroup) { // If not connected dive rt traffic from REST to websocket w.Connected <- struct{}{} if w.verbose { - log.Debugf("%v has received a traffic alert. Setting status to connected", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v has received a traffic alert. Setting status to connected", w.exchangeName) } w.connected = true } @@ -722,7 +722,7 @@ func (w *Websocket) manageSubscriptions() error { w.Wg.Add(1) defer func() { if w.verbose { - log.Debugf("%v ManageSubscriptions exiting", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v ManageSubscriptions exiting", w.exchangeName) } w.Wg.Done() }() @@ -731,13 +731,13 @@ func (w *Websocket) manageSubscriptions() error { case <-w.ShutdownC: w.subscribedChannels = []WebsocketChannelSubscription{} if w.verbose { - log.Debugf("%v shutdown manageSubscriptions", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v shutdown manageSubscriptions", w.exchangeName) } return nil default: time.Sleep(manageSubscriptionsDelay) if w.verbose { - log.Debugf("%v checking subscriptions", w.exchangeName) + log.Debugf(log.ExchangeSys, "%v checking subscriptions", w.exchangeName) } // Subscribe to channels Pending a subscription if w.SupportsFunctionality(WebsocketSubscribeSupported) { @@ -771,7 +771,7 @@ func (w *Websocket) subscribeToChannels() error { } if !channelIsSubscribed { if w.verbose { - log.Debugf("%v Subscribing to %v %v", w.exchangeName, w.channelsToSubscribe[i].Channel, w.channelsToSubscribe[i].Currency.String()) + log.Debugf(log.ExchangeSys, "%v Subscribing to %v %v", w.exchangeName, w.channelsToSubscribe[i].Channel, w.channelsToSubscribe[i].Currency.String()) } err := w.channelSubscriber(w.channelsToSubscribe[i]) if err != nil { diff --git a/exchanges/yobit/yobit.go b/exchanges/yobit/yobit.go index 0e10a69a..3562931c 100644 --- a/exchanges/yobit/yobit.go +++ b/exchanges/yobit/yobit.go @@ -286,7 +286,7 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res hmac := crypto.GetHMAC(crypto.HashSHA512, []byte(encoded), []byte(y.API.Credentials.Secret)) if y.Verbose { - log.Debugf("Sending POST request to %s calling path %s with params %s\n", + log.Debugf(log.ExchangeSys, "Sending POST request to %s calling path %s with params %s\n", apiPrivateURL, path, encoded) diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 65b0898d..fe78f5e8 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -125,7 +125,7 @@ func (y *Yobit) Run() { err := y.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", y.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", y.Name, err) } } diff --git a/exchanges/zb/zb_test.go b/exchanges/zb/zb_test.go index cecc804e..35ff33cb 100644 --- a/exchanges/zb/zb_test.go +++ b/exchanges/zb/zb_test.go @@ -82,7 +82,7 @@ func TestSpotNewOrder(t *testing.T) { if err != nil { t.Errorf("Test failed - ZB SpotNewOrder: %s", err) } else { - fmt.Println(orderid) + t.Log(orderid) } } diff --git a/exchanges/zb/zb_websocket.go b/exchanges/zb/zb_websocket.go index 6e3bcefa..c8aeffc2 100644 --- a/exchanges/zb/zb_websocket.go +++ b/exchanges/zb/zb_websocket.go @@ -364,7 +364,7 @@ func (z *ZB) wsSend(data interface{}) error { return err } if z.Verbose { - log.Debugf("%v sending message to websocket %v", z.Name, string(json)) + log.Debugf(log.ExchangeSys, "%v sending message to websocket %v", z.Name, string(json)) } return z.WebsocketConn.WriteMessage(websocket.TextMessage, json) } @@ -442,7 +442,7 @@ func (z *ZB) wsCreateSubUserKey(assetPerm, entrustPerm, leverPerm, moneyPerm boo func (z *ZB) wsGenerateSignature(request interface{}) string { jsonResponse, err := common.JSONEncode(request) if err != nil { - log.Error(err) + log.Error(log.ExchangeSys, err) } hmac := crypto.GetHMAC(crypto.HashMD5, jsonResponse, diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index 78418169..93b82f79 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -141,7 +141,7 @@ func (z *ZB) Run() { err := z.UpdateTradablePairs(false) if err != nil { - log.Errorf("%s failed to update tradable pairs. Err: %s", z.Name, err) + log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", z.Name, err) } } diff --git a/gctrpc/gen_pb_linux.sh b/gctrpc/gen_pb_linux.sh old mode 100644 new mode 100755 diff --git a/gctrpc/rpc.pb.go b/gctrpc/rpc.pb.go index 33603502..b80231e3 100644 --- a/gctrpc/rpc.pb.go +++ b/gctrpc/rpc.pb.go @@ -4393,6 +4393,155 @@ func (m *WithdrawResponse) GetResult() string { return "" } +type GetLoggerDetailsRequest struct { + Logger string `protobuf:"bytes,1,opt,name=logger,proto3" json:"logger,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetLoggerDetailsRequest) Reset() { *m = GetLoggerDetailsRequest{} } +func (m *GetLoggerDetailsRequest) String() string { return proto.CompactTextString(m) } +func (*GetLoggerDetailsRequest) ProtoMessage() {} +func (*GetLoggerDetailsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{85} +} + +func (m *GetLoggerDetailsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetLoggerDetailsRequest.Unmarshal(m, b) +} +func (m *GetLoggerDetailsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetLoggerDetailsRequest.Marshal(b, m, deterministic) +} +func (m *GetLoggerDetailsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetLoggerDetailsRequest.Merge(m, src) +} +func (m *GetLoggerDetailsRequest) XXX_Size() int { + return xxx_messageInfo_GetLoggerDetailsRequest.Size(m) +} +func (m *GetLoggerDetailsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetLoggerDetailsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetLoggerDetailsRequest proto.InternalMessageInfo + +func (m *GetLoggerDetailsRequest) GetLogger() string { + if m != nil { + return m.Logger + } + return "" +} + +type GetLoggerDetailsResponse struct { + Info bool `protobuf:"varint,1,opt,name=info,proto3" json:"info,omitempty"` + Debug bool `protobuf:"varint,2,opt,name=debug,proto3" json:"debug,omitempty"` + Warn bool `protobuf:"varint,3,opt,name=warn,proto3" json:"warn,omitempty"` + Error bool `protobuf:"varint,4,opt,name=error,proto3" json:"error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetLoggerDetailsResponse) Reset() { *m = GetLoggerDetailsResponse{} } +func (m *GetLoggerDetailsResponse) String() string { return proto.CompactTextString(m) } +func (*GetLoggerDetailsResponse) ProtoMessage() {} +func (*GetLoggerDetailsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{86} +} + +func (m *GetLoggerDetailsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetLoggerDetailsResponse.Unmarshal(m, b) +} +func (m *GetLoggerDetailsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetLoggerDetailsResponse.Marshal(b, m, deterministic) +} +func (m *GetLoggerDetailsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetLoggerDetailsResponse.Merge(m, src) +} +func (m *GetLoggerDetailsResponse) XXX_Size() int { + return xxx_messageInfo_GetLoggerDetailsResponse.Size(m) +} +func (m *GetLoggerDetailsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetLoggerDetailsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetLoggerDetailsResponse proto.InternalMessageInfo + +func (m *GetLoggerDetailsResponse) GetInfo() bool { + if m != nil { + return m.Info + } + return false +} + +func (m *GetLoggerDetailsResponse) GetDebug() bool { + if m != nil { + return m.Debug + } + return false +} + +func (m *GetLoggerDetailsResponse) GetWarn() bool { + if m != nil { + return m.Warn + } + return false +} + +func (m *GetLoggerDetailsResponse) GetError() bool { + if m != nil { + return m.Error + } + return false +} + +type SetLoggerDetailsRequest struct { + Logger string `protobuf:"bytes,1,opt,name=logger,proto3" json:"logger,omitempty"` + Level string `protobuf:"bytes,2,opt,name=level,proto3" json:"level,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetLoggerDetailsRequest) Reset() { *m = SetLoggerDetailsRequest{} } +func (m *SetLoggerDetailsRequest) String() string { return proto.CompactTextString(m) } +func (*SetLoggerDetailsRequest) ProtoMessage() {} +func (*SetLoggerDetailsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{87} +} + +func (m *SetLoggerDetailsRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetLoggerDetailsRequest.Unmarshal(m, b) +} +func (m *SetLoggerDetailsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetLoggerDetailsRequest.Marshal(b, m, deterministic) +} +func (m *SetLoggerDetailsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetLoggerDetailsRequest.Merge(m, src) +} +func (m *SetLoggerDetailsRequest) XXX_Size() int { + return xxx_messageInfo_SetLoggerDetailsRequest.Size(m) +} +func (m *SetLoggerDetailsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SetLoggerDetailsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SetLoggerDetailsRequest proto.InternalMessageInfo + +func (m *SetLoggerDetailsRequest) GetLogger() string { + if m != nil { + return m.Logger + } + return "" +} + +func (m *SetLoggerDetailsRequest) GetLevel() string { + if m != nil { + return m.Level + } + return "" +} + func init() { proto.RegisterType((*GetInfoRequest)(nil), "gctrpc.GetInfoRequest") proto.RegisterType((*GetInfoResponse)(nil), "gctrpc.GetInfoResponse") @@ -4491,278 +4640,289 @@ func init() { proto.RegisterType((*GetCryptocurrencyDepositAddressResponse)(nil), "gctrpc.GetCryptocurrencyDepositAddressResponse") proto.RegisterType((*WithdrawCurrencyRequest)(nil), "gctrpc.WithdrawCurrencyRequest") proto.RegisterType((*WithdrawResponse)(nil), "gctrpc.WithdrawResponse") + proto.RegisterType((*GetLoggerDetailsRequest)(nil), "gctrpc.GetLoggerDetailsRequest") + proto.RegisterType((*GetLoggerDetailsResponse)(nil), "gctrpc.GetLoggerDetailsResponse") + proto.RegisterType((*SetLoggerDetailsRequest)(nil), "gctrpc.SetLoggerDetailsRequest") } func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) } var fileDescriptor_77a6da22d6a3feb1 = []byte{ - // 4250 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3b, 0x4d, 0x6f, 0x25, 0x49, - 0x52, 0xaa, 0x67, 0xb7, 0x3f, 0xe2, 0x3d, 0xfb, 0xd9, 0xe9, 0xaf, 0xd7, 0xaf, 0xed, 0xfe, 0xa8, - 0xd9, 0xe9, 0xe9, 0x9e, 0x0f, 0xf7, 0x4c, 0x4f, 0x8b, 0x1d, 0x76, 0x96, 0x05, 0x8f, 0xa7, 0xc7, - 0xdb, 0xec, 0xec, 0xb4, 0xa9, 0xee, 0xed, 0x96, 0x66, 0xd1, 0x16, 0xe5, 0xaa, 0xb4, 0x5d, 0x74, - 0xbd, 0xaa, 0x9a, 0xaa, 0x7c, 0x76, 0x7b, 0x84, 0x84, 0xb4, 0x12, 0x88, 0x13, 0x1c, 0x56, 0x48, - 0x1c, 0x38, 0x71, 0x44, 0xe2, 0x82, 0x38, 0x81, 0x34, 0xe2, 0x8a, 0x38, 0x72, 0xe1, 0x07, 0x20, - 0x6e, 0x80, 0x84, 0xc4, 0x85, 0x13, 0xca, 0xc8, 0x8f, 0xca, 0x7c, 0x55, 0xef, 0xf9, 0x35, 0xdb, - 0x3b, 0x97, 0xee, 0x57, 0x91, 0x91, 0x11, 0x91, 0x11, 0x91, 0x91, 0x91, 0x91, 0x61, 0x58, 0x2c, - 0xf2, 0x70, 0x37, 0x2f, 0x32, 0x96, 0x91, 0xb9, 0x93, 0x90, 0x15, 0x79, 0xd8, 0xdf, 0x3e, 0xc9, - 0xb2, 0x93, 0x84, 0xde, 0x0b, 0xf2, 0xf8, 0x5e, 0x90, 0xa6, 0x19, 0x0b, 0x58, 0x9c, 0xa5, 0xa5, - 0xc0, 0x72, 0x57, 0x60, 0xf9, 0x80, 0xb2, 0x47, 0xe9, 0x71, 0xe6, 0xd1, 0xaf, 0x86, 0xb4, 0x64, - 0xee, 0xdf, 0xcd, 0x42, 0x57, 0x83, 0xca, 0x3c, 0x4b, 0x4b, 0x4a, 0x36, 0x61, 0x6e, 0x98, 0xb3, - 0x78, 0x40, 0x7b, 0xce, 0x4d, 0xe7, 0xce, 0xa2, 0x27, 0xbf, 0xc8, 0x3d, 0x58, 0x0b, 0xce, 0x82, - 0x38, 0x09, 0x8e, 0x12, 0xea, 0xd3, 0x97, 0xe1, 0x69, 0x90, 0x9e, 0xd0, 0xb2, 0xd7, 0xba, 0xe9, - 0xdc, 0x99, 0xf1, 0x88, 0x1e, 0x7a, 0xa8, 0x46, 0xc8, 0x3b, 0xb0, 0x4a, 0x53, 0x0e, 0x8a, 0x0c, - 0xf4, 0x19, 0x44, 0x5f, 0x91, 0x03, 0x15, 0xf2, 0x03, 0xd8, 0x8c, 0xe8, 0x71, 0x30, 0x4c, 0x98, - 0x7f, 0x9c, 0x15, 0xf4, 0xa5, 0x9f, 0x17, 0xd9, 0x59, 0x1c, 0xd1, 0xa2, 0x37, 0x8b, 0x52, 0xac, - 0xcb, 0xd1, 0xcf, 0xf8, 0xe0, 0xa1, 0x1c, 0x23, 0xf7, 0x61, 0x43, 0xcf, 0x8a, 0x03, 0xe6, 0x87, - 0xc3, 0xa2, 0xa0, 0x69, 0x78, 0xd1, 0xbb, 0x82, 0x93, 0xd6, 0xd4, 0xa4, 0x38, 0x60, 0xfb, 0x72, - 0x88, 0x3c, 0x87, 0x95, 0x72, 0x78, 0x54, 0x5e, 0x94, 0x8c, 0x0e, 0xfc, 0x92, 0x05, 0x6c, 0x58, - 0xf6, 0xe6, 0x6e, 0xce, 0xdc, 0x69, 0xdf, 0x7f, 0x77, 0x57, 0xa8, 0x71, 0x77, 0x44, 0x25, 0xbb, - 0x4f, 0x14, 0xfe, 0x13, 0x44, 0x7f, 0x98, 0xb2, 0xe2, 0xc2, 0xeb, 0x96, 0x36, 0x94, 0x7c, 0x01, - 0x4b, 0x45, 0x1e, 0xfa, 0x34, 0x8d, 0xf2, 0x2c, 0x4e, 0x59, 0xd9, 0x9b, 0x47, 0xaa, 0x77, 0xc7, - 0x51, 0xf5, 0xf2, 0xf0, 0xa1, 0xc2, 0x15, 0x24, 0x3b, 0x85, 0x01, 0xea, 0x7f, 0x02, 0xeb, 0x4d, - 0x8c, 0xc9, 0x0a, 0xcc, 0xbc, 0xa0, 0x17, 0xd2, 0x3a, 0xfc, 0x27, 0x59, 0x87, 0x2b, 0x67, 0x41, - 0x32, 0xa4, 0x68, 0x8c, 0x05, 0x4f, 0x7c, 0x7c, 0xaf, 0xf5, 0x91, 0xd3, 0x7f, 0x0a, 0xab, 0x35, - 0x36, 0x0d, 0x04, 0xee, 0x9a, 0x04, 0xda, 0xf7, 0xd7, 0x94, 0xc8, 0xde, 0xe1, 0xbe, 0x9a, 0x6b, - 0x50, 0x75, 0x6f, 0xc1, 0x8d, 0x03, 0xca, 0xf6, 0xb3, 0xc1, 0x60, 0x98, 0xc6, 0x21, 0xfa, 0x98, - 0x47, 0x93, 0xe0, 0x82, 0x16, 0xa5, 0xf2, 0xac, 0x2f, 0x60, 0xbd, 0x69, 0x9c, 0xf4, 0x60, 0x5e, - 0xda, 0x1e, 0xf9, 0x2f, 0x78, 0xea, 0x93, 0x6c, 0xc3, 0x62, 0x98, 0xa5, 0x29, 0x0d, 0x19, 0x8d, - 0xe4, 0x42, 0x2a, 0x80, 0xfb, 0xc7, 0x2d, 0xb8, 0x39, 0x9e, 0xa7, 0x74, 0xdd, 0xaf, 0x61, 0x33, - 0x34, 0x11, 0xfc, 0x42, 0x62, 0xf4, 0x1c, 0x34, 0xc5, 0xbe, 0x61, 0x8a, 0x89, 0x94, 0x76, 0x1b, - 0x47, 0x85, 0x91, 0x36, 0xc2, 0xa6, 0xb1, 0xfe, 0x31, 0xf4, 0xc7, 0x4f, 0x6a, 0x50, 0xf9, 0x7d, - 0x5b, 0xe5, 0xdb, 0x4a, 0xb4, 0x26, 0x22, 0xa6, 0xee, 0xbf, 0x0b, 0x5b, 0x07, 0x34, 0xa5, 0x45, - 0x1c, 0x6a, 0xe7, 0x90, 0x3a, 0xe7, 0x1a, 0xd4, 0x3e, 0x29, 0x59, 0x55, 0x00, 0xb7, 0x0f, 0xbd, - 0xfa, 0x44, 0xb1, 0x5c, 0x77, 0x13, 0xd6, 0x0f, 0x28, 0xd3, 0x70, 0x6d, 0xc5, 0x6f, 0x1c, 0xd8, - 0xc0, 0x81, 0xf2, 0xa8, 0xbc, 0x10, 0x03, 0x52, 0xd5, 0xbf, 0x07, 0xab, 0x9a, 0x74, 0xa9, 0xb6, - 0x91, 0xd0, 0xf2, 0x87, 0x86, 0x96, 0xeb, 0x33, 0xab, 0xcd, 0x54, 0x9a, 0xbb, 0xa9, 0xda, 0x93, - 0x12, 0xdc, 0xdf, 0x87, 0x8d, 0x46, 0xd4, 0x57, 0xf1, 0x7f, 0xb7, 0x07, 0x9b, 0x07, 0x94, 0x19, - 0x6e, 0x6c, 0x38, 0x68, 0xdb, 0x00, 0x73, 0xbf, 0x2c, 0x59, 0x50, 0xb0, 0xca, 0x2f, 0xe5, 0x27, - 0x79, 0x13, 0x96, 0x93, 0xb8, 0x64, 0x34, 0xf5, 0x83, 0x28, 0x2a, 0x68, 0x29, 0x42, 0xde, 0xa2, - 0xb7, 0x24, 0xa0, 0x7b, 0x02, 0xe8, 0xfe, 0xbd, 0xc3, 0x0d, 0x33, 0xc2, 0x4a, 0x2a, 0xeb, 0x73, - 0x58, 0xac, 0xa2, 0x82, 0x50, 0xd2, 0xae, 0xa1, 0xa4, 0xa6, 0x39, 0xbb, 0x23, 0xa1, 0xa1, 0x22, - 0xd0, 0xff, 0x1d, 0x58, 0x7e, 0xdd, 0x1b, 0xfa, 0x23, 0xe8, 0x4b, 0xdf, 0x50, 0x11, 0xf9, 0x8b, - 0x60, 0x40, 0x95, 0x5f, 0xf5, 0x61, 0x41, 0x05, 0x70, 0xc9, 0x43, 0x7f, 0xbb, 0x3b, 0x70, 0xad, - 0x71, 0xa6, 0x74, 0xac, 0x7b, 0xb0, 0x76, 0x40, 0x99, 0x0e, 0xf3, 0x8a, 0xe2, 0xd8, 0x28, 0xe0, - 0x3e, 0x40, 0x4f, 0x34, 0x26, 0x48, 0x15, 0x6e, 0xc3, 0x62, 0x75, 0x88, 0x48, 0xdf, 0xd6, 0x00, - 0xf7, 0x3e, 0xba, 0xa9, 0x9a, 0xf5, 0xf8, 0xe9, 0xa1, 0x47, 0xc5, 0xb4, 0xab, 0xb0, 0x90, 0xb1, - 0xdc, 0x0f, 0xb3, 0x48, 0x89, 0x3e, 0x9f, 0xb1, 0x7c, 0x3f, 0x8b, 0xa8, 0x74, 0x0d, 0x63, 0x8e, - 0x76, 0x8d, 0xbf, 0x12, 0xa6, 0xb4, 0x87, 0xa4, 0x1c, 0xbf, 0x0d, 0x8b, 0x8a, 0xa0, 0x32, 0xe5, - 0x7b, 0x86, 0x29, 0x9b, 0xe6, 0xec, 0x3e, 0x16, 0x1c, 0xa5, 0x25, 0x17, 0xa4, 0x00, 0x65, 0xff, - 0x63, 0x58, 0xb2, 0x86, 0x2e, 0xf3, 0xec, 0x45, 0xd3, 0x64, 0x0f, 0x60, 0xf3, 0xd3, 0xb8, 0x34, - 0x4f, 0xdc, 0x69, 0xcc, 0xf5, 0xcd, 0x8c, 0xb5, 0x34, 0xeb, 0xe0, 0x27, 0x30, 0x9b, 0x06, 0xfa, - 0xd8, 0xc7, 0xdf, 0xa6, 0xa1, 0x5a, 0x76, 0xb8, 0xee, 0xc1, 0xfc, 0x19, 0x2d, 0x8e, 0xb2, 0x92, - 0xe2, 0x99, 0xbe, 0xe0, 0xa9, 0x4f, 0xf2, 0x06, 0x2c, 0x0d, 0xcb, 0x38, 0x3d, 0xf1, 0xcb, 0x20, - 0x8d, 0x8e, 0xb2, 0x97, 0x78, 0x82, 0x2f, 0x78, 0x1d, 0x04, 0x3e, 0x11, 0x30, 0x72, 0x0b, 0x3a, - 0xa7, 0x8c, 0xe5, 0x3e, 0x4f, 0x2d, 0xb2, 0x21, 0x93, 0x07, 0x76, 0x9b, 0xc3, 0x9e, 0x0a, 0x10, - 0xdf, 0x78, 0x88, 0x32, 0x2c, 0x69, 0x11, 0x9c, 0xd0, 0x94, 0xf5, 0xe6, 0xc4, 0xc6, 0xe3, 0xd0, - 0x9f, 0x28, 0x20, 0xd9, 0x01, 0x40, 0xb4, 0xbc, 0xc8, 0x5e, 0x5e, 0xf4, 0xe6, 0x85, 0x6b, 0x70, - 0xc8, 0x21, 0x07, 0x90, 0xb7, 0xa0, 0x7b, 0x14, 0x94, 0x54, 0xa5, 0x06, 0x31, 0x2d, 0x7b, 0x0b, - 0x88, 0xb3, 0xcc, 0xc1, 0xfb, 0x1a, 0x4a, 0xee, 0xf2, 0xbc, 0x20, 0xcf, 0x33, 0xbe, 0xe9, 0xfd, - 0xa0, 0x2c, 0x29, 0x2b, 0x7b, 0x8b, 0x88, 0xd9, 0xd5, 0xf0, 0x3d, 0x04, 0xf3, 0x15, 0xaa, 0xcc, - 0x26, 0x0f, 0xe2, 0xa2, 0xec, 0x01, 0xe2, 0x75, 0x24, 0xf0, 0x90, 0xc3, 0x38, 0xe3, 0x2a, 0x5f, - 0x12, 0x68, 0x6d, 0xc1, 0x58, 0x83, 0x05, 0xe2, 0x3b, 0xb0, 0x1a, 0x0c, 0xd9, 0x29, 0x4d, 0x19, - 0x8f, 0xfa, 0x9c, 0x79, 0x1e, 0xf7, 0x3a, 0xa8, 0xb3, 0x15, 0x6b, 0x60, 0x2f, 0x8f, 0xdd, 0x73, - 0x58, 0x39, 0xa0, 0xec, 0x69, 0x1c, 0xbe, 0xa0, 0xc5, 0x14, 0x06, 0x27, 0x77, 0x60, 0x96, 0xf3, - 0x96, 0x71, 0x60, 0x5d, 0x9f, 0x32, 0x32, 0x1b, 0xe2, 0x12, 0x78, 0x88, 0xc1, 0xf5, 0x88, 0xab, - 0xf6, 0xd9, 0x45, 0x2e, 0x6c, 0xba, 0xe8, 0x2d, 0x22, 0xe4, 0xe9, 0x45, 0x4e, 0xdd, 0x67, 0xd0, - 0x31, 0x27, 0xf1, 0x0d, 0x19, 0xd1, 0x24, 0x1e, 0xc4, 0x8c, 0x16, 0x6a, 0x43, 0x6a, 0x00, 0xf7, - 0x25, 0xae, 0x5e, 0xe9, 0xb6, 0xf8, 0x9b, 0xfb, 0xf2, 0x57, 0xc3, 0x8c, 0x29, 0xda, 0xe2, 0xc3, - 0xfd, 0xf3, 0x16, 0x2c, 0xab, 0xe5, 0x48, 0x47, 0x54, 0x32, 0x3b, 0x97, 0xca, 0x7c, 0x0b, 0x3a, - 0x49, 0x50, 0x32, 0x7f, 0x98, 0x47, 0x81, 0x4a, 0x1b, 0x66, 0xbc, 0x36, 0x87, 0xfd, 0x44, 0x80, - 0xb8, 0xad, 0x54, 0x56, 0x88, 0x56, 0x90, 0xdc, 0x3b, 0xa1, 0xb9, 0x18, 0x02, 0xb3, 0x7c, 0x0e, - 0x7a, 0xaa, 0xe3, 0xe1, 0x6f, 0x0e, 0x3b, 0x8d, 0x4f, 0x4e, 0xd1, 0x33, 0x1d, 0x0f, 0x7f, 0xf3, - 0x0d, 0x9a, 0x64, 0xe7, 0xe8, 0x87, 0x8e, 0xc7, 0x7f, 0x72, 0xc8, 0x51, 0x1c, 0xa1, 0xdb, 0x39, - 0x1e, 0xff, 0xc9, 0x21, 0x41, 0xf9, 0x02, 0x9d, 0xcc, 0xf1, 0xf8, 0x4f, 0x9e, 0x51, 0x9f, 0x65, - 0xc9, 0x70, 0x40, 0xd1, 0x9f, 0x1c, 0x4f, 0x7e, 0x91, 0x6b, 0xb0, 0x98, 0x17, 0x71, 0x48, 0xfd, - 0x80, 0x9d, 0xa2, 0x0b, 0x39, 0xde, 0x02, 0x02, 0xf6, 0xd8, 0xa9, 0xbb, 0x06, 0xab, 0xda, 0xd0, - 0x3a, 0x32, 0x3d, 0x87, 0x79, 0x09, 0x99, 0x68, 0xf4, 0xf7, 0x61, 0x9e, 0x09, 0xb4, 0x5e, 0x0b, - 0x43, 0xd4, 0xa6, 0xd2, 0xa1, 0xad, 0x69, 0x4f, 0xa1, 0xb9, 0xbf, 0x09, 0xc4, 0xe4, 0x26, 0x0d, - 0x71, 0xb7, 0xa2, 0x23, 0x42, 0x5d, 0xd7, 0xa6, 0x53, 0x56, 0x04, 0xbe, 0xc6, 0x40, 0xff, 0xb8, - 0x88, 0x78, 0x10, 0xc8, 0x5e, 0x7c, 0xab, 0xae, 0xf9, 0x63, 0x58, 0xd2, 0x8c, 0x1f, 0x31, 0x3a, - 0xe0, 0x0a, 0x0f, 0x06, 0xd9, 0x30, 0x65, 0xc8, 0xd3, 0xf1, 0xe4, 0x17, 0xf7, 0x40, 0xd4, 0x2f, - 0xb2, 0x74, 0x3c, 0xf1, 0x41, 0x96, 0xa1, 0x15, 0x47, 0xf2, 0x62, 0xd2, 0x8a, 0x23, 0xf7, 0x7f, - 0x1d, 0x58, 0x35, 0x16, 0xf2, 0xca, 0x4e, 0x59, 0xf3, 0xb8, 0x56, 0x83, 0xc7, 0xdd, 0x85, 0xd9, - 0xa3, 0x38, 0xe2, 0xf7, 0x21, 0xae, 0xd7, 0x0d, 0x45, 0xce, 0x5a, 0x87, 0x87, 0x28, 0x1c, 0x35, - 0x28, 0x5f, 0x94, 0xbd, 0xd9, 0x89, 0xa8, 0x1c, 0xa5, 0xb6, 0x1f, 0xae, 0xd4, 0xf7, 0x83, 0xad, - 0xcb, 0xb9, 0x51, 0x5d, 0x8a, 0x4c, 0x50, 0xd3, 0xd6, 0x9e, 0x17, 0x02, 0x54, 0xc0, 0x89, 0x66, - 0xfd, 0x75, 0x80, 0x4c, 0x63, 0x4a, 0xff, 0xbb, 0x5a, 0x13, 0x5a, 0xbb, 0xa0, 0x81, 0xec, 0xfe, - 0x08, 0x8f, 0x71, 0x93, 0xb9, 0x54, 0xfe, 0x7d, 0x8b, 0xa6, 0xf0, 0x45, 0x52, 0xa3, 0x59, 0x5a, - 0xc4, 0x3e, 0x44, 0x62, 0x7b, 0x61, 0xc8, 0x4d, 0x6f, 0x5c, 0x7a, 0x27, 0x9e, 0x8f, 0xcf, 0x60, - 0x5e, 0xce, 0x90, 0x6e, 0x21, 0x10, 0x5a, 0x71, 0x44, 0x3e, 0x06, 0x30, 0xce, 0x10, 0xb1, 0xae, - 0x6b, 0x4a, 0x06, 0x39, 0x49, 0x79, 0x03, 0xb2, 0x33, 0xd0, 0xdd, 0x63, 0x58, 0x6b, 0x40, 0xe1, - 0xa2, 0xe8, 0x2b, 0xab, 0x14, 0x45, 0x7d, 0x93, 0x1b, 0xd0, 0x66, 0x19, 0x0b, 0x12, 0xbf, 0x4a, - 0x00, 0x1c, 0x0f, 0x10, 0xf4, 0x8c, 0x43, 0x30, 0x40, 0x65, 0x89, 0xf0, 0x5c, 0x1e, 0xa0, 0xb2, - 0x24, 0x72, 0x03, 0x4c, 0x6a, 0xac, 0x45, 0x4b, 0x15, 0x4e, 0x32, 0xd9, 0x3b, 0xb0, 0x10, 0x88, - 0x29, 0x6a, 0x61, 0xdd, 0x91, 0x85, 0x79, 0x1a, 0xc1, 0x25, 0x78, 0x02, 0xed, 0x67, 0xe9, 0x71, - 0x7c, 0xa2, 0xbc, 0xe3, 0x2d, 0x0c, 0x56, 0x0a, 0x56, 0xe5, 0x13, 0x51, 0xc0, 0x02, 0xe4, 0xd6, - 0xf1, 0xf0, 0xb7, 0xfb, 0x47, 0x0e, 0xac, 0x1c, 0x66, 0x05, 0x3b, 0xce, 0x92, 0x38, 0x93, 0xa9, - 0x33, 0x4f, 0x25, 0x54, 0x6a, 0x2d, 0x73, 0x34, 0xf9, 0xc9, 0x23, 0x64, 0x98, 0xc5, 0xa9, 0xf0, - 0xd5, 0x96, 0x54, 0x50, 0x16, 0xa7, 0xdc, 0x55, 0xc9, 0x4d, 0x68, 0x47, 0xb4, 0x0c, 0x8b, 0x38, - 0xe7, 0x57, 0x25, 0x19, 0x16, 0x4c, 0x10, 0x27, 0x7c, 0x14, 0x24, 0x41, 0x1a, 0x52, 0x19, 0xd9, - 0xd5, 0xa7, 0xbb, 0x81, 0xe1, 0x4a, 0x4b, 0x62, 0xdc, 0x5a, 0x6d, 0xb0, 0x5c, 0xca, 0xaf, 0xc1, - 0x62, 0xae, 0x80, 0xd2, 0xfd, 0x7a, 0x4a, 0x43, 0xa3, 0xcb, 0xf1, 0x2a, 0x54, 0x77, 0x9b, 0xe7, - 0xd5, 0x15, 0xbd, 0x27, 0xc3, 0xc1, 0x20, 0x28, 0x2e, 0x14, 0xb7, 0x14, 0x66, 0xf7, 0xb3, 0x38, - 0xe5, 0x8a, 0xe2, 0x8b, 0x52, 0x89, 0x17, 0xff, 0x6d, 0x8a, 0xde, 0xb2, 0x44, 0x37, 0xb5, 0x35, - 0x63, 0x6b, 0xeb, 0x3a, 0x40, 0x4e, 0x8b, 0x90, 0xa6, 0x2c, 0x38, 0x51, 0x2b, 0x36, 0x20, 0xee, - 0x29, 0x90, 0xc7, 0xc7, 0xc7, 0x49, 0x9c, 0x52, 0xce, 0x56, 0x0a, 0x33, 0x41, 0xfb, 0xe3, 0x65, - 0xb0, 0x39, 0xcd, 0xd4, 0x38, 0xfd, 0x18, 0x56, 0x1f, 0xa7, 0x0d, 0x8c, 0x14, 0x39, 0x67, 0x12, - 0xb9, 0x56, 0x8d, 0xdc, 0x0f, 0xa1, 0x63, 0x08, 0x5e, 0x92, 0x8f, 0x60, 0x51, 0xca, 0xa8, 0x93, - 0xf0, 0xbe, 0x8e, 0x06, 0xb5, 0x15, 0x7a, 0x15, 0xb2, 0xfb, 0x17, 0x0e, 0xb4, 0x2b, 0xc9, 0x4a, - 0xf2, 0x00, 0xae, 0x70, 0x75, 0x2b, 0x2a, 0xd7, 0x35, 0x95, 0x0a, 0x67, 0x17, 0xff, 0x15, 0xb9, - 0xbb, 0x40, 0xee, 0x3f, 0x01, 0xa8, 0x80, 0x0d, 0x59, 0xfb, 0x3d, 0xfb, 0xf6, 0x75, 0xb5, 0x4e, - 0x55, 0x89, 0x66, 0x24, 0xf4, 0xff, 0x3c, 0xcb, 0xaf, 0x52, 0x0d, 0xce, 0x22, 0x7d, 0xf0, 0x3d, - 0x68, 0x8b, 0xbd, 0xc0, 0x23, 0x80, 0x12, 0xb8, 0x53, 0x95, 0x0d, 0xe2, 0xd4, 0x03, 0xdc, 0x1b, - 0x38, 0x4e, 0x3e, 0x80, 0x25, 0x14, 0xd6, 0xcf, 0x84, 0x42, 0xe4, 0xc6, 0xb6, 0x27, 0x74, 0x10, - 0x45, 0xaa, 0x8c, 0xe4, 0xb0, 0x61, 0x4d, 0xf1, 0x4b, 0x21, 0x82, 0x3c, 0xa4, 0xbe, 0x6f, 0xdc, - 0x73, 0xc6, 0x49, 0x29, 0x94, 0x25, 0x09, 0xca, 0x31, 0xa1, 0xba, 0xb5, 0xb0, 0x3e, 0x42, 0xee, - 0x41, 0x47, 0x72, 0x44, 0xcd, 0xc8, 0x23, 0xce, 0x96, 0xb1, 0x2d, 0x26, 0x22, 0x02, 0x19, 0xc0, - 0xba, 0x39, 0x41, 0x4b, 0x78, 0x05, 0x27, 0x7e, 0x3c, 0xbd, 0x84, 0x69, 0x4d, 0x40, 0x12, 0xd6, - 0x06, 0xfa, 0xbf, 0x0b, 0xbd, 0x71, 0x0b, 0x6a, 0x30, 0xfb, 0xdb, 0xb6, 0xd9, 0xd7, 0x1b, 0x5c, - 0xb2, 0x34, 0x8b, 0x73, 0x5f, 0xc2, 0xd6, 0x18, 0x61, 0x5e, 0xe1, 0x46, 0x6f, 0x78, 0xaa, 0xe9, - 0x4d, 0x7f, 0xe6, 0x40, 0x7f, 0x2f, 0x8a, 0x6a, 0xc1, 0xa9, 0xba, 0x80, 0x7f, 0xdb, 0x21, 0x77, - 0x07, 0xae, 0x35, 0x0a, 0x24, 0x2b, 0x05, 0x2f, 0x61, 0xc7, 0xa3, 0x83, 0xec, 0x8c, 0x7e, 0xdb, - 0x22, 0xbb, 0x37, 0xe1, 0xfa, 0x38, 0xce, 0x52, 0x36, 0x2c, 0x9d, 0xd9, 0xa5, 0x67, 0x9d, 0x18, - 0xfd, 0x87, 0x03, 0x4b, 0x76, 0x51, 0xfa, 0x75, 0xdd, 0xa3, 0xdf, 0x05, 0x52, 0xd0, 0x92, 0xf9, - 0x45, 0x96, 0x24, 0xfc, 0x3a, 0x1d, 0xd1, 0x24, 0xb8, 0x90, 0xe5, 0xf0, 0x15, 0x3e, 0xe2, 0x89, - 0x81, 0x4f, 0x39, 0x9c, 0x6c, 0xc1, 0x7c, 0x90, 0xc7, 0x3e, 0xf7, 0x1a, 0x71, 0x97, 0x9e, 0x0b, - 0xf2, 0xf8, 0x47, 0xf4, 0x82, 0xb8, 0xb0, 0x24, 0x07, 0xfc, 0x84, 0x9e, 0xd1, 0x04, 0x73, 0xbe, - 0x19, 0xaf, 0x2d, 0x86, 0x3f, 0xe7, 0x20, 0x7e, 0xf7, 0xcd, 0x8b, 0x98, 0xbb, 0x5f, 0x55, 0x77, - 0x9f, 0x47, 0x69, 0xba, 0x12, 0xae, 0x56, 0xe7, 0xfe, 0x14, 0xae, 0x36, 0xe8, 0x42, 0xc6, 0xa8, - 0x1f, 0x40, 0xd7, 0xae, 0xde, 0xab, 0x38, 0xa5, 0xb3, 0x56, 0x6b, 0xa2, 0xb7, 0x7c, 0x6c, 0xd1, - 0x91, 0xd9, 0x27, 0xe2, 0x78, 0x01, 0xd3, 0xf5, 0x22, 0xf7, 0x2b, 0x58, 0xaf, 0x80, 0xfb, 0x59, - 0x7a, 0x46, 0x8b, 0x92, 0x7b, 0x1b, 0x81, 0xd9, 0xe3, 0x22, 0x53, 0xc5, 0x4e, 0xfc, 0xcd, 0xf3, - 0x36, 0x96, 0x49, 0x37, 0x68, 0xb1, 0x8c, 0xe3, 0x14, 0x01, 0x53, 0xa7, 0x14, 0xfe, 0xe6, 0x79, - 0x72, 0x8c, 0x44, 0xa8, 0x8f, 0x63, 0xc2, 0x55, 0xdb, 0x12, 0xc6, 0xb9, 0xb8, 0xcf, 0x30, 0x7d, - 0x34, 0x45, 0x91, 0x6b, 0xfc, 0x0d, 0x68, 0x8b, 0x35, 0xf2, 0x99, 0x6a, 0x7d, 0xdb, 0xd6, 0xfa, - 0x46, 0xc4, 0xf4, 0xe0, 0x58, 0x43, 0xdd, 0xff, 0x6a, 0x41, 0x07, 0x33, 0xd6, 0x4f, 0x29, 0x0b, - 0xe2, 0x64, 0x72, 0x2e, 0x2d, 0x72, 0xd0, 0x96, 0xce, 0x41, 0xdf, 0x80, 0x25, 0xb3, 0x98, 0x71, - 0xa1, 0x2e, 0xb3, 0x46, 0x29, 0xe3, 0x82, 0xbc, 0x09, 0xcb, 0x78, 0xb5, 0xae, 0xb0, 0x84, 0xcf, - 0x2c, 0x21, 0x54, 0xa3, 0xd9, 0x17, 0x81, 0x2b, 0x23, 0x17, 0x01, 0x3e, 0x8c, 0xc9, 0xb4, 0x5f, - 0xc6, 0x91, 0xbe, 0x27, 0x20, 0xe4, 0x49, 0x1c, 0x19, 0xc3, 0x38, 0x7b, 0xde, 0x18, 0xc6, 0xd9, - 0xfc, 0x0e, 0x54, 0x50, 0x51, 0x84, 0xc7, 0xb7, 0xa4, 0x05, 0x74, 0xba, 0x8e, 0x02, 0x3e, 0x8d, - 0x07, 0xf8, 0xd2, 0x24, 0x0b, 0xc7, 0xa2, 0xce, 0x22, 0xbf, 0xaa, 0x6b, 0x1a, 0x98, 0xd7, 0xb4, - 0xea, 0x52, 0xd7, 0xb6, 0x2e, 0x75, 0x37, 0xa0, 0x9d, 0xe5, 0x34, 0xf5, 0xe5, 0x15, 0xbb, 0x23, - 0xb2, 0x07, 0x0e, 0x7a, 0x86, 0x10, 0x59, 0x32, 0x41, 0x9d, 0x97, 0xd3, 0xdc, 0x4b, 0x6d, 0xc5, - 0xb4, 0x46, 0x15, 0xa3, 0x2e, 0x82, 0x33, 0x97, 0x5d, 0x04, 0xdd, 0x3d, 0xcc, 0x8a, 0x15, 0x63, - 0xe9, 0x3e, 0xef, 0xc2, 0x1c, 0xaa, 0x49, 0x79, 0xce, 0xba, 0x75, 0x8d, 0x91, 0x4e, 0xe1, 0x49, - 0x1c, 0xf7, 0x87, 0xf8, 0x3e, 0x87, 0x43, 0xd3, 0x88, 0x7e, 0x15, 0x16, 0x84, 0x55, 0xb4, 0xd7, - 0xcc, 0xe3, 0xf7, 0xa3, 0xc8, 0xfd, 0x57, 0x07, 0xc8, 0x93, 0xe1, 0xd1, 0x20, 0x9e, 0x9e, 0xda, - 0xf4, 0x17, 0x74, 0x02, 0xb3, 0xe8, 0x26, 0xc2, 0x1d, 0xf1, 0xf7, 0x88, 0x87, 0xcc, 0x8e, 0x7a, - 0x48, 0x65, 0xce, 0x2b, 0xcd, 0x77, 0xf4, 0x39, 0xd3, 0xf8, 0x3c, 0xc4, 0x27, 0x31, 0x4d, 0x99, - 0x2f, 0x8b, 0x2d, 0x3c, 0xc4, 0x23, 0xe0, 0x51, 0xe4, 0x3e, 0x81, 0x35, 0x6b, 0x65, 0x52, 0xd3, - 0xb7, 0xa0, 0x23, 0x04, 0xc8, 0x93, 0x20, 0xd4, 0x95, 0xe6, 0x36, 0xc2, 0x0e, 0x11, 0x34, 0x49, - 0x5f, 0x7f, 0xe2, 0xc0, 0xfa, 0x93, 0x78, 0x30, 0x4c, 0x02, 0x46, 0x7f, 0x05, 0x1a, 0xab, 0x96, - 0x3f, 0x63, 0x2d, 0x5f, 0x69, 0x72, 0xb6, 0xd2, 0xa4, 0xfb, 0xdf, 0x0e, 0x6c, 0x8c, 0x88, 0xa2, - 0x73, 0x42, 0xdb, 0x99, 0xc6, 0x14, 0x07, 0x24, 0x92, 0xc1, 0xb4, 0x65, 0x31, 0x7d, 0x03, 0x96, - 0x06, 0x71, 0x1a, 0x0f, 0x86, 0x03, 0x5f, 0xe8, 0x5e, 0xc8, 0xd4, 0x91, 0xc0, 0x43, 0x34, 0x01, - 0x47, 0x0a, 0x5e, 0x1a, 0x48, 0xb3, 0x12, 0x49, 0x00, 0x05, 0xd2, 0xfb, 0xb0, 0x5e, 0xe5, 0xed, - 0xfe, 0x49, 0x10, 0xa7, 0x7e, 0x92, 0x95, 0xa5, 0xb4, 0x31, 0xa9, 0xc6, 0x0e, 0x82, 0x38, 0xfd, - 0x3c, 0x2b, 0x4b, 0x23, 0x08, 0xcc, 0x99, 0x41, 0x80, 0x27, 0x30, 0x2b, 0xcf, 0x4f, 0x83, 0x84, - 0x7e, 0x92, 0x0d, 0x8e, 0x5e, 0xaf, 0xee, 0x6f, 0x41, 0x47, 0xd4, 0xdd, 0x58, 0x50, 0x9c, 0x50, - 0x65, 0x81, 0x36, 0xc2, 0x9e, 0x22, 0xa8, 0xd1, 0x0c, 0xff, 0xe9, 0x00, 0xd9, 0xe7, 0xa9, 0x4c, - 0x32, 0xb5, 0x3f, 0xf0, 0x50, 0x22, 0xee, 0xcd, 0x95, 0x87, 0x2d, 0x4a, 0xc8, 0x23, 0xdb, 0xfd, - 0x66, 0x2c, 0xf7, 0xd3, 0xab, 0x99, 0x7d, 0xc5, 0xe2, 0x58, 0x2d, 0x8e, 0xbf, 0x09, 0xcb, 0xe7, - 0x41, 0x92, 0x50, 0xa6, 0x9f, 0xaf, 0x64, 0x15, 0x5d, 0x40, 0xd5, 0x1d, 0x5c, 0x2d, 0x78, 0xde, - 0x58, 0xf0, 0x06, 0xac, 0x59, 0xeb, 0x95, 0xd9, 0xd0, 0x03, 0xd8, 0x14, 0xe0, 0xbd, 0x24, 0x99, - 0x3a, 0xaa, 0xba, 0x7f, 0xd9, 0x82, 0xad, 0xda, 0x34, 0x9d, 0x36, 0xd8, 0x6e, 0x7c, 0x5b, 0x2f, - 0xb7, 0x79, 0xc2, 0xae, 0xfc, 0x94, 0xb3, 0xfa, 0xff, 0xe8, 0xc0, 0x9c, 0x00, 0x4d, 0xb4, 0xc6, - 0x97, 0x2a, 0x20, 0x48, 0x87, 0x13, 0x37, 0xa2, 0xef, 0x4e, 0xc7, 0x4c, 0xfc, 0x67, 0x3e, 0x59, - 0x8a, 0x48, 0x22, 0x5f, 0x2b, 0x7f, 0x00, 0x2b, 0xa3, 0x08, 0xaf, 0xf4, 0x9c, 0x23, 0xaa, 0x2a, - 0x0f, 0xcf, 0xa8, 0xf1, 0x44, 0xf9, 0x8d, 0x03, 0xdd, 0xfd, 0x2c, 0x8d, 0x62, 0x7e, 0x62, 0x1e, - 0x06, 0x45, 0x30, 0x28, 0xe5, 0x2b, 0xb9, 0x00, 0xa9, 0xb2, 0xbb, 0x06, 0x8c, 0x29, 0x70, 0xee, - 0x00, 0x84, 0xa7, 0x34, 0x7c, 0xe1, 0xcb, 0x8a, 0xa3, 0x78, 0x5a, 0xe7, 0x90, 0x4f, 0xe2, 0xa8, - 0x24, 0xef, 0xc1, 0x5a, 0x35, 0xec, 0x07, 0x69, 0xe4, 0xcb, 0x72, 0x23, 0xbe, 0x40, 0x68, 0xbc, - 0xbd, 0x34, 0xda, 0x2b, 0x5f, 0xe0, 0x3b, 0x89, 0xae, 0xb2, 0xf9, 0x56, 0x08, 0xef, 0x6a, 0xf8, - 0x1e, 0x82, 0xdd, 0xff, 0x71, 0xf0, 0x04, 0x54, 0xab, 0x92, 0xd6, 0xae, 0x0a, 0x6b, 0x58, 0x6f, - 0xb5, 0x4c, 0xd6, 0x1a, 0x31, 0x19, 0x81, 0xd9, 0x98, 0xd1, 0x81, 0x3a, 0x58, 0xf8, 0x6f, 0xf2, - 0x09, 0xac, 0xe8, 0x15, 0xfb, 0x39, 0xaa, 0x45, 0x6e, 0x93, 0xad, 0xea, 0xe2, 0x68, 0x69, 0xcd, - 0xeb, 0x86, 0x23, 0x6a, 0x54, 0xdb, 0xeb, 0xca, 0x54, 0x81, 0x3a, 0x44, 0x6d, 0xcb, 0xf8, 0x24, - 0xbe, 0x84, 0xd4, 0x34, 0x1c, 0x32, 0x1a, 0xc9, 0x54, 0x59, 0x7f, 0xbb, 0xff, 0xee, 0x40, 0x77, - 0x2f, 0x8a, 0x70, 0xdd, 0xd3, 0x84, 0x09, 0xb5, 0xca, 0xd6, 0x25, 0xab, 0x9c, 0xf9, 0x7f, 0xae, - 0xf2, 0x97, 0x0e, 0x22, 0x63, 0x94, 0xe0, 0xba, 0xb0, 0x52, 0xad, 0xb3, 0xd9, 0xbc, 0xee, 0x77, - 0x80, 0x88, 0xeb, 0x95, 0xa5, 0x8e, 0x51, 0xac, 0x0d, 0x58, 0xb3, 0xb0, 0x64, 0xac, 0xf9, 0x0c, - 0xee, 0x1c, 0x50, 0xb6, 0x5f, 0x5c, 0xe4, 0x2c, 0x53, 0xe9, 0xec, 0xa7, 0x34, 0xcf, 0xca, 0x58, - 0x45, 0x2e, 0x3a, 0x55, 0xf4, 0xf9, 0x27, 0x07, 0xee, 0x4e, 0x41, 0x48, 0x2e, 0xe1, 0x67, 0xf5, - 0xfa, 0xd2, 0x6f, 0x99, 0xad, 0x23, 0x53, 0x51, 0xd9, 0xd5, 0x10, 0xf9, 0x82, 0xaf, 0x49, 0xf6, - 0xbf, 0x0f, 0xcb, 0xf6, 0xe0, 0x2b, 0x85, 0x8a, 0x04, 0x6e, 0x5f, 0x22, 0xc4, 0x34, 0x3e, 0x77, - 0x1b, 0x96, 0x43, 0x8b, 0x84, 0x64, 0x34, 0x02, 0x75, 0xf7, 0xe1, 0xad, 0x4b, 0xb9, 0x49, 0xb5, - 0x8d, 0xbd, 0xa1, 0xbb, 0x7f, 0x33, 0x0b, 0x5b, 0xcf, 0x63, 0x76, 0x1a, 0x15, 0xc1, 0xb9, 0xf2, - 0xbe, 0x69, 0x84, 0x1c, 0xb9, 0xbc, 0xb7, 0xea, 0xf5, 0x86, 0xb7, 0x61, 0x35, 0x4b, 0x29, 0xde, - 0x31, 0xfc, 0x3c, 0x28, 0xcb, 0xf3, 0xac, 0x50, 0x67, 0x69, 0x37, 0x4b, 0x29, 0xbf, 0x67, 0x1c, - 0x4a, 0xf0, 0xc8, 0x69, 0x3c, 0x3b, 0x7a, 0x1a, 0xaf, 0xc0, 0x4c, 0x1e, 0xa7, 0xf2, 0xcd, 0x84, - 0xff, 0xe4, 0x67, 0x27, 0x2b, 0x82, 0xc8, 0xa0, 0x2c, 0xcf, 0x4e, 0x84, 0x6a, 0xba, 0x66, 0x15, - 0x7f, 0x7e, 0xa4, 0x8a, 0x6f, 0xe8, 0x64, 0xc1, 0xae, 0x5a, 0xdc, 0x80, 0xb6, 0xfc, 0xe9, 0xb3, - 0xe0, 0x44, 0x5e, 0x81, 0x40, 0x82, 0x9e, 0x06, 0x27, 0x46, 0xb6, 0x06, 0x56, 0xb6, 0xb6, 0x03, - 0x70, 0x4c, 0xa9, 0x6f, 0x5d, 0x86, 0x16, 0x8f, 0x29, 0x15, 0x41, 0x97, 0xa7, 0xca, 0x47, 0x41, - 0xfa, 0xc2, 0xc7, 0x1a, 0x44, 0x47, 0x88, 0xc3, 0x01, 0x5f, 0x04, 0x03, 0xcc, 0x89, 0x71, 0x50, - 0xc9, 0xb4, 0x24, 0x34, 0xca, 0x61, 0x7b, 0x55, 0x35, 0x05, 0x51, 0xc2, 0x98, 0x5d, 0xf4, 0x96, - 0xab, 0xf9, 0xfb, 0x31, 0xbb, 0xd0, 0xf3, 0x51, 0x67, 0xc5, 0x45, 0xaf, 0x5b, 0xcd, 0xdf, 0x17, - 0x20, 0x2e, 0x5e, 0x79, 0x1e, 0x1f, 0x53, 0xd1, 0x74, 0xb1, 0x22, 0xdb, 0x90, 0x38, 0x64, 0x3f, - 0x8b, 0x30, 0x8d, 0x3c, 0x8f, 0x0b, 0xe3, 0x72, 0xba, 0x2a, 0xae, 0xb0, 0x1c, 0xa8, 0x5c, 0xc3, - 0x7d, 0x1b, 0x56, 0x94, 0xbb, 0x98, 0x7d, 0x89, 0x05, 0x2d, 0x87, 0x09, 0x53, 0x7d, 0x89, 0xe2, - 0xeb, 0xfe, 0x3f, 0xdc, 0x82, 0xe5, 0x83, 0x4c, 0x38, 0xe8, 0x53, 0x6e, 0x97, 0x82, 0x3c, 0x86, - 0x79, 0xd9, 0x6c, 0x47, 0x36, 0x6b, 0xdd, 0x77, 0xe8, 0x75, 0xfd, 0xad, 0x31, 0x5d, 0x79, 0xee, - 0xda, 0xcf, 0xff, 0xe5, 0xdf, 0x7e, 0xd1, 0x5a, 0x22, 0xed, 0x7b, 0x67, 0x1f, 0xdc, 0x3b, 0xa1, - 0x2c, 0xe6, 0x54, 0x4e, 0x61, 0xc9, 0xea, 0x8f, 0x22, 0xdb, 0x56, 0x8f, 0xd3, 0x48, 0xdb, 0x54, - 0x7f, 0x67, 0x62, 0x07, 0x94, 0xdb, 0x47, 0x16, 0xeb, 0x84, 0x48, 0x16, 0x25, 0xa2, 0x08, 0xc2, - 0x5f, 0x41, 0xf7, 0x21, 0x56, 0x86, 0x34, 0x55, 0x72, 0xa3, 0xa2, 0xd6, 0xd8, 0xf7, 0xd5, 0xbf, - 0x39, 0x1e, 0x41, 0x72, 0xbc, 0x86, 0x1c, 0x37, 0xc8, 0x1a, 0xe7, 0x28, 0x2a, 0x4f, 0xba, 0xdf, - 0x8a, 0x94, 0xb0, 0x22, 0x3b, 0x49, 0x5e, 0x2b, 0xcf, 0x6d, 0xe4, 0xb9, 0x49, 0xd6, 0x39, 0xcf, - 0x48, 0x30, 0xa8, 0x98, 0x66, 0x78, 0xb1, 0x35, 0x3b, 0x9f, 0xc8, 0xf5, 0xb1, 0x2d, 0x51, 0x82, - 0xe5, 0x8d, 0x4b, 0x5a, 0xa6, 0xec, 0x55, 0x9e, 0x50, 0x8e, 0xab, 0xbb, 0xa6, 0xc8, 0x2f, 0x1c, - 0x2c, 0xe2, 0x35, 0xf6, 0xe8, 0x91, 0xb7, 0x2e, 0x6f, 0x0c, 0x14, 0x32, 0xdc, 0x99, 0xb6, 0x83, - 0xd0, 0xfd, 0x0e, 0x0a, 0x73, 0x9d, 0x6c, 0x4b, 0x61, 0xac, 0xae, 0x41, 0xd5, 0x97, 0x48, 0x42, - 0xe8, 0x98, 0xed, 0x4e, 0xe4, 0x5a, 0x43, 0x2f, 0x91, 0x66, 0xbe, 0xdd, 0x3c, 0x28, 0x19, 0xf6, - 0x90, 0x21, 0x21, 0x2b, 0x92, 0xa1, 0xee, 0x8e, 0x22, 0x5f, 0x43, 0x77, 0xa4, 0x55, 0x88, 0xb8, - 0x23, 0xe6, 0x6b, 0x68, 0xfb, 0xea, 0xbf, 0x31, 0x11, 0x47, 0x72, 0xbd, 0x8e, 0x5c, 0x7b, 0xee, - 0x9a, 0x61, 0x65, 0xc5, 0xf9, 0x7b, 0xce, 0xdb, 0xa4, 0x44, 0x3b, 0x9b, 0xfd, 0x46, 0x53, 0xf1, - 0xbe, 0xd1, 0xb0, 0x54, 0x6b, 0x9b, 0x8e, 0xda, 0x5a, 0xf1, 0xc4, 0xed, 0x5a, 0x62, 0x37, 0x83, - 0xd1, 0x8b, 0x85, 0x91, 0x67, 0x1a, 0xbe, 0x3b, 0xcd, 0xbd, 0x5c, 0xb2, 0x9d, 0xac, 0xb6, 0x73, - 0x15, 0xd7, 0x8c, 0xe5, 0xa4, 0xb4, 0x5a, 0xdd, 0x24, 0x53, 0xdb, 0xab, 0x1b, 0x9a, 0xcd, 0x1a, - 0x57, 0x6a, 0x76, 0x8f, 0x8d, 0x5d, 0x69, 0xc6, 0xf2, 0x92, 0xbc, 0x84, 0x65, 0x11, 0x2e, 0x5e, - 0xbf, 0x65, 0x77, 0x90, 0xef, 0x96, 0x4b, 0xaa, 0x98, 0x61, 0x1a, 0xf6, 0x39, 0x2c, 0xea, 0x8e, - 0x11, 0xd2, 0x33, 0x16, 0x61, 0xf5, 0x26, 0xf5, 0xc7, 0x74, 0x9e, 0x28, 0x6f, 0x75, 0x97, 0xe4, - 0xaa, 0x44, 0x1f, 0x09, 0x27, 0xfc, 0x53, 0x80, 0xaa, 0x15, 0x85, 0x5c, 0xad, 0x51, 0xd6, 0x9a, - 0xeb, 0x37, 0x0d, 0xa9, 0x86, 0x56, 0x24, 0xbf, 0x42, 0x96, 0x2d, 0xf2, 0x6a, 0xbf, 0xe9, 0xea, - 0x88, 0xb5, 0xdf, 0x46, 0x9b, 0x57, 0xfa, 0xe3, 0xbb, 0x16, 0x94, 0x51, 0x5c, 0xb5, 0xd9, 0xf4, - 0xcd, 0x87, 0xaf, 0xe0, 0x04, 0x4f, 0x0b, 0xa3, 0x5d, 0x62, 0xbb, 0x89, 0x4b, 0xe3, 0x69, 0x51, - 0xef, 0x7d, 0x70, 0xaf, 0x22, 0xab, 0x35, 0xb2, 0x3a, 0xca, 0xaa, 0x24, 0x2f, 0xb0, 0xa1, 0xdf, - 0x78, 0xed, 0x27, 0x26, 0xad, 0x7a, 0xeb, 0x43, 0xff, 0xfa, 0xb8, 0xe1, 0x31, 0x27, 0x93, 0x4c, - 0x8e, 0x70, 0x53, 0x09, 0x83, 0x8b, 0x37, 0x7e, 0xcb, 0xe0, 0x56, 0x2b, 0x40, 0xff, 0x6a, 0xc3, - 0x88, 0xa4, 0xbe, 0x81, 0xd4, 0xbb, 0x64, 0x49, 0x87, 0x44, 0xa4, 0x25, 0x6c, 0xa2, 0x1f, 0x5f, - 0x2c, 0x9b, 0x8c, 0xbe, 0xd0, 0x5b, 0x31, 0xb0, 0xf6, 0x4e, 0x5f, 0x8b, 0x81, 0xfa, 0x25, 0x9e, - 0xfc, 0xa1, 0xfd, 0xe0, 0xaf, 0x1e, 0x20, 0xdd, 0x89, 0x2f, 0x86, 0xb5, 0xdd, 0x32, 0xf6, 0x55, - 0xd1, 0xbd, 0x81, 0x9c, 0xaf, 0x92, 0xad, 0x51, 0xce, 0xf2, 0x85, 0x92, 0xfc, 0xdc, 0x81, 0xb5, - 0x86, 0xf7, 0xaf, 0x4a, 0x82, 0xf1, 0xaf, 0x75, 0x95, 0x04, 0x93, 0x1e, 0xd0, 0x5c, 0x94, 0x60, - 0xdb, 0x45, 0x09, 0x82, 0x28, 0xd2, 0x12, 0xc8, 0x5c, 0x8f, 0x7b, 0xe6, 0x9f, 0x3a, 0xb0, 0xd9, - 0xfc, 0xd6, 0x45, 0xde, 0xd4, 0x2d, 0xc2, 0x93, 0x5e, 0xe1, 0xfa, 0xb7, 0x2f, 0x43, 0x93, 0xd2, - 0xbc, 0x89, 0xd2, 0xdc, 0x70, 0xfb, 0x5c, 0x9a, 0x02, 0x71, 0x9b, 0x04, 0x3a, 0xc7, 0x02, 0x81, - 0xfd, 0x9a, 0x44, 0x8c, 0xdc, 0xa2, 0xf9, 0xd1, 0xad, 0x7f, 0x6b, 0x02, 0x86, 0x1d, 0xbe, 0xc8, - 0x86, 0x34, 0x08, 0x3e, 0xc1, 0xe8, 0x67, 0x29, 0xb9, 0x47, 0xab, 0xd7, 0x1a, 0x6b, 0x8f, 0xd6, - 0x1e, 0xa0, 0xac, 0x3d, 0x5a, 0x7f, 0x13, 0xaa, 0xed, 0x51, 0x64, 0x86, 0xef, 0x43, 0xe4, 0x4b, - 0xdc, 0x36, 0xb2, 0x3a, 0xd5, 0x1b, 0xdd, 0xea, 0x65, 0xd3, 0xb6, 0xb1, 0xeb, 0x4f, 0xb5, 0x50, - 0x29, 0x8a, 0x5e, 0x5c, 0x7b, 0x1e, 0x2c, 0x28, 0x74, 0xb2, 0x35, 0x4a, 0x40, 0x51, 0x6e, 0x7c, - 0x60, 0x70, 0xb7, 0x90, 0xe8, 0xaa, 0xdb, 0x31, 0x89, 0x72, 0x9a, 0x47, 0xd0, 0x36, 0x8a, 0xe9, - 0x44, 0x07, 0xd9, 0xfa, 0xdb, 0x41, 0xff, 0x5a, 0xe3, 0x98, 0x1d, 0x4a, 0xdc, 0x2e, 0x67, 0x50, - 0x22, 0x82, 0xe6, 0xf1, 0xfb, 0xb0, 0x64, 0xd5, 0xb3, 0x2b, 0xe5, 0x37, 0x55, 0xdc, 0x2b, 0xe5, - 0x37, 0x16, 0xc1, 0x55, 0xa2, 0xe9, 0xa2, 0xf2, 0x4b, 0x89, 0xa2, 0x79, 0xfd, 0x0c, 0x16, 0x75, - 0x19, 0xb9, 0xd2, 0xff, 0x68, 0x65, 0xf9, 0x32, 0x1e, 0x96, 0x0d, 0xce, 0xf9, 0xe4, 0xa3, 0x6c, - 0x70, 0x24, 0xf5, 0x65, 0x14, 0x49, 0x2b, 0x7d, 0xd5, 0x2b, 0xc5, 0x95, 0xbe, 0x9a, 0xaa, 0xaa, - 0x96, 0xbe, 0x42, 0x44, 0xd0, 0x6b, 0x28, 0xa0, 0x3b, 0x52, 0x9c, 0xac, 0xd2, 0x8a, 0xe6, 0x52, - 0x6c, 0x95, 0x56, 0x8c, 0xa9, 0x6a, 0xda, 0x89, 0x9b, 0xe0, 0x17, 0x24, 0x49, 0xe5, 0x5b, 0x22, - 0xdc, 0x8b, 0xd2, 0x9d, 0xe5, 0xb7, 0x56, 0x8d, 0xd2, 0xf2, 0x5b, 0xbb, 0xce, 0x57, 0x0b, 0xf7, - 0x54, 0xd0, 0x7a, 0x06, 0x0b, 0xaa, 0x66, 0x54, 0x39, 0xed, 0x48, 0xb5, 0xac, 0xdf, 0xab, 0x0f, - 0x48, 0xaa, 0x96, 0xe3, 0x06, 0x51, 0x84, 0x54, 0xa5, 0x21, 0x8c, 0x0a, 0x52, 0x65, 0x88, 0x7a, - 0xf1, 0xa9, 0x32, 0x44, 0x53, 0xc9, 0xc9, 0x32, 0x84, 0x88, 0x5c, 0x9a, 0xc7, 0xdf, 0x3a, 0x70, - 0xeb, 0xd2, 0x02, 0x10, 0x79, 0xff, 0x15, 0x6a, 0x45, 0x42, 0xa0, 0x0f, 0x5e, 0xb9, 0xba, 0xe4, - 0xde, 0x41, 0x31, 0x5d, 0x77, 0x47, 0x1d, 0xa6, 0x38, 0x2d, 0x12, 0xe8, 0xba, 0xd4, 0xc4, 0x85, - 0xfe, 0x6b, 0x47, 0xfc, 0xb9, 0xd6, 0x04, 0xba, 0x64, 0x77, 0x4a, 0x01, 0x94, 0xc0, 0xf7, 0xa6, - 0xc6, 0x97, 0xe2, 0xde, 0x46, 0x71, 0x6f, 0xba, 0xd7, 0x26, 0x88, 0xcb, 0x85, 0xfd, 0x03, 0xb8, - 0xa6, 0x0b, 0x45, 0x16, 0xdd, 0xcf, 0x86, 0x69, 0x54, 0x56, 0xf7, 0xd2, 0x31, 0xd5, 0xa4, 0xca, - 0x71, 0x46, 0xeb, 0x07, 0xf6, 0xf9, 0x78, 0x2e, 0x47, 0x85, 0x18, 0xc7, 0x9c, 0x36, 0xe7, 0x9e, - 0xc3, 0xaa, 0x9a, 0xf7, 0x59, 0x1c, 0xb0, 0x5f, 0x9a, 0xe7, 0x4d, 0xe4, 0xd9, 0x77, 0x37, 0x4c, - 0x9e, 0xc7, 0x71, 0xc0, 0x14, 0xc7, 0xa3, 0x39, 0xfc, 0xd3, 0xcc, 0x0f, 0xff, 0x2f, 0x00, 0x00, - 0xff, 0xff, 0x26, 0x18, 0xb3, 0x56, 0xcd, 0x39, 0x00, 0x00, + // 4379 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3b, 0x4d, 0x6f, 0x1c, 0x57, + 0x72, 0xe8, 0x21, 0xc5, 0x8f, 0x9a, 0x21, 0x67, 0xf8, 0xf8, 0x35, 0x1a, 0x91, 0xfa, 0x68, 0xad, + 0x64, 0x49, 0xb6, 0x29, 0x5b, 0x16, 0xb2, 0x8e, 0xbd, 0xd9, 0x84, 0xa6, 0x65, 0xae, 0xb2, 0x5e, + 0x8b, 0x69, 0x6a, 0x25, 0xc0, 0x1b, 0xec, 0xa4, 0xd9, 0xfd, 0x38, 0xec, 0xa8, 0xa7, 0xbb, 0xdd, + 0xdd, 0x43, 0x8a, 0x46, 0x80, 0x00, 0x0b, 0x24, 0xc8, 0x29, 0x39, 0x2c, 0x02, 0xe4, 0x90, 0x53, + 0x4e, 0x41, 0x80, 0x5c, 0x82, 0x9c, 0x72, 0x30, 0x72, 0x0d, 0x72, 0xcc, 0x25, 0x3f, 0x20, 0xc8, + 0x2d, 0x09, 0x10, 0x20, 0x97, 0x9c, 0x82, 0x57, 0xef, 0xa3, 0xdf, 0xeb, 0xee, 0x19, 0x0e, 0xd7, + 0x8a, 0x2f, 0xd2, 0x74, 0xbd, 0x7a, 0x55, 0xf5, 0xaa, 0xea, 0xd5, 0xab, 0x57, 0xaf, 0x08, 0x8b, + 0x69, 0xe2, 0xed, 0x24, 0x69, 0x9c, 0xc7, 0x64, 0x6e, 0xe0, 0xe5, 0x69, 0xe2, 0xf5, 0xb6, 0x06, + 0x71, 0x3c, 0x08, 0xe9, 0x43, 0x37, 0x09, 0x1e, 0xba, 0x51, 0x14, 0xe7, 0x6e, 0x1e, 0xc4, 0x51, + 0xc6, 0xb1, 0xec, 0x0e, 0x2c, 0xef, 0xd3, 0xfc, 0x69, 0x74, 0x1c, 0x3b, 0xf4, 0xab, 0x11, 0xcd, + 0x72, 0xfb, 0xef, 0x67, 0xa1, 0xad, 0x40, 0x59, 0x12, 0x47, 0x19, 0x25, 0x1b, 0x30, 0x37, 0x4a, + 0xf2, 0x60, 0x48, 0xbb, 0xd6, 0x4d, 0xeb, 0xde, 0xa2, 0x23, 0xbe, 0xc8, 0x43, 0x58, 0x75, 0x4f, + 0xdd, 0x20, 0x74, 0x8f, 0x42, 0xda, 0xa7, 0xaf, 0xbd, 0x13, 0x37, 0x1a, 0xd0, 0xac, 0xdb, 0xb8, + 0x69, 0xdd, 0x9b, 0x71, 0x88, 0x1a, 0x7a, 0x22, 0x47, 0xc8, 0xdb, 0xb0, 0x42, 0x23, 0x06, 0xf2, + 0x35, 0xf4, 0x19, 0x44, 0xef, 0x88, 0x81, 0x02, 0xf9, 0x31, 0x6c, 0xf8, 0xf4, 0xd8, 0x1d, 0x85, + 0x79, 0xff, 0x38, 0x4e, 0xe9, 0xeb, 0x7e, 0x92, 0xc6, 0xa7, 0x81, 0x4f, 0xd3, 0xee, 0x2c, 0x4a, + 0xb1, 0x26, 0x46, 0x3f, 0x63, 0x83, 0x07, 0x62, 0x8c, 0x3c, 0x82, 0x75, 0x35, 0x2b, 0x70, 0xf3, + 0xbe, 0x37, 0x4a, 0x53, 0x1a, 0x79, 0xe7, 0xdd, 0x2b, 0x38, 0x69, 0x55, 0x4e, 0x0a, 0xdc, 0x7c, + 0x4f, 0x0c, 0x91, 0x97, 0xd0, 0xc9, 0x46, 0x47, 0xd9, 0x79, 0x96, 0xd3, 0x61, 0x3f, 0xcb, 0xdd, + 0x7c, 0x94, 0x75, 0xe7, 0x6e, 0xce, 0xdc, 0x6b, 0x3e, 0x7a, 0x67, 0x87, 0xab, 0x71, 0xa7, 0xa4, + 0x92, 0x9d, 0x43, 0x89, 0x7f, 0x88, 0xe8, 0x4f, 0xa2, 0x3c, 0x3d, 0x77, 0xda, 0x99, 0x09, 0x25, + 0x5f, 0xc0, 0x52, 0x9a, 0x78, 0x7d, 0x1a, 0xf9, 0x49, 0x1c, 0x44, 0x79, 0xd6, 0x9d, 0x47, 0xaa, + 0xf7, 0xc7, 0x51, 0x75, 0x12, 0xef, 0x89, 0xc4, 0xe5, 0x24, 0x5b, 0xa9, 0x06, 0xea, 0x7d, 0x02, + 0x6b, 0x75, 0x8c, 0x49, 0x07, 0x66, 0x5e, 0xd1, 0x73, 0x61, 0x1d, 0xf6, 0x93, 0xac, 0xc1, 0x95, + 0x53, 0x37, 0x1c, 0x51, 0x34, 0xc6, 0x82, 0xc3, 0x3f, 0x3e, 0x6a, 0x7c, 0x68, 0xf5, 0x9e, 0xc3, + 0x4a, 0x85, 0x4d, 0x0d, 0x81, 0xfb, 0x3a, 0x81, 0xe6, 0xa3, 0x55, 0x29, 0xb2, 0x73, 0xb0, 0x27, + 0xe7, 0x6a, 0x54, 0xed, 0x5b, 0x70, 0x63, 0x9f, 0xe6, 0x7b, 0xf1, 0x70, 0x38, 0x8a, 0x02, 0x0f, + 0x7d, 0xcc, 0xa1, 0xa1, 0x7b, 0x4e, 0xd3, 0x4c, 0x7a, 0xd6, 0x17, 0xb0, 0x56, 0x37, 0x4e, 0xba, + 0x30, 0x2f, 0x6c, 0x8f, 0xfc, 0x17, 0x1c, 0xf9, 0x49, 0xb6, 0x60, 0xd1, 0x8b, 0xa3, 0x88, 0x7a, + 0x39, 0xf5, 0xc5, 0x42, 0x0a, 0x80, 0xfd, 0xc7, 0x0d, 0xb8, 0x39, 0x9e, 0xa7, 0x70, 0xdd, 0xaf, + 0x61, 0xc3, 0xd3, 0x11, 0xfa, 0xa9, 0xc0, 0xe8, 0x5a, 0x68, 0x8a, 0x3d, 0xcd, 0x14, 0x13, 0x29, + 0xed, 0xd4, 0x8e, 0x72, 0x23, 0xad, 0x7b, 0x75, 0x63, 0xbd, 0x63, 0xe8, 0x8d, 0x9f, 0x54, 0xa3, + 0xf2, 0x47, 0xa6, 0xca, 0xb7, 0xa4, 0x68, 0x75, 0x44, 0x74, 0xdd, 0x7f, 0x1f, 0x36, 0xf7, 0x69, + 0x44, 0xd3, 0xc0, 0x53, 0xce, 0x21, 0x74, 0xce, 0x34, 0xa8, 0x7c, 0x52, 0xb0, 0x2a, 0x00, 0x76, + 0x0f, 0xba, 0xd5, 0x89, 0x7c, 0xb9, 0xf6, 0x06, 0xac, 0xed, 0xd3, 0x5c, 0xc1, 0x95, 0x15, 0xbf, + 0xb1, 0x60, 0x1d, 0x07, 0xb2, 0xa3, 0xec, 0x9c, 0x0f, 0x08, 0x55, 0xff, 0x1e, 0xac, 0x28, 0xd2, + 0x99, 0xdc, 0x46, 0x5c, 0xcb, 0x1f, 0x68, 0x5a, 0xae, 0xce, 0x2c, 0x36, 0x53, 0xa6, 0xef, 0xa6, + 0x62, 0x4f, 0x0a, 0x70, 0x6f, 0x0f, 0xd6, 0x6b, 0x51, 0x2f, 0xe3, 0xff, 0x76, 0x17, 0x36, 0xf6, + 0x69, 0xae, 0xb9, 0xb1, 0xe6, 0xa0, 0x4d, 0x0d, 0xcc, 0xfc, 0x32, 0xcb, 0xdd, 0x34, 0x2f, 0xfc, + 0x52, 0x7c, 0x92, 0x3b, 0xb0, 0x1c, 0x06, 0x59, 0x4e, 0xa3, 0xbe, 0xeb, 0xfb, 0x29, 0xcd, 0x78, + 0xc8, 0x5b, 0x74, 0x96, 0x38, 0x74, 0x97, 0x03, 0xed, 0x7f, 0xb0, 0x98, 0x61, 0x4a, 0xac, 0x84, + 0xb2, 0x3e, 0x87, 0xc5, 0x22, 0x2a, 0x70, 0x25, 0xed, 0x68, 0x4a, 0xaa, 0x9b, 0xb3, 0x53, 0x0a, + 0x0d, 0x05, 0x81, 0xde, 0xef, 0xc0, 0xf2, 0x9b, 0xde, 0xd0, 0x1f, 0x42, 0x4f, 0xf8, 0x86, 0x8c, + 0xc8, 0x5f, 0xb8, 0x43, 0x2a, 0xfd, 0xaa, 0x07, 0x0b, 0x32, 0x80, 0x0b, 0x1e, 0xea, 0xdb, 0xde, + 0x86, 0x6b, 0xb5, 0x33, 0x85, 0x63, 0x3d, 0x84, 0xd5, 0x7d, 0x9a, 0xab, 0x30, 0x2f, 0x29, 0x8e, + 0x8d, 0x02, 0xf6, 0x63, 0xf4, 0x44, 0x6d, 0x82, 0x50, 0xe1, 0x16, 0x2c, 0x16, 0x87, 0x88, 0xf0, + 0x6d, 0x05, 0xb0, 0x1f, 0xa1, 0x9b, 0xca, 0x59, 0xcf, 0x9e, 0x1f, 0x38, 0x94, 0x4f, 0xbb, 0x0a, + 0x0b, 0x71, 0x9e, 0xf4, 0xbd, 0xd8, 0x97, 0xa2, 0xcf, 0xc7, 0x79, 0xb2, 0x17, 0xfb, 0x54, 0xb8, + 0x86, 0x36, 0x47, 0xb9, 0xc6, 0x5f, 0x71, 0x53, 0x9a, 0x43, 0x42, 0x8e, 0xdf, 0x86, 0x45, 0x49, + 0x50, 0x9a, 0xf2, 0x5d, 0xcd, 0x94, 0x75, 0x73, 0x76, 0x9e, 0x71, 0x8e, 0xc2, 0x92, 0x0b, 0x42, + 0x80, 0xac, 0xf7, 0x31, 0x2c, 0x19, 0x43, 0x17, 0x79, 0xf6, 0xa2, 0x6e, 0xb2, 0xc7, 0xb0, 0xf1, + 0x69, 0x90, 0xe9, 0x27, 0xee, 0x34, 0xe6, 0xfa, 0x66, 0xc6, 0x58, 0x9a, 0x71, 0xf0, 0x13, 0x98, + 0x8d, 0x5c, 0x75, 0xec, 0xe3, 0x6f, 0xdd, 0x50, 0x0d, 0x33, 0x5c, 0x77, 0x61, 0xfe, 0x94, 0xa6, + 0x47, 0x71, 0x46, 0xf1, 0x4c, 0x5f, 0x70, 0xe4, 0x27, 0xb9, 0x0d, 0x4b, 0xa3, 0x2c, 0x88, 0x06, + 0xfd, 0xcc, 0x8d, 0xfc, 0xa3, 0xf8, 0x35, 0x9e, 0xe0, 0x0b, 0x4e, 0x0b, 0x81, 0x87, 0x1c, 0x46, + 0x6e, 0x41, 0xeb, 0x24, 0xcf, 0x93, 0x3e, 0x4b, 0x2d, 0xe2, 0x51, 0x2e, 0x0e, 0xec, 0x26, 0x83, + 0x3d, 0xe7, 0x20, 0xb6, 0xf1, 0x10, 0x65, 0x94, 0xd1, 0xd4, 0x1d, 0xd0, 0x28, 0xef, 0xce, 0xf1, + 0x8d, 0xc7, 0xa0, 0x3f, 0x95, 0x40, 0xb2, 0x0d, 0x80, 0x68, 0x49, 0x1a, 0xbf, 0x3e, 0xef, 0xce, + 0x73, 0xd7, 0x60, 0x90, 0x03, 0x06, 0x20, 0x6f, 0x41, 0xfb, 0xc8, 0xcd, 0xa8, 0x4c, 0x0d, 0x02, + 0x9a, 0x75, 0x17, 0x10, 0x67, 0x99, 0x81, 0xf7, 0x14, 0x94, 0xdc, 0x67, 0x79, 0x41, 0x92, 0xc4, + 0x6c, 0xd3, 0xf7, 0xdd, 0x2c, 0xa3, 0x79, 0xd6, 0x5d, 0x44, 0xcc, 0xb6, 0x82, 0xef, 0x22, 0x98, + 0xad, 0x50, 0x66, 0x36, 0x89, 0x1b, 0xa4, 0x59, 0x17, 0x10, 0xaf, 0x25, 0x80, 0x07, 0x0c, 0xc6, + 0x18, 0x17, 0xf9, 0x12, 0x47, 0x6b, 0x72, 0xc6, 0x0a, 0xcc, 0x11, 0xdf, 0x86, 0x15, 0x77, 0x94, + 0x9f, 0xd0, 0x28, 0x67, 0x51, 0x9f, 0x31, 0x4f, 0x82, 0x6e, 0x0b, 0x75, 0xd6, 0x31, 0x06, 0x76, + 0x93, 0xc0, 0x3e, 0x83, 0xce, 0x3e, 0xcd, 0x9f, 0x07, 0xde, 0x2b, 0x9a, 0x4e, 0x61, 0x70, 0x72, + 0x0f, 0x66, 0x19, 0x6f, 0x11, 0x07, 0xd6, 0xd4, 0x29, 0x23, 0xb2, 0x21, 0x26, 0x81, 0x83, 0x18, + 0x4c, 0x8f, 0xb8, 0xea, 0x7e, 0x7e, 0x9e, 0x70, 0x9b, 0x2e, 0x3a, 0x8b, 0x08, 0x79, 0x7e, 0x9e, + 0x50, 0xfb, 0x05, 0xb4, 0xf4, 0x49, 0x6c, 0x43, 0xfa, 0x34, 0x0c, 0x86, 0x41, 0x4e, 0x53, 0xb9, + 0x21, 0x15, 0x80, 0xf9, 0x12, 0x53, 0xaf, 0x70, 0x5b, 0xfc, 0xcd, 0x7c, 0xf9, 0xab, 0x51, 0x9c, + 0x4b, 0xda, 0xfc, 0xc3, 0xfe, 0xf3, 0x06, 0x2c, 0xcb, 0xe5, 0x08, 0x47, 0x94, 0x32, 0x5b, 0x17, + 0xca, 0x7c, 0x0b, 0x5a, 0xa1, 0x9b, 0xe5, 0xfd, 0x51, 0xe2, 0xbb, 0x32, 0x6d, 0x98, 0x71, 0x9a, + 0x0c, 0xf6, 0x53, 0x0e, 0x62, 0xb6, 0x92, 0x59, 0x21, 0x5a, 0x41, 0x70, 0x6f, 0x79, 0xfa, 0x62, + 0x08, 0xcc, 0xb2, 0x39, 0xe8, 0xa9, 0x96, 0x83, 0xbf, 0x19, 0xec, 0x24, 0x18, 0x9c, 0xa0, 0x67, + 0x5a, 0x0e, 0xfe, 0x66, 0x1b, 0x34, 0x8c, 0xcf, 0xd0, 0x0f, 0x2d, 0x87, 0xfd, 0x64, 0x90, 0xa3, + 0xc0, 0x47, 0xb7, 0xb3, 0x1c, 0xf6, 0x93, 0x41, 0xdc, 0xec, 0x15, 0x3a, 0x99, 0xe5, 0xb0, 0x9f, + 0x2c, 0xa3, 0x3e, 0x8d, 0xc3, 0xd1, 0x90, 0xa2, 0x3f, 0x59, 0x8e, 0xf8, 0x22, 0xd7, 0x60, 0x31, + 0x49, 0x03, 0x8f, 0xf6, 0xdd, 0xfc, 0x04, 0x5d, 0xc8, 0x72, 0x16, 0x10, 0xb0, 0x9b, 0x9f, 0xd8, + 0xab, 0xb0, 0xa2, 0x0c, 0xad, 0x22, 0xd3, 0x4b, 0x98, 0x17, 0x90, 0x89, 0x46, 0x7f, 0x0f, 0xe6, + 0x73, 0x8e, 0xd6, 0x6d, 0x60, 0x88, 0xda, 0x90, 0x3a, 0x34, 0x35, 0xed, 0x48, 0x34, 0xfb, 0x37, + 0x81, 0xe8, 0xdc, 0x84, 0x21, 0xee, 0x17, 0x74, 0x78, 0xa8, 0x6b, 0x9b, 0x74, 0xb2, 0x82, 0xc0, + 0xd7, 0x18, 0xe8, 0x9f, 0xa5, 0x3e, 0x0b, 0x02, 0xf1, 0xab, 0xef, 0xd4, 0x35, 0x7f, 0x02, 0x4b, + 0x8a, 0xf1, 0xd3, 0x9c, 0x0e, 0x99, 0xc2, 0xdd, 0x61, 0x3c, 0x8a, 0x72, 0xe4, 0x69, 0x39, 0xe2, + 0x8b, 0x79, 0x20, 0xea, 0x17, 0x59, 0x5a, 0x0e, 0xff, 0x20, 0xcb, 0xd0, 0x08, 0x7c, 0x71, 0x31, + 0x69, 0x04, 0xbe, 0xfd, 0xbf, 0x16, 0xac, 0x68, 0x0b, 0xb9, 0xb4, 0x53, 0x56, 0x3c, 0xae, 0x51, + 0xe3, 0x71, 0xf7, 0x61, 0xf6, 0x28, 0xf0, 0xd9, 0x7d, 0x88, 0xe9, 0x75, 0x5d, 0x92, 0x33, 0xd6, + 0xe1, 0x20, 0x0a, 0x43, 0x75, 0xb3, 0x57, 0x59, 0x77, 0x76, 0x22, 0x2a, 0x43, 0xa9, 0xec, 0x87, + 0x2b, 0xd5, 0xfd, 0x60, 0xea, 0x72, 0xae, 0xac, 0x4b, 0x9e, 0x09, 0x2a, 0xda, 0xca, 0xf3, 0x3c, + 0x80, 0x02, 0x38, 0xd1, 0xac, 0xbf, 0x0e, 0x10, 0x2b, 0x4c, 0xe1, 0x7f, 0x57, 0x2b, 0x42, 0x2b, + 0x17, 0xd4, 0x90, 0xed, 0x1f, 0xe3, 0x31, 0xae, 0x33, 0x17, 0xca, 0x7f, 0x64, 0xd0, 0xe4, 0xbe, + 0x48, 0x2a, 0x34, 0x33, 0x83, 0xd8, 0x07, 0x48, 0x6c, 0xd7, 0xf3, 0x98, 0xe9, 0xb5, 0x4b, 0xef, + 0xc4, 0xf3, 0xf1, 0x05, 0xcc, 0x8b, 0x19, 0xc2, 0x2d, 0x38, 0x42, 0x23, 0xf0, 0xc9, 0xc7, 0x00, + 0xda, 0x19, 0xc2, 0xd7, 0x75, 0x4d, 0xca, 0x20, 0x26, 0x49, 0x6f, 0x40, 0x76, 0x1a, 0xba, 0x7d, + 0x0c, 0xab, 0x35, 0x28, 0x4c, 0x14, 0x75, 0x65, 0x15, 0xa2, 0xc8, 0x6f, 0x72, 0x03, 0x9a, 0x79, + 0x9c, 0xbb, 0x61, 0xbf, 0x48, 0x00, 0x2c, 0x07, 0x10, 0xf4, 0x82, 0x41, 0x30, 0x40, 0xc5, 0x21, + 0xf7, 0x5c, 0x16, 0xa0, 0xe2, 0xd0, 0xb7, 0x5d, 0x4c, 0x6a, 0x8c, 0x45, 0x0b, 0x15, 0x4e, 0x32, + 0xd9, 0xdb, 0xb0, 0xe0, 0xf2, 0x29, 0x72, 0x61, 0xed, 0xd2, 0xc2, 0x1c, 0x85, 0x60, 0x13, 0x3c, + 0x81, 0xf6, 0xe2, 0xe8, 0x38, 0x18, 0x48, 0xef, 0x78, 0x0b, 0x83, 0x95, 0x84, 0x15, 0xf9, 0x84, + 0xef, 0xe6, 0x2e, 0x72, 0x6b, 0x39, 0xf8, 0xdb, 0xfe, 0x23, 0x0b, 0x3a, 0x07, 0x71, 0x9a, 0x1f, + 0xc7, 0x61, 0x10, 0x8b, 0xd4, 0x99, 0xa5, 0x12, 0x32, 0xb5, 0x16, 0x39, 0x9a, 0xf8, 0x64, 0x11, + 0xd2, 0x8b, 0x83, 0x88, 0xfb, 0x6a, 0x43, 0x28, 0x28, 0x0e, 0x22, 0xe6, 0xaa, 0xe4, 0x26, 0x34, + 0x7d, 0x9a, 0x79, 0x69, 0x90, 0xb0, 0xab, 0x92, 0x08, 0x0b, 0x3a, 0x88, 0x11, 0x3e, 0x72, 0x43, + 0x37, 0xf2, 0xa8, 0x88, 0xec, 0xf2, 0xd3, 0x5e, 0xc7, 0x70, 0xa5, 0x24, 0xd1, 0x6e, 0xad, 0x26, + 0x58, 0x2c, 0xe5, 0xd7, 0x60, 0x31, 0x91, 0x40, 0xe1, 0x7e, 0x5d, 0xa9, 0xa1, 0xf2, 0x72, 0x9c, + 0x02, 0xd5, 0xde, 0x62, 0x79, 0x75, 0x41, 0xef, 0x70, 0x34, 0x1c, 0xba, 0xe9, 0xb9, 0xe4, 0x16, + 0xc1, 0xec, 0x5e, 0x1c, 0x44, 0x4c, 0x51, 0x6c, 0x51, 0x32, 0xf1, 0x62, 0xbf, 0x75, 0xd1, 0x1b, + 0x86, 0xe8, 0xba, 0xb6, 0x66, 0x4c, 0x6d, 0x5d, 0x07, 0x48, 0x68, 0xea, 0xd1, 0x28, 0x77, 0x07, + 0x72, 0xc5, 0x1a, 0xc4, 0x3e, 0x01, 0xf2, 0xec, 0xf8, 0x38, 0x0c, 0x22, 0xca, 0xd8, 0x0a, 0x61, + 0x26, 0x68, 0x7f, 0xbc, 0x0c, 0x26, 0xa7, 0x99, 0x0a, 0xa7, 0x9f, 0xc0, 0xca, 0xb3, 0xa8, 0x86, + 0x91, 0x24, 0x67, 0x4d, 0x22, 0xd7, 0xa8, 0x90, 0xfb, 0x11, 0xb4, 0x34, 0xc1, 0x33, 0xf2, 0x21, + 0x2c, 0x0a, 0x19, 0x55, 0x12, 0xde, 0x53, 0xd1, 0xa0, 0xb2, 0x42, 0xa7, 0x40, 0xb6, 0xff, 0xc2, + 0x82, 0x66, 0x21, 0x59, 0x46, 0x1e, 0xc3, 0x15, 0xa6, 0x6e, 0x49, 0xe5, 0xba, 0xa2, 0x52, 0xe0, + 0xec, 0xe0, 0xbf, 0x3c, 0x77, 0xe7, 0xc8, 0xbd, 0x43, 0x80, 0x02, 0x58, 0x93, 0xb5, 0x3f, 0x34, + 0x6f, 0x5f, 0x57, 0xab, 0x54, 0xa5, 0x68, 0x5a, 0x42, 0xff, 0xcf, 0xb3, 0xec, 0x2a, 0x55, 0xe3, + 0x2c, 0xc2, 0x07, 0xdf, 0x85, 0x26, 0xdf, 0x0b, 0x2c, 0x02, 0x48, 0x81, 0x5b, 0x45, 0xd9, 0x20, + 0x88, 0x1c, 0xc0, 0xbd, 0x81, 0xe3, 0xe4, 0x7d, 0x58, 0x42, 0x61, 0xfb, 0x31, 0x57, 0x88, 0xd8, + 0xd8, 0xe6, 0x84, 0x16, 0xa2, 0x08, 0x95, 0x91, 0x04, 0xd6, 0x8d, 0x29, 0xfd, 0x8c, 0x8b, 0x20, + 0x0e, 0xa9, 0x1f, 0x68, 0xf7, 0x9c, 0x71, 0x52, 0x72, 0x65, 0x09, 0x82, 0x62, 0x8c, 0xab, 0x6e, + 0xd5, 0xab, 0x8e, 0x90, 0x87, 0xd0, 0x12, 0x1c, 0x51, 0x33, 0xe2, 0x88, 0x33, 0x65, 0x6c, 0xf2, + 0x89, 0x88, 0x40, 0x86, 0xb0, 0xa6, 0x4f, 0x50, 0x12, 0x5e, 0xc1, 0x89, 0x1f, 0x4f, 0x2f, 0x61, + 0x54, 0x11, 0x90, 0x78, 0x95, 0x81, 0xde, 0xef, 0x42, 0x77, 0xdc, 0x82, 0x6a, 0xcc, 0xfe, 0xc0, + 0x34, 0xfb, 0x5a, 0x8d, 0x4b, 0x66, 0x7a, 0x71, 0xee, 0x4b, 0xd8, 0x1c, 0x23, 0xcc, 0x25, 0x6e, + 0xf4, 0x9a, 0xa7, 0xea, 0xde, 0xf4, 0x67, 0x16, 0xf4, 0x76, 0x7d, 0xbf, 0x12, 0x9c, 0x8a, 0x0b, + 0xf8, 0x77, 0x1d, 0x72, 0xb7, 0xe1, 0x5a, 0xad, 0x40, 0xa2, 0x52, 0xf0, 0x1a, 0xb6, 0x1d, 0x3a, + 0x8c, 0x4f, 0xe9, 0x77, 0x2d, 0xb2, 0x7d, 0x13, 0xae, 0x8f, 0xe3, 0x2c, 0x64, 0xc3, 0xd2, 0x99, + 0x59, 0x7a, 0x56, 0x89, 0xd1, 0x7f, 0x58, 0xb0, 0x64, 0x16, 0xa5, 0xdf, 0xd4, 0x3d, 0xfa, 0x1d, + 0x20, 0x29, 0xcd, 0xf2, 0x7e, 0x1a, 0x87, 0x21, 0xbb, 0x4e, 0xfb, 0x34, 0x74, 0xcf, 0x45, 0x39, + 0xbc, 0xc3, 0x46, 0x1c, 0x3e, 0xf0, 0x29, 0x83, 0x93, 0x4d, 0x98, 0x77, 0x93, 0xa0, 0xcf, 0xbc, + 0x86, 0xdf, 0xa5, 0xe7, 0xdc, 0x24, 0xf8, 0x31, 0x3d, 0x27, 0x36, 0x2c, 0x89, 0x81, 0x7e, 0x48, + 0x4f, 0x69, 0x88, 0x39, 0xdf, 0x8c, 0xd3, 0xe4, 0xc3, 0x9f, 0x33, 0x10, 0xbb, 0xfb, 0x26, 0x69, + 0xc0, 0xdc, 0xaf, 0xa8, 0xbb, 0xcf, 0xa3, 0x34, 0x6d, 0x01, 0x97, 0xab, 0xb3, 0x7f, 0x06, 0x57, + 0x6b, 0x74, 0x21, 0x62, 0xd4, 0x0f, 0xa1, 0x6d, 0x56, 0xef, 0x65, 0x9c, 0x52, 0x59, 0xab, 0x31, + 0xd1, 0x59, 0x3e, 0x36, 0xe8, 0x88, 0xec, 0x13, 0x71, 0x1c, 0x37, 0x57, 0xf5, 0x22, 0xfb, 0x2b, + 0x58, 0x2b, 0x80, 0x7b, 0x71, 0x74, 0x4a, 0xd3, 0x8c, 0x79, 0x1b, 0x81, 0xd9, 0xe3, 0x34, 0x96, + 0xc5, 0x4e, 0xfc, 0xcd, 0xf2, 0xb6, 0x3c, 0x16, 0x6e, 0xd0, 0xc8, 0x63, 0x86, 0x93, 0xba, 0xb9, + 0x3c, 0xa5, 0xf0, 0x37, 0xcb, 0x93, 0x03, 0x24, 0x42, 0xfb, 0x38, 0xc6, 0x5d, 0xb5, 0x29, 0x60, + 0x8c, 0x8b, 0xfd, 0x02, 0xd3, 0x47, 0x5d, 0x14, 0xb1, 0xc6, 0xdf, 0x80, 0x26, 0x5f, 0x23, 0x9b, + 0x29, 0xd7, 0xb7, 0x65, 0xac, 0xaf, 0x24, 0xa6, 0x03, 0xc7, 0x0a, 0x6a, 0xff, 0x57, 0x03, 0x5a, + 0x98, 0xb1, 0x7e, 0x4a, 0x73, 0x37, 0x08, 0x27, 0xe7, 0xd2, 0x3c, 0x07, 0x6d, 0xa8, 0x1c, 0xf4, + 0x36, 0x2c, 0xe9, 0xc5, 0x8c, 0x73, 0x79, 0x99, 0xd5, 0x4a, 0x19, 0xe7, 0xe4, 0x0e, 0x2c, 0xe3, + 0xd5, 0xba, 0xc0, 0xe2, 0x3e, 0xb3, 0x84, 0x50, 0x85, 0x66, 0x5e, 0x04, 0xae, 0x94, 0x2e, 0x02, + 0x6c, 0x18, 0x93, 0xe9, 0x7e, 0x16, 0xf8, 0xea, 0x9e, 0x80, 0x90, 0xc3, 0xc0, 0xd7, 0x86, 0x71, + 0xf6, 0xbc, 0x36, 0x8c, 0xb3, 0xd9, 0x1d, 0x28, 0xa5, 0xbc, 0x08, 0x8f, 0x6f, 0x49, 0x0b, 0xe8, + 0x74, 0x2d, 0x09, 0x7c, 0x1e, 0x0c, 0xf1, 0xa5, 0x49, 0x14, 0x8e, 0x79, 0x9d, 0x45, 0x7c, 0x15, + 0xd7, 0x34, 0xd0, 0xaf, 0x69, 0xc5, 0xa5, 0xae, 0x69, 0x5c, 0xea, 0x6e, 0x40, 0x33, 0x4e, 0x68, + 0xd4, 0x17, 0x57, 0xec, 0x16, 0xcf, 0x1e, 0x18, 0xe8, 0x05, 0x42, 0x44, 0xc9, 0x04, 0x75, 0x9e, + 0x4d, 0x73, 0x2f, 0x35, 0x15, 0xd3, 0x28, 0x2b, 0x46, 0x5e, 0x04, 0x67, 0x2e, 0xba, 0x08, 0xda, + 0xbb, 0x98, 0x15, 0x4b, 0xc6, 0xc2, 0x7d, 0xde, 0x81, 0x39, 0x54, 0x93, 0xf4, 0x9c, 0x35, 0xe3, + 0x1a, 0x23, 0x9c, 0xc2, 0x11, 0x38, 0xf6, 0x8f, 0xf0, 0x7d, 0x0e, 0x87, 0xa6, 0x11, 0xfd, 0x2a, + 0x2c, 0x70, 0xab, 0x28, 0xaf, 0x99, 0xc7, 0xef, 0xa7, 0xbe, 0xfd, 0xaf, 0x16, 0x90, 0xc3, 0xd1, + 0xd1, 0x30, 0x98, 0x9e, 0xda, 0xf4, 0x17, 0x74, 0x02, 0xb3, 0xe8, 0x26, 0xdc, 0x1d, 0xf1, 0x77, + 0xc9, 0x43, 0x66, 0xcb, 0x1e, 0x52, 0x98, 0xf3, 0x4a, 0xfd, 0x1d, 0x7d, 0x4e, 0x37, 0x3e, 0x0b, + 0xf1, 0x61, 0x40, 0xa3, 0xbc, 0x2f, 0x8a, 0x2d, 0x2c, 0xc4, 0x23, 0xe0, 0xa9, 0x6f, 0x1f, 0xc2, + 0xaa, 0xb1, 0x32, 0xa1, 0xe9, 0x5b, 0xd0, 0xe2, 0x02, 0x24, 0xa1, 0xeb, 0xa9, 0x4a, 0x73, 0x13, + 0x61, 0x07, 0x08, 0x9a, 0xa4, 0xaf, 0x3f, 0xb1, 0x60, 0xed, 0x30, 0x18, 0x8e, 0x42, 0x37, 0xa7, + 0xff, 0x0f, 0x1a, 0x2b, 0x96, 0x3f, 0x63, 0x2c, 0x5f, 0x6a, 0x72, 0xb6, 0xd0, 0xa4, 0xfd, 0xdf, + 0x16, 0xac, 0x97, 0x44, 0x51, 0x39, 0xa1, 0xe9, 0x4c, 0x63, 0x8a, 0x03, 0x02, 0x49, 0x63, 0xda, + 0x30, 0x98, 0xde, 0x86, 0xa5, 0x61, 0x10, 0x05, 0xc3, 0xd1, 0xb0, 0xcf, 0x75, 0xcf, 0x65, 0x6a, + 0x09, 0xe0, 0x01, 0x9a, 0x80, 0x21, 0xb9, 0xaf, 0x35, 0xa4, 0x59, 0x81, 0xc4, 0x81, 0x1c, 0xe9, + 0x3d, 0x58, 0x2b, 0xf2, 0xf6, 0xfe, 0xc0, 0x0d, 0xa2, 0x7e, 0x18, 0x67, 0x99, 0xb0, 0x31, 0x29, + 0xc6, 0xf6, 0xdd, 0x20, 0xfa, 0x3c, 0xce, 0x32, 0x2d, 0x08, 0xcc, 0xe9, 0x41, 0x80, 0x25, 0x30, + 0x9d, 0x97, 0x27, 0x6e, 0x48, 0x3f, 0x89, 0x87, 0x47, 0x6f, 0x56, 0xf7, 0xb7, 0xa0, 0xc5, 0xeb, + 0x6e, 0xb9, 0x9b, 0x0e, 0xa8, 0xb4, 0x40, 0x13, 0x61, 0xcf, 0x11, 0x54, 0x6b, 0x86, 0xff, 0xb4, + 0x80, 0xec, 0xb1, 0x54, 0x26, 0x9c, 0xda, 0x1f, 0x58, 0x28, 0xe1, 0xf7, 0xe6, 0xc2, 0xc3, 0x16, + 0x05, 0xe4, 0xa9, 0xe9, 0x7e, 0x33, 0x86, 0xfb, 0xa9, 0xd5, 0xcc, 0x5e, 0xb2, 0x38, 0x56, 0x89, + 0xe3, 0x77, 0x60, 0xf9, 0xcc, 0x0d, 0x43, 0x9a, 0xab, 0xe7, 0x2b, 0x51, 0x45, 0xe7, 0x50, 0x79, + 0x07, 0x97, 0x0b, 0x9e, 0xd7, 0x16, 0xbc, 0x0e, 0xab, 0xc6, 0x7a, 0x45, 0x36, 0xf4, 0x18, 0x36, + 0x38, 0x78, 0x37, 0x0c, 0xa7, 0x8e, 0xaa, 0xf6, 0x5f, 0x36, 0x60, 0xb3, 0x32, 0x4d, 0xa5, 0x0d, + 0xa6, 0x1b, 0xdf, 0x55, 0xcb, 0xad, 0x9f, 0xb0, 0x23, 0x3e, 0xc5, 0xac, 0xde, 0x3f, 0x5a, 0x30, + 0xc7, 0x41, 0x13, 0xad, 0xf1, 0xa5, 0x0c, 0x08, 0xc2, 0xe1, 0xf8, 0x8d, 0xe8, 0xfb, 0xd3, 0x31, + 0xe3, 0xff, 0xe9, 0x4f, 0x96, 0x3c, 0x92, 0x88, 0xd7, 0xca, 0x1f, 0x42, 0xa7, 0x8c, 0x70, 0xa9, + 0xe7, 0x1c, 0x5e, 0x55, 0x79, 0x72, 0x4a, 0xb5, 0x27, 0xca, 0x6f, 0x2c, 0x68, 0xef, 0xc5, 0x91, + 0x1f, 0xb0, 0x13, 0xf3, 0xc0, 0x4d, 0xdd, 0x61, 0x26, 0x5e, 0xc9, 0x39, 0x48, 0x96, 0xdd, 0x15, + 0x60, 0x4c, 0x81, 0x73, 0x1b, 0xc0, 0x3b, 0xa1, 0xde, 0xab, 0xbe, 0xa8, 0x38, 0xf2, 0xa7, 0x75, + 0x06, 0xf9, 0x24, 0xf0, 0x33, 0xf2, 0x2e, 0xac, 0x16, 0xc3, 0x7d, 0x37, 0xf2, 0xfb, 0xa2, 0xdc, + 0x88, 0x2f, 0x10, 0x0a, 0x6f, 0x37, 0xf2, 0x77, 0xb3, 0x57, 0xf8, 0x4e, 0xa2, 0xaa, 0x6c, 0x7d, + 0x23, 0x84, 0xb7, 0x15, 0x7c, 0x17, 0xc1, 0xf6, 0xff, 0x58, 0x78, 0x02, 0xca, 0x55, 0x09, 0x6b, + 0x17, 0x85, 0x35, 0xac, 0xb7, 0x1a, 0x26, 0x6b, 0x94, 0x4c, 0x46, 0x60, 0x36, 0xc8, 0xe9, 0x50, + 0x1e, 0x2c, 0xec, 0x37, 0xf9, 0x04, 0x3a, 0x6a, 0xc5, 0xfd, 0x04, 0xd5, 0x22, 0xb6, 0xc9, 0x66, + 0x71, 0x71, 0x34, 0xb4, 0xe6, 0xb4, 0xbd, 0x92, 0x1a, 0xe5, 0xf6, 0xba, 0x32, 0x55, 0xa0, 0xf6, + 0x50, 0xdb, 0x22, 0x3e, 0xf1, 0x2f, 0x2e, 0x35, 0xf5, 0x46, 0x39, 0xf5, 0x45, 0xaa, 0xac, 0xbe, + 0xed, 0x7f, 0xb7, 0xa0, 0xbd, 0xeb, 0xfb, 0xb8, 0xee, 0x69, 0xc2, 0x84, 0x5c, 0x65, 0xe3, 0x82, + 0x55, 0xce, 0xfc, 0x8a, 0xab, 0xfc, 0xd6, 0x41, 0x64, 0x8c, 0x12, 0x6c, 0x1b, 0x3a, 0xc5, 0x3a, + 0xeb, 0xcd, 0x6b, 0x7f, 0x0f, 0x08, 0xbf, 0x5e, 0x19, 0xea, 0x28, 0x63, 0xad, 0xc3, 0xaa, 0x81, + 0x25, 0x62, 0xcd, 0x67, 0x70, 0x6f, 0x9f, 0xe6, 0x7b, 0xe9, 0x79, 0x92, 0xc7, 0x32, 0x9d, 0xfd, + 0x94, 0x26, 0x71, 0x16, 0xc8, 0xc8, 0x45, 0xa7, 0x8a, 0x3e, 0xff, 0x64, 0xc1, 0xfd, 0x29, 0x08, + 0x89, 0x25, 0xfc, 0xbc, 0x5a, 0x5f, 0xfa, 0x2d, 0xbd, 0x75, 0x64, 0x2a, 0x2a, 0x3b, 0x0a, 0x22, + 0x5e, 0xf0, 0x15, 0xc9, 0xde, 0x0f, 0x60, 0xd9, 0x1c, 0xbc, 0x54, 0xa8, 0x08, 0xe1, 0xee, 0x05, + 0x42, 0x4c, 0xe3, 0x73, 0x77, 0x61, 0xd9, 0x33, 0x48, 0x08, 0x46, 0x25, 0xa8, 0xbd, 0x07, 0x6f, + 0x5d, 0xc8, 0x4d, 0xa8, 0x6d, 0xec, 0x0d, 0xdd, 0xfe, 0xdb, 0x59, 0xd8, 0x7c, 0x19, 0xe4, 0x27, + 0x7e, 0xea, 0x9e, 0x49, 0xef, 0x9b, 0x46, 0xc8, 0xd2, 0xe5, 0xbd, 0x51, 0xad, 0x37, 0x3c, 0x80, + 0x95, 0x38, 0xa2, 0x78, 0xc7, 0xe8, 0x27, 0x6e, 0x96, 0x9d, 0xc5, 0xa9, 0x3c, 0x4b, 0xdb, 0x71, + 0x44, 0xd9, 0x3d, 0xe3, 0x40, 0x80, 0x4b, 0xa7, 0xf1, 0x6c, 0xf9, 0x34, 0xee, 0xc0, 0x4c, 0x12, + 0x44, 0xe2, 0xcd, 0x84, 0xfd, 0x64, 0x67, 0x67, 0x9e, 0xba, 0xbe, 0x46, 0x59, 0x9c, 0x9d, 0x08, + 0x55, 0x74, 0xf5, 0x2a, 0xfe, 0x7c, 0xa9, 0x8a, 0xaf, 0xe9, 0x64, 0xc1, 0xac, 0x5a, 0xdc, 0x80, + 0xa6, 0xf8, 0xd9, 0xcf, 0xdd, 0x81, 0xb8, 0x02, 0x81, 0x00, 0x3d, 0x77, 0x07, 0x5a, 0xb6, 0x06, + 0x46, 0xb6, 0xb6, 0x0d, 0x70, 0x4c, 0x69, 0xdf, 0xb8, 0x0c, 0x2d, 0x1e, 0x53, 0xca, 0x83, 0x2e, + 0x4b, 0x95, 0x8f, 0xdc, 0xe8, 0x55, 0x1f, 0x6b, 0x10, 0x2d, 0x2e, 0x0e, 0x03, 0x7c, 0xe1, 0x0e, + 0x31, 0x27, 0xc6, 0x41, 0x29, 0xd3, 0x12, 0xd7, 0x28, 0x83, 0xed, 0x16, 0xd5, 0x14, 0x44, 0xf1, + 0x82, 0xfc, 0xbc, 0xbb, 0x5c, 0xcc, 0xdf, 0x0b, 0xf2, 0x73, 0x35, 0x1f, 0x75, 0x96, 0x9e, 0x77, + 0xdb, 0xc5, 0xfc, 0x3d, 0x0e, 0x62, 0xe2, 0x65, 0x67, 0xc1, 0x31, 0xe5, 0x4d, 0x17, 0x1d, 0xd1, + 0x86, 0xc4, 0x20, 0x7b, 0xb1, 0x8f, 0x69, 0xe4, 0x59, 0x90, 0x6a, 0x97, 0xd3, 0x15, 0x7e, 0x85, + 0x65, 0x40, 0xe9, 0x1a, 0xf6, 0x03, 0xe8, 0x48, 0x77, 0xd1, 0xfb, 0x12, 0x53, 0x9a, 0x8d, 0xc2, + 0x5c, 0xf6, 0x25, 0xf2, 0x2f, 0xfb, 0x7d, 0xec, 0x68, 0xf8, 0x3c, 0x1e, 0x0c, 0x8a, 0xeb, 0x93, + 0x70, 0xad, 0x0d, 0x98, 0x0b, 0x11, 0x2e, 0xa7, 0xf0, 0x2f, 0x3b, 0xc2, 0x7a, 0x4e, 0x69, 0x4a, + 0xf1, 0x6a, 0x11, 0x44, 0xc7, 0xb1, 0xb8, 0x2d, 0xe0, 0x6f, 0xb6, 0x17, 0x7d, 0x7a, 0x34, 0x1a, + 0xc8, 0xfe, 0x22, 0xfc, 0x60, 0x98, 0x67, 0x6e, 0x1a, 0x89, 0x03, 0x15, 0x7f, 0x33, 0x4c, 0x9a, + 0xa6, 0x71, 0x2a, 0x4e, 0x4f, 0xfe, 0x61, 0xef, 0xc3, 0xe6, 0xe1, 0xe5, 0x44, 0x64, 0x84, 0x78, + 0xb5, 0x46, 0x6c, 0x7f, 0xfc, 0x78, 0xf4, 0xd7, 0xb7, 0x61, 0x79, 0x3f, 0xe6, 0x9b, 0xf1, 0x39, + 0xf3, 0xc1, 0x94, 0x3c, 0x83, 0x79, 0xd1, 0x58, 0x48, 0x36, 0x2a, 0x9d, 0x86, 0xc8, 0xa3, 0xb7, + 0x39, 0xa6, 0x03, 0xd1, 0x5e, 0xfd, 0xc5, 0xbf, 0xfc, 0xdb, 0x2f, 0x1b, 0x4b, 0xa4, 0xf9, 0xf0, + 0xf4, 0xfd, 0x87, 0x03, 0x9a, 0xe3, 0x62, 0x4f, 0x60, 0xc9, 0xe8, 0x05, 0x23, 0x5b, 0x46, 0x3f, + 0x57, 0xa9, 0x45, 0xac, 0xb7, 0x3d, 0xb1, 0xdb, 0xcb, 0xee, 0x21, 0x8b, 0x35, 0x42, 0x04, 0x8b, + 0x0c, 0x51, 0x38, 0xe1, 0xaf, 0xa0, 0xfd, 0x04, 0xab, 0x60, 0x8a, 0x2a, 0xb9, 0x51, 0x50, 0xab, + 0xed, 0x71, 0xeb, 0xdd, 0x1c, 0x8f, 0x20, 0x38, 0x5e, 0x43, 0x8e, 0xeb, 0x64, 0x95, 0x71, 0xe4, + 0x55, 0x36, 0xd5, 0x5b, 0x46, 0x32, 0xe8, 0x88, 0xae, 0x99, 0x37, 0xca, 0x73, 0x0b, 0x79, 0x6e, + 0x90, 0x35, 0xc6, 0xd3, 0xe7, 0x0c, 0x0a, 0xa6, 0x31, 0x5e, 0xe2, 0xf5, 0x2e, 0x2f, 0x72, 0x7d, + 0x6c, 0xfb, 0x17, 0x67, 0x79, 0xe3, 0x82, 0xf6, 0x30, 0x73, 0x95, 0x03, 0xca, 0x70, 0x55, 0x87, + 0x18, 0xf9, 0xa5, 0x85, 0x0e, 0x5e, 0xdb, 0x8f, 0x48, 0xde, 0xba, 0xb8, 0x09, 0x92, 0xcb, 0x70, + 0x6f, 0xda, 0x6e, 0x49, 0xfb, 0x7b, 0x28, 0xcc, 0x75, 0xb2, 0x25, 0x84, 0x31, 0x3a, 0x24, 0x65, + 0x0f, 0x26, 0xf1, 0xa0, 0xa5, 0xb7, 0x76, 0x91, 0x6b, 0x35, 0x7d, 0x53, 0x8a, 0xf9, 0x56, 0xfd, + 0xa0, 0x60, 0xd8, 0x45, 0x86, 0x84, 0x74, 0x04, 0x43, 0xd5, 0x09, 0x46, 0xbe, 0x86, 0x76, 0xa9, + 0x2d, 0x8a, 0xd8, 0x25, 0xf3, 0xd5, 0xb4, 0xb8, 0xf5, 0x6e, 0x4f, 0xc4, 0x11, 0x5c, 0xaf, 0x23, + 0xd7, 0xae, 0xbd, 0xaa, 0x59, 0x59, 0x72, 0xfe, 0xc8, 0x7a, 0x40, 0x32, 0xb4, 0xb3, 0xde, 0x5b, + 0x35, 0x15, 0xef, 0x1b, 0x35, 0x4b, 0x35, 0xb6, 0x69, 0xd9, 0xd6, 0x92, 0x27, 0x6e, 0xd7, 0x0c, + 0x3b, 0x37, 0xb4, 0xbe, 0x33, 0x8c, 0xb2, 0xd3, 0xf0, 0xdd, 0xae, 0xef, 0x5b, 0x13, 0xad, 0x73, + 0x95, 0x9d, 0x2b, 0xb9, 0xc6, 0x79, 0x42, 0x32, 0xa3, 0xad, 0x4f, 0x30, 0x35, 0xbd, 0xba, 0xa6, + 0xb1, 0xae, 0x76, 0xa5, 0x7a, 0xa7, 0xdc, 0xd8, 0x95, 0xc6, 0x79, 0x92, 0x91, 0xd7, 0xb0, 0xcc, + 0xc3, 0xc5, 0x9b, 0xb7, 0xec, 0x36, 0xf2, 0xdd, 0xb4, 0x49, 0x11, 0x33, 0x74, 0xc3, 0xbe, 0x84, + 0x45, 0xd5, 0x1d, 0x43, 0xba, 0xda, 0x22, 0x8c, 0x3e, 0xac, 0xde, 0x98, 0x2e, 0x1b, 0xe9, 0xad, + 0xf6, 0x92, 0x58, 0x15, 0xef, 0x99, 0x61, 0x84, 0x7f, 0x06, 0x50, 0xb4, 0xdd, 0x90, 0xab, 0x15, + 0xca, 0x4a, 0x73, 0xbd, 0xba, 0x21, 0xd9, 0xbc, 0x8b, 0xe4, 0x3b, 0x64, 0xd9, 0x20, 0x2f, 0xf7, + 0x9b, 0xaa, 0x04, 0x19, 0xfb, 0xad, 0xdc, 0xa8, 0xd3, 0x1b, 0xdf, 0xa1, 0x21, 0x8d, 0x62, 0xcb, + 0xcd, 0xa6, 0x6e, 0x79, 0x6c, 0x05, 0x03, 0x3c, 0x2d, 0xb4, 0xd6, 0x90, 0xad, 0x3a, 0x2e, 0xb5, + 0xa7, 0x45, 0xb5, 0xcf, 0xc3, 0xbe, 0x8a, 0xac, 0x56, 0xc9, 0x4a, 0x99, 0x55, 0x46, 0x5e, 0xe1, + 0x1f, 0x2f, 0x68, 0x9d, 0x0d, 0x44, 0xa7, 0x55, 0x6d, 0xf3, 0xe8, 0x5d, 0x1f, 0x37, 0x3c, 0xe6, + 0x64, 0x12, 0x89, 0x20, 0x6e, 0x2a, 0x6e, 0x70, 0xde, 0xcf, 0x60, 0x18, 0xdc, 0x68, 0x7b, 0xe8, + 0x5d, 0xad, 0x19, 0x11, 0xd4, 0xd7, 0x91, 0x7a, 0x9b, 0x2c, 0xa9, 0x90, 0x88, 0xb4, 0xb8, 0x4d, + 0xd4, 0x43, 0x93, 0x61, 0x93, 0x72, 0x37, 0x82, 0x11, 0x03, 0x2b, 0x3d, 0x09, 0x95, 0x18, 0xa8, + 0xba, 0x0e, 0xc8, 0x1f, 0x9a, 0xcd, 0x0d, 0xf2, 0xb1, 0xd5, 0x9e, 0xf8, 0x3a, 0x5a, 0xd9, 0x2d, + 0x63, 0x5f, 0x50, 0xed, 0x1b, 0xc8, 0xf9, 0x2a, 0xd9, 0x2c, 0x73, 0x16, 0xaf, 0xb1, 0xe4, 0x17, + 0x16, 0xac, 0xd6, 0xbc, 0xf5, 0x15, 0x12, 0x8c, 0x7f, 0x99, 0x2c, 0x24, 0x98, 0xf4, 0x58, 0x68, + 0xa3, 0x04, 0x5b, 0x36, 0x4a, 0xe0, 0xfa, 0xbe, 0x92, 0x40, 0xe4, 0xb5, 0xcc, 0x33, 0xff, 0xd4, + 0x82, 0x8d, 0xfa, 0x77, 0x3d, 0x72, 0x47, 0xb5, 0x43, 0x4f, 0x7a, 0x71, 0xec, 0xdd, 0xbd, 0x08, + 0x4d, 0x48, 0x73, 0x07, 0xa5, 0xb9, 0x61, 0xf7, 0x98, 0x34, 0x29, 0xe2, 0xd6, 0x09, 0x74, 0x86, + 0xc5, 0x10, 0xf3, 0xe5, 0x8c, 0x68, 0xb9, 0x45, 0xfd, 0x03, 0x63, 0xef, 0xd6, 0x04, 0x0c, 0x33, + 0x7c, 0x91, 0x75, 0x61, 0x10, 0x7c, 0x6e, 0x52, 0x4f, 0x70, 0x62, 0x8f, 0x16, 0x2f, 0x53, 0xc6, + 0x1e, 0xad, 0x3c, 0xb6, 0x19, 0x7b, 0xb4, 0xfa, 0xfe, 0x55, 0xd9, 0xa3, 0xc8, 0x0c, 0xdf, 0xc2, + 0xc8, 0x97, 0xb8, 0x6d, 0x44, 0x25, 0xae, 0x5b, 0xde, 0xea, 0x59, 0xdd, 0xb6, 0x31, 0x6b, 0x6d, + 0x95, 0x50, 0xc9, 0x0b, 0x7c, 0x4c, 0x7b, 0x0e, 0x2c, 0x48, 0x74, 0xb2, 0x59, 0x26, 0x20, 0x29, + 0xd7, 0x3e, 0xa6, 0xd8, 0x9b, 0x48, 0x74, 0xc5, 0x6e, 0xe9, 0x44, 0x19, 0xcd, 0x23, 0x68, 0x6a, + 0x0f, 0x07, 0x44, 0x05, 0xd9, 0xea, 0x3b, 0x49, 0xef, 0x5a, 0xed, 0x98, 0x19, 0x4a, 0xec, 0x36, + 0x63, 0x90, 0x21, 0x82, 0xe2, 0xf1, 0xfb, 0xb0, 0x64, 0xd4, 0xee, 0x0b, 0xe5, 0xd7, 0xbd, 0x2e, + 0x14, 0xca, 0xaf, 0x2d, 0xf8, 0xcb, 0x44, 0xd3, 0x46, 0xe5, 0x67, 0x02, 0x45, 0xf1, 0xfa, 0x39, + 0x2c, 0xaa, 0x92, 0x79, 0xa1, 0xff, 0x72, 0x15, 0xfd, 0x22, 0x1e, 0x86, 0x0d, 0xce, 0xd8, 0xe4, + 0xa3, 0x78, 0x78, 0x24, 0xf4, 0xa5, 0x15, 0x84, 0x0b, 0x7d, 0x55, 0xab, 0xe2, 0x85, 0xbe, 0xea, + 0x2a, 0xc8, 0x86, 0xbe, 0x3c, 0x44, 0x50, 0x6b, 0x48, 0xa1, 0x5d, 0x2a, 0xc4, 0x16, 0x69, 0x45, + 0x7d, 0xd9, 0xb9, 0x48, 0x2b, 0xc6, 0x54, 0x70, 0xcd, 0xc4, 0x8d, 0xf3, 0x73, 0xc3, 0xb0, 0xf0, + 0x2d, 0x1e, 0xee, 0x79, 0x99, 0xd2, 0xf0, 0x5b, 0xa3, 0x1e, 0x6b, 0xf8, 0xad, 0x59, 0xd3, 0xac, + 0x84, 0x7b, 0xca, 0x69, 0xbd, 0x80, 0x05, 0x59, 0x1f, 0x2b, 0x9c, 0xb6, 0x54, 0x19, 0xec, 0x75, + 0xab, 0x03, 0x82, 0xaa, 0xe1, 0xb8, 0xae, 0xef, 0x23, 0x55, 0x61, 0x08, 0xad, 0x5a, 0x56, 0x18, + 0xa2, 0x5a, 0x68, 0x2b, 0x0c, 0x51, 0x57, 0x5e, 0x33, 0x0c, 0xc1, 0x23, 0x97, 0xe2, 0xf1, 0x77, + 0x16, 0xdc, 0xba, 0xb0, 0xd8, 0x45, 0xde, 0xbb, 0x44, 0x5d, 0x8c, 0x0b, 0xf4, 0xfe, 0xa5, 0x2b, + 0x69, 0xf6, 0x3d, 0x14, 0xd3, 0xb6, 0xb7, 0xe5, 0x61, 0x8a, 0xd3, 0x7c, 0x8e, 0xae, 0xca, 0x6a, + 0x4c, 0xe8, 0xbf, 0xb1, 0xf8, 0x9f, 0xa6, 0x4d, 0xa0, 0x4b, 0x76, 0xa6, 0x14, 0x40, 0x0a, 0xfc, + 0x70, 0x6a, 0x7c, 0x21, 0xee, 0x5d, 0x14, 0xf7, 0xa6, 0x7d, 0x6d, 0x82, 0xb8, 0x4c, 0xd8, 0x3f, + 0x80, 0x6b, 0xaa, 0x28, 0x66, 0xd0, 0xfd, 0x6c, 0x14, 0xf9, 0x59, 0x71, 0x2f, 0x1d, 0x53, 0x39, + 0x2b, 0x1c, 0xa7, 0x5c, 0x2b, 0x31, 0xcf, 0xc7, 0x33, 0x31, 0xca, 0xc5, 0x38, 0x66, 0xb4, 0x19, + 0xf7, 0x04, 0x56, 0xe4, 0xbc, 0xcf, 0x02, 0x37, 0xff, 0xd6, 0x3c, 0x6f, 0x22, 0xcf, 0x9e, 0xbd, + 0xae, 0xf3, 0x3c, 0x0e, 0xdc, 0x5c, 0x71, 0xcc, 0xf0, 0x8d, 0xc3, 0x28, 0x83, 0xe8, 0x97, 0xef, + 0xda, 0x02, 0x89, 0x7e, 0xf9, 0xae, 0xaf, 0xd8, 0x98, 0x97, 0xef, 0x01, 0xcd, 0x79, 0x05, 0xc5, + 0x17, 0x0c, 0x4e, 0xa1, 0x73, 0x38, 0x96, 0xe9, 0xe1, 0xaf, 0xcc, 0x54, 0xe4, 0x40, 0x36, 0x32, + 0xcd, 0x4a, 0x4c, 0x3f, 0xb2, 0x1e, 0x1c, 0xcd, 0xe1, 0xdf, 0xdc, 0x7e, 0xf0, 0x7f, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x0a, 0xe0, 0x50, 0x4a, 0xa6, 0x3b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4815,6 +4975,8 @@ type GoCryptoTraderClient interface { GetCryptocurrencyDepositAddress(ctx context.Context, in *GetCryptocurrencyDepositAddressRequest, opts ...grpc.CallOption) (*GetCryptocurrencyDepositAddressResponse, error) WithdrawCryptocurrencyFunds(ctx context.Context, in *WithdrawCurrencyRequest, opts ...grpc.CallOption) (*WithdrawResponse, error) WithdrawFiatFunds(ctx context.Context, in *WithdrawCurrencyRequest, opts ...grpc.CallOption) (*WithdrawResponse, error) + GetLoggerDetails(ctx context.Context, in *GetLoggerDetailsRequest, opts ...grpc.CallOption) (*GetLoggerDetailsResponse, error) + SetLoggerDetails(ctx context.Context, in *SetLoggerDetailsRequest, opts ...grpc.CallOption) (*GetLoggerDetailsResponse, error) } type goCryptoTraderClient struct { @@ -5167,6 +5329,24 @@ func (c *goCryptoTraderClient) WithdrawFiatFunds(ctx context.Context, in *Withdr return out, nil } +func (c *goCryptoTraderClient) GetLoggerDetails(ctx context.Context, in *GetLoggerDetailsRequest, opts ...grpc.CallOption) (*GetLoggerDetailsResponse, error) { + out := new(GetLoggerDetailsResponse) + err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/GetLoggerDetails", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *goCryptoTraderClient) SetLoggerDetails(ctx context.Context, in *SetLoggerDetailsRequest, opts ...grpc.CallOption) (*GetLoggerDetailsResponse, error) { + out := new(GetLoggerDetailsResponse) + err := c.cc.Invoke(ctx, "/gctrpc.GoCryptoTrader/SetLoggerDetails", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // GoCryptoTraderServer is the server API for GoCryptoTrader service. type GoCryptoTraderServer interface { GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error) @@ -5207,6 +5387,8 @@ type GoCryptoTraderServer interface { GetCryptocurrencyDepositAddress(context.Context, *GetCryptocurrencyDepositAddressRequest) (*GetCryptocurrencyDepositAddressResponse, error) WithdrawCryptocurrencyFunds(context.Context, *WithdrawCurrencyRequest) (*WithdrawResponse, error) WithdrawFiatFunds(context.Context, *WithdrawCurrencyRequest) (*WithdrawResponse, error) + GetLoggerDetails(context.Context, *GetLoggerDetailsRequest) (*GetLoggerDetailsResponse, error) + SetLoggerDetails(context.Context, *SetLoggerDetailsRequest) (*GetLoggerDetailsResponse, error) } func RegisterGoCryptoTraderServer(s *grpc.Server, srv GoCryptoTraderServer) { @@ -5897,6 +6079,42 @@ func _GoCryptoTrader_WithdrawFiatFunds_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _GoCryptoTrader_GetLoggerDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetLoggerDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GoCryptoTraderServer).GetLoggerDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gctrpc.GoCryptoTrader/GetLoggerDetails", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GoCryptoTraderServer).GetLoggerDetails(ctx, req.(*GetLoggerDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _GoCryptoTrader_SetLoggerDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetLoggerDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GoCryptoTraderServer).SetLoggerDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gctrpc.GoCryptoTrader/SetLoggerDetails", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GoCryptoTraderServer).SetLoggerDetails(ctx, req.(*SetLoggerDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _GoCryptoTrader_serviceDesc = grpc.ServiceDesc{ ServiceName: "gctrpc.GoCryptoTrader", HandlerType: (*GoCryptoTraderServer)(nil), @@ -6053,6 +6271,14 @@ var _GoCryptoTrader_serviceDesc = grpc.ServiceDesc{ MethodName: "WithdrawFiatFunds", Handler: _GoCryptoTrader_WithdrawFiatFunds_Handler, }, + { + MethodName: "GetLoggerDetails", + Handler: _GoCryptoTrader_GetLoggerDetails_Handler, + }, + { + MethodName: "SetLoggerDetails", + Handler: _GoCryptoTrader_SetLoggerDetails_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "rpc.proto", diff --git a/gctrpc/rpc.pb.gw.go b/gctrpc/rpc.pb.gw.go index 8a90ca9f..4bd4c1e7 100644 --- a/gctrpc/rpc.pb.gw.go +++ b/gctrpc/rpc.pb.gw.go @@ -9,13 +9,13 @@ It translates gRPC into RESTful JSON APIs. package gctrpc import ( + "context" "io" "net/http" "github.com/golang/protobuf/proto" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/grpc-ecosystem/grpc-gateway/utilities" - "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" @@ -54,7 +54,10 @@ func request_GoCryptoTrader_EnableSubsystem_0(ctx context.Context, marshaler run var protoReq GenericSubsystemRequest var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_GoCryptoTrader_EnableSubsystem_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_EnableSubsystem_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -71,7 +74,10 @@ func request_GoCryptoTrader_DisableSubsystem_0(ctx context.Context, marshaler ru var protoReq GenericSubsystemRequest var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_GoCryptoTrader_DisableSubsystem_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_DisableSubsystem_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -106,7 +112,10 @@ func request_GoCryptoTrader_GetExchanges_0(ctx context.Context, marshaler runtim var protoReq GetExchangesRequest var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_GoCryptoTrader_GetExchanges_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetExchanges_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -140,7 +149,10 @@ func request_GoCryptoTrader_GetExchangeInfo_0(ctx context.Context, marshaler run var protoReq GenericExchangeNameRequest var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_GoCryptoTrader_GetExchangeInfo_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetExchangeInfo_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -157,7 +169,10 @@ func request_GoCryptoTrader_GetExchangeOTPCode_0(ctx context.Context, marshaler var protoReq GenericExchangeNameRequest var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_GoCryptoTrader_GetExchangeOTPCode_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetExchangeOTPCode_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -252,7 +267,10 @@ func request_GoCryptoTrader_GetAccountInfo_0(ctx context.Context, marshaler runt var protoReq GetAccountInfoRequest var metadata runtime.ServerMetadata - if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_GoCryptoTrader_GetAccountInfo_0); err != nil { + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetAccountInfo_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -570,6 +588,43 @@ func request_GoCryptoTrader_WithdrawFiatFunds_0(ctx context.Context, marshaler r } +var ( + filter_GoCryptoTrader_GetLoggerDetails_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_GoCryptoTrader_GetLoggerDetails_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetLoggerDetailsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_GoCryptoTrader_GetLoggerDetails_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetLoggerDetails(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_GoCryptoTrader_SetLoggerDetails_0(ctx context.Context, marshaler runtime.Marshaler, client GoCryptoTraderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SetLoggerDetailsRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SetLoggerDetails(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + // RegisterGoCryptoTraderHandlerFromEndpoint is same as RegisterGoCryptoTraderHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterGoCryptoTraderHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -1368,85 +1423,129 @@ func RegisterGoCryptoTraderHandlerClient(ctx context.Context, mux *runtime.Serve }) + mux.Handle("GET", pattern_GoCryptoTrader_GetLoggerDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GoCryptoTrader_GetLoggerDetails_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GoCryptoTrader_GetLoggerDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GoCryptoTrader_SetLoggerDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GoCryptoTrader_SetLoggerDetails_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GoCryptoTrader_SetLoggerDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( - pattern_GoCryptoTrader_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getinfo"}, "")) + pattern_GoCryptoTrader_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getinfo"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetSubsystems_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getsusbsystems"}, "")) + pattern_GoCryptoTrader_GetSubsystems_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getsusbsystems"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_EnableSubsystem_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "enablesubsystem"}, "")) + pattern_GoCryptoTrader_EnableSubsystem_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "enablesubsystem"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_DisableSubsystem_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "disablesubsystem"}, "")) + pattern_GoCryptoTrader_DisableSubsystem_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "disablesubsystem"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetRPCEndpoints_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getrpcendpoints"}, "")) + pattern_GoCryptoTrader_GetRPCEndpoints_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getrpcendpoints"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetCommunicationRelayers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getcommunicationrelayers"}, "")) + pattern_GoCryptoTrader_GetCommunicationRelayers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getcommunicationrelayers"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetExchanges_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchanges"}, "")) + pattern_GoCryptoTrader_GetExchanges_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchanges"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_DisableExchange_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "disableexchange"}, "")) + pattern_GoCryptoTrader_DisableExchange_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "disableexchange"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetExchangeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchangeinfo"}, "")) + pattern_GoCryptoTrader_GetExchangeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchangeinfo"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetExchangeOTPCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchangeotp"}, "")) + pattern_GoCryptoTrader_GetExchangeOTPCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchangeotp"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetExchangeOTPCodes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchangeotps"}, "")) + pattern_GoCryptoTrader_GetExchangeOTPCodes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getexchangeotps"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_EnableExchange_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "enableexchange"}, "")) + pattern_GoCryptoTrader_EnableExchange_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "enableexchange"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetTicker_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getticker"}, "")) + pattern_GoCryptoTrader_GetTicker_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getticker"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetTickers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "gettickers"}, "")) + pattern_GoCryptoTrader_GetTickers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "gettickers"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetOrderbook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorderbook"}, "")) + pattern_GoCryptoTrader_GetOrderbook_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorderbook"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetOrderbooks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorderbooks"}, "")) + pattern_GoCryptoTrader_GetOrderbooks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorderbooks"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetAccountInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getaccountinfo"}, "")) + pattern_GoCryptoTrader_GetAccountInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getaccountinfo"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getconfig"}, "")) + pattern_GoCryptoTrader_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getconfig"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetPortfolio_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getportfolio"}, "")) + pattern_GoCryptoTrader_GetPortfolio_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getportfolio"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetPortfolioSummary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getportfoliosummary"}, "")) + pattern_GoCryptoTrader_GetPortfolioSummary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getportfoliosummary"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_AddPortfolioAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "addportfolioaddress"}, "")) + pattern_GoCryptoTrader_AddPortfolioAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "addportfolioaddress"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_RemovePortfolioAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "removeportfolioaddress"}, "")) + pattern_GoCryptoTrader_RemovePortfolioAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "removeportfolioaddress"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetForexProviders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getforexproviders"}, "")) + pattern_GoCryptoTrader_GetForexProviders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getforexproviders"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetForexRates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getforexrates"}, "")) + pattern_GoCryptoTrader_GetForexRates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getforexrates"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorders"}, "")) + pattern_GoCryptoTrader_GetOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorders"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorder"}, "")) + pattern_GoCryptoTrader_GetOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getorder"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_SubmitOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "submitorder"}, "")) + pattern_GoCryptoTrader_SubmitOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "submitorder"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_SimulateOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "simulateorder"}, "")) + pattern_GoCryptoTrader_SimulateOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "simulateorder"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_WhaleBomb_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "whalebomb"}, "")) + pattern_GoCryptoTrader_WhaleBomb_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "whalebomb"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_CancelOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "cancelorder"}, "")) + pattern_GoCryptoTrader_CancelOrder_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "cancelorder"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_CancelAllOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "cancelallorders"}, "")) + pattern_GoCryptoTrader_CancelAllOrders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "cancelallorders"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetEvents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getevents"}, "")) + pattern_GoCryptoTrader_GetEvents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getevents"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_AddEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "addevent"}, "")) + pattern_GoCryptoTrader_AddEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "addevent"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_RemoveEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "removeevent"}, "")) + pattern_GoCryptoTrader_RemoveEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "removeevent"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetCryptocurrencyDepositAddresses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getcryptodepositaddresses"}, "")) + pattern_GoCryptoTrader_GetCryptocurrencyDepositAddresses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getcryptodepositaddresses"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_GetCryptocurrencyDepositAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getcryptodepositaddress"}, "")) + pattern_GoCryptoTrader_GetCryptocurrencyDepositAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getcryptodepositaddress"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_WithdrawCryptocurrencyFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "withdrawcryptofunds"}, "")) + pattern_GoCryptoTrader_WithdrawCryptocurrencyFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "withdrawcryptofunds"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_GoCryptoTrader_WithdrawFiatFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "withdrawfiatfunds"}, "")) + pattern_GoCryptoTrader_WithdrawFiatFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "withdrawfiatfunds"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_GoCryptoTrader_GetLoggerDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getloggerdetails"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_GoCryptoTrader_SetLoggerDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "setloggerdetails"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -1525,4 +1624,8 @@ var ( forward_GoCryptoTrader_WithdrawCryptocurrencyFunds_0 = runtime.ForwardResponseMessage forward_GoCryptoTrader_WithdrawFiatFunds_0 = runtime.ForwardResponseMessage + + forward_GoCryptoTrader_GetLoggerDetails_0 = runtime.ForwardResponseMessage + + forward_GoCryptoTrader_SetLoggerDetails_0 = runtime.ForwardResponseMessage ) diff --git a/gctrpc/rpc.proto b/gctrpc/rpc.proto index 644a3bb0..aa0cde00 100644 --- a/gctrpc/rpc.proto +++ b/gctrpc/rpc.proto @@ -68,7 +68,7 @@ message GetExchangeOTPReponse { string otp_code = 1; } -message GetExchangeOTPsRequest {} +message GetExchangeOTPsRequest {} message GetExchangeOTPsResponse { map otp_codes = 1; @@ -147,7 +147,7 @@ message OrderbookResponse { repeated OrderbookItem bids = 3; repeated OrderbookItem asks = 4; int64 last_updated = 5; - string asset_type = 6; + string asset_type = 6; } message GetOrderbooksRequest {} @@ -225,7 +225,7 @@ message OfflineCoins { } message OnlineCoins { - map coins = 1; + map coins = 1; } message GetPortfolioSummaryResponse { @@ -371,7 +371,7 @@ message CancelAllOrdersResponse { string exchange = 1; map order_status = 2; } - repeated Orders orders = 1; + repeated Orders orders = 1; } message GetEventsRequest {} @@ -455,6 +455,22 @@ message WithdrawResponse { string result = 1; } +message GetLoggerDetailsRequest { + string logger = 1; +} + +message GetLoggerDetailsResponse{ + bool info = 1; + bool debug = 2; + bool warn = 3; + bool error = 4; +} + +message SetLoggerDetailsRequest { + string logger = 1; + string level = 2; +} + service GoCryptoTrader { rpc GetInfo (GetInfoRequest) returns (GetInfoResponse) { option (google.api.http) = { @@ -703,4 +719,17 @@ service GoCryptoTrader { body: "*" }; } + + rpc GetLoggerDetails(GetLoggerDetailsRequest) returns (GetLoggerDetailsResponse) { + option (google.api.http) = { + get: "/v1/getloggerdetails" + }; + } + + rpc SetLoggerDetails(SetLoggerDetailsRequest) returns (GetLoggerDetailsResponse) { + option (google.api.http) = { + post: "/v1/setloggerdetails", + body: "*" + }; + } } diff --git a/gctrpc/rpc.swagger.json b/gctrpc/rpc.swagger.json index 032da9db..c590bbd3 100644 --- a/gctrpc/rpc.swagger.json +++ b/gctrpc/rpc.swagger.json @@ -480,6 +480,30 @@ ] } }, + "/v1/getloggerdetails": { + "get": { + "operationId": "GetLoggerDetails", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/gctrpcGetLoggerDetailsResponse" + } + } + }, + "parameters": [ + { + "name": "logger", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "GoCryptoTrader" + ] + } + }, "/v1/getorder": { "post": { "operationId": "GetOrder", @@ -732,6 +756,32 @@ ] } }, + "/v1/setloggerdetails": { + "post": { + "operationId": "SetLoggerDetails", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/gctrpcGetLoggerDetailsResponse" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/gctrpcSetLoggerDetailsRequest" + } + } + ], + "tags": [ + "GoCryptoTrader" + ] + } + }, "/v1/simulateorder": { "post": { "operationId": "SimulateOrder", @@ -1371,6 +1421,27 @@ } } }, + "gctrpcGetLoggerDetailsResponse": { + "type": "object", + "properties": { + "info": { + "type": "boolean", + "format": "boolean" + }, + "debug": { + "type": "boolean", + "format": "boolean" + }, + "warn": { + "type": "boolean", + "format": "boolean" + }, + "error": { + "type": "boolean", + "format": "boolean" + } + } + }, "gctrpcGetOrderRequest": { "type": "object", "properties": { @@ -1742,6 +1813,17 @@ "gctrpcRemovePortfolioAddressResponse": { "type": "object" }, + "gctrpcSetLoggerDetailsRequest": { + "type": "object", + "properties": { + "logger": { + "type": "string" + }, + "level": { + "type": "string" + } + } + }, "gctrpcSimulateOrderRequest": { "type": "object", "properties": { diff --git a/go.mod b/go.mod index 00e0d429..1c618c5a 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/gorilla/mux v1.7.2 github.com/gorilla/websocket v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 - github.com/grpc-ecosystem/grpc-gateway v1.9.0 + github.com/grpc-ecosystem/grpc-gateway v1.9.2 github.com/pquerna/otp v1.2.0 github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b github.com/urfave/cli v1.20.0 diff --git a/go.sum b/go.sum index 8fc938f2..a84ddf41 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmo github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.2 h1:S+ef0492XaIknb8LMjcwgW2i3cNTzDYMmDrOThOJNWc= +github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= diff --git a/logger/logger.go b/logger/logger.go index 84572942..7dfdc323 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -1,120 +1,78 @@ package logger import ( + "errors" "fmt" "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "runtime" "time" ) -func init() { - setDefaultOutputs() -} - -// SetupLogger configure logger instance with user provided settings -func SetupLogger() (err error) { - if *Logger.Enabled { - err = setupOutputs() - if err != nil { - return - } - logLevel() - if Logger.ColourOutput { - colourOutput() - } - } else { - clearAllLoggers() - } - return -} - -// setDefaultOutputs() this setups defaults used by the logger -// This allows it to be used without any user configuration -func setDefaultOutputs() { - debugLogger = log.New(os.Stdout, - "[DEBUG]: ", - log.Ldate|log.Ltime) - - infoLogger = log.New(os.Stdout, - "[INFO]: ", - log.Ldate|log.Ltime) - - warnLogger = log.New(os.Stdout, - "[WARN]: ", - log.Ldate|log.Ltime) - - errorLogger = log.New(os.Stdout, - "[ERROR]: ", - log.Ldate|log.Ltime) - - fatalLogger = log.New(os.Stdout, - "[FATAL]: ", - log.Ldate|log.Ltime) -} - -// colorOutput() sets the prefix of each log type to matching colour -// TODO: add windows support -func colourOutput() { - if runtime.GOOS != "windows" || Logger.ColourOutputOverride { - debugLogger.SetPrefix("\033[34m[DEBUG]\033[0m: ") - infoLogger.SetPrefix("\033[32m[INFO]\033[0m: ") - warnLogger.SetPrefix("\033[33m[WARN]\033[0m: ") - errorLogger.SetPrefix("\033[31m[ERROR]\033[0m: ") - fatalLogger.SetPrefix("\033[31m[FATAL]\033[0m: ") +func newLogger(c *Config) *Logger { + return &Logger{ + Timestamp: c.AdvancedSettings.TimeStampFormat, + Spacer: c.AdvancedSettings.Spacer, + ErrorHeader: c.AdvancedSettings.Headers.Error, + InfoHeader: c.AdvancedSettings.Headers.Info, + WarnHeader: c.AdvancedSettings.Headers.Warn, + DebugHeader: c.AdvancedSettings.Headers.Debug, } } -// clearAllLoggers() sets all logger flags to 0 and outputs to Discard -func clearAllLoggers() { - debugLogger.SetFlags(0) - infoLogger.SetFlags(0) - warnLogger.SetFlags(0) - errorLogger.SetFlags(0) - fatalLogger.SetFlags(0) - - debugLogger.SetOutput(ioutil.Discard) - infoLogger.SetOutput(ioutil.Discard) - warnLogger.SetOutput(ioutil.Discard) - errorLogger.SetOutput(ioutil.Discard) - fatalLogger.SetOutput(ioutil.Discard) -} - -// setupOutputs() sets up the io.writer to use for logging -// TODO: Fix up rotating at the moment its a quick job -func setupOutputs() (err error) { - if len(Logger.File) > 0 { - logFile := filepath.Join(LogPath, Logger.File) - if Logger.Rotate { - if _, err = os.Stat(logFile); !os.IsNotExist(err) { - currentTime := time.Now() - newName := currentTime.Format("2006-01-02 15-04-05") - newFile := newName + " " + Logger.File - err = os.Rename(logFile, filepath.Join(LogPath, newFile)) - if err != nil { - err = fmt.Errorf("failed to rename old log file %s", err) - return - } - } - } - logFileHandle, err = os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return - } - logOutput = io.MultiWriter(os.Stdout, logFileHandle) - } else { - logOutput = os.Stdout +func (l *Logger) newLogEvent(data, header string, w io.Writer) error { + if w == nil { + return errors.New("io.Writer not set") } - return + e := eventPool.Get().(*LogEvent) + e.output = w + e.data = append(e.data, []byte(header)...) + e.data = append(e.data, l.Spacer...) + if l.Timestamp != "" { + e.data = time.Now().AppendFormat(e.data, l.Timestamp) + } + e.data = append(e.data, l.Spacer...) + e.data = append(e.data, []byte(data)...) + if data == "" || data[len(data)-1] != '\n' { + e.data = append(e.data, '\n') + } + e.output.Write(e.data) + e.data = e.data[:0] + eventPool.Put(e) + + return nil } -// CloseLogFile close the handler for any open log files -func CloseLogFile() (err error) { - if logFileHandle != nil { - err = logFileHandle.Close() +// CloseLogger is called on shutdown of application +func CloseLogger() error { + err := GlobalLogFile.Close() + if err != nil { + return err } - return + return nil + +} + +func validSubLogger(s string) (bool, *subLogger) { + if v, found := subLoggers[s]; found { + return true, v + } + return false, nil +} + +func Level(s string) (*Levels, error) { + found, logger := validSubLogger(s) + if !found { + return nil, fmt.Errorf("logger %v not found", s) + } + + return &logger.Levels, nil +} + +func SetLevel(s, level string) (*Levels, error) { + found, logger := validSubLogger(s) + if !found { + return nil, fmt.Errorf("logger %v not found", s) + } + logger.Levels = splitLevel(level) + + return &logger.Levels, nil } diff --git a/logger/logger_levels.go b/logger/logger_levels.go deleted file mode 100644 index ce7f2c8c..00000000 --- a/logger/logger_levels.go +++ /dev/null @@ -1,33 +0,0 @@ -package logger - -import ( - "log" - "strings" -) - -func logLevel() { - clearAllLoggers() - enabledLevels := strings.Split(Logger.Level, "|") - - for x := range enabledLevels { - switch level := enabledLevels[x]; level { - case "DEBUG": - debugLogger.SetOutput(logOutput) - debugLogger.SetFlags(log.Ldate | log.Ltime) - case "INFO": - infoLogger.SetOutput(logOutput) - infoLogger.SetFlags(log.Ldate | log.Ltime) - case "WARN": - warnLogger.SetOutput(logOutput) - warnLogger.SetFlags(log.Ldate | log.Ltime) - case "ERROR": - errorLogger.SetOutput(logOutput) - errorLogger.SetFlags(log.Ldate | log.Ltime) - case "FATAL": - fatalLogger.SetOutput(logOutput) - fatalLogger.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) - default: - continue - } - } -} diff --git a/logger/logger_multiwriter.go b/logger/logger_multiwriter.go new file mode 100644 index 00000000..af07cfff --- /dev/null +++ b/logger/logger_multiwriter.go @@ -0,0 +1,75 @@ +package logger + +import ( + "io" +) + +// Add appends a new writer to the multiwriter slice +func (mw *multiWriter) Add(writer io.Writer) { + mw.mu.Lock() + mw.writers = append(mw.writers, writer) + mw.mu.Unlock() +} + +// Remove removes exisiting writer from multiwriter slice +func (mw *multiWriter) Remove(writer io.Writer) { + mw.mu.Lock() + + var removeIDs []int + for i := range mw.writers { + if mw.writers[i] == writer { + removeIDs = append(removeIDs, i) + } + } + + for x := range removeIDs { + mw.writers[x] = mw.writers[len(mw.writers)-1] + mw.writers[len(mw.writers)-1] = nil + mw.writers = mw.writers[:len(mw.writers)-1] + } + + mw.mu.Unlock() +} + +// Write concurrent safe Write for each writer +func (mw *multiWriter) Write(p []byte) (n int, err error) { + type data struct { + n int + err error + } + + results := make(chan data) + + for _, wr := range mw.writers { + go func(w io.Writer, p []byte, ch chan data) { + n, err = w.Write(p) + if err != nil { + ch <- data{n, err} + return + } + if n != len(p) { + ch <- data{n, io.ErrShortWrite} + return + } + select { + case ch <- data{n, nil}: + default: + } + }(wr, p, results) + } + + for range mw.writers { + d := <-results + if d.err != nil { + return d.n, d.err + } + } + return len(p), nil +} + +// MultiWriter make and return a new copy of multiWriter +func MultiWriter(writers ...io.Writer) io.Writer { + w := make([]io.Writer, len(writers)) + copy(w, writers) + return &multiWriter{writers: w} +} diff --git a/logger/logger_rotate.go b/logger/logger_rotate.go new file mode 100644 index 00000000..dc4a0f3d --- /dev/null +++ b/logger/logger_rotate.go @@ -0,0 +1,132 @@ +package logger + +import ( + "fmt" + "os" + "path/filepath" + "time" +) + +// Write implementation to satisfy io.Writer handles length check and rotation +func (r *Rotate) Write(output []byte) (n int, err error) { + r.mu.Lock() + defer r.mu.Unlock() + + outputLen := int64(len(output)) + + if outputLen > r.maxSize() { + return 0, fmt.Errorf( + "write length %v exceeds max file size %v", outputLen, r.maxSize(), + ) + } + + if r.output == nil { + err = r.openOrCreateFile(outputLen) + if err != nil { + return 0, err + } + } + + if *r.Rotate { + if r.size+outputLen > r.maxSize() { + err = r.rotateFile() + if err != nil { + return 0, err + } + } + } + + n, err = r.output.Write(output) + r.size += int64(n) + + return n, err +} + +func (r *Rotate) openOrCreateFile(n int64) error { + logFile := filepath.Join(LogPath, r.FileName) + + info, err := os.Stat(logFile) + if err != nil { + if os.IsNotExist(err) { + return r.openNew() + } + return fmt.Errorf("error opening log file info: %s", err) + } + + if *r.Rotate { + if info.Size()+n >= r.maxSize() { + return r.rotateFile() + } + } + + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + return r.openNew() + } + + r.output = file + r.size = info.Size() + + return nil +} + +func (r *Rotate) openNew() error { + name := filepath.Join(LogPath, r.FileName) + + t := time.Now() + timestamp := t.Format("2006-01-02T15-04-05") + newName := filepath.Join(LogPath, timestamp+"-"+r.FileName) + _, err := os.Stat(name) + + if err == nil { + err = os.Rename(name, newName) + if err != nil { + return fmt.Errorf("can't rename log file: %s", err) + } + } + + file, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) + if err != nil { + return fmt.Errorf("can't open new logfile: %s", err) + } + + r.output = file + r.size = 0 + + return nil +} + +func (r *Rotate) close() (err error) { + if r.output == nil { + return nil + } + err = r.output.Close() + r.output = nil + return err +} + +func (r *Rotate) Close() error { + r.mu.Lock() + defer r.mu.Unlock() + return r.close() +} + +func (r *Rotate) rotateFile() (err error) { + err = r.close() + if err != nil { + return + } + + err = r.openNew() + if err != nil { + return + } + return nil +} + +func (r *Rotate) maxSize() int64 { + if r.MaxSize == 0 { + return int64(defaultMaxSize * megabyte) + } + return r.MaxSize * int64(megabyte) +} diff --git a/logger/logger_rotate_types.go b/logger/logger_rotate_types.go new file mode 100644 index 00000000..8b298ce8 --- /dev/null +++ b/logger/logger_rotate_types.go @@ -0,0 +1,22 @@ +package logger + +import ( + "os" + "sync" +) + +const ( + defaultMaxSize = 250 + megabyte = 1024 * 1024 +) + +// Rotate struct for each instance of Rotate +type Rotate struct { + FileName string + Rotate *bool + MaxSize int64 + + size int64 + output *os.File + mu sync.Mutex +} diff --git a/logger/logger_setup.go b/logger/logger_setup.go new file mode 100644 index 00000000..b461e059 --- /dev/null +++ b/logger/logger_setup.go @@ -0,0 +1,156 @@ +package logger + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "strings" +) + +func getWriters(s *SubLoggerConfig) io.Writer { + mw := MultiWriter() + m := mw.(*multiWriter) + + outputWriters := strings.Split(s.Output, "|") + for x := range outputWriters { + switch outputWriters[x] { + case "stdout", "console": + m.Add(os.Stdout) + case "stderr": + m.Add(os.Stderr) + case "file": + if FileLoggingConfiguredCorrectly { + m.Add(GlobalLogFile) + } + default: + m.Add(ioutil.Discard) + } + } + + return m +} + +// GenDefaultSettings return struct with known sane/working logger settings +func GenDefaultSettings() (log Config) { + t := func(t bool) *bool { return &t }(true) + f := func(f bool) *bool { return &f }(false) + + log = Config{ + Enabled: t, + SubLoggerConfig: SubLoggerConfig{ + Level: "INFO|DEBUG|WARN|ERROR", + Output: "console", + }, + LoggerFileConfig: &loggerFileConfig{ + FileName: "log.txt", + Rotate: f, + MaxSize: 0, + }, + AdvancedSettings: advancedSettings{ + Spacer: " | ", + TimeStampFormat: timestampFormat, + Headers: headers{ + Info: "[INFO]", + Warn: "[WARN]", + Debug: "[DEBUG]", + Error: "[ERROR]", + }, + }, + } + return +} + +func configureSubLogger(logger, levels string, output io.Writer) error { + found, logPtr := validSubLogger(logger) + if !found { + return fmt.Errorf("logger %v not found", logger) + } + + logPtr.output = output + + logPtr.Levels = splitLevel(levels) + subLoggers[logger] = logPtr + + return nil +} + +// SetupSubLoggers configure all sub loggers with provided configuration values +func SetupSubLoggers(s []SubLoggerConfig) { + for x := range s { + output := getWriters(&s[x]) + err := configureSubLogger(s[x].Name, s[x].Level, output) + if err != nil { + continue + } + } +} + +// SetupGlobalLogger setup the global loggers with the default global config values +func SetupGlobalLogger() { + if FileLoggingConfiguredCorrectly { + GlobalLogFile = &Rotate{ + FileName: GlobalLogConfig.LoggerFileConfig.FileName, + MaxSize: GlobalLogConfig.LoggerFileConfig.MaxSize, + Rotate: GlobalLogConfig.LoggerFileConfig.Rotate, + } + } + + for x := range subLoggers { + subLoggers[x].Levels = splitLevel(GlobalLogConfig.Level) + subLoggers[x].output = getWriters(&GlobalLogConfig.SubLoggerConfig) + } + + logger = newLogger(GlobalLogConfig) +} + +func splitLevel(level string) (l Levels) { + enabledLevels := strings.Split(level, "|") + for x := range enabledLevels { + switch level := enabledLevels[x]; level { + case "DEBUG": + l.Debug = true + case "INFO": + l.Info = true + case "WARN": + l.Warn = true + case "ERROR": + l.Error = true + } + } + return +} + +func registerNewSubLogger(logger string) *subLogger { + temp := subLogger{ + name: logger, + output: os.Stdout, + } + + temp.Levels = splitLevel("INFO|WARN|DEBUG|ERROR") + subLoggers[logger] = &temp + + return &temp +} + +// register all loggers at package init() +func init() { + Global = registerNewSubLogger("log") + + ConnectionMgr = registerNewSubLogger("connection") + CommunicationMgr = registerNewSubLogger("comms") + ConfigMgr = registerNewSubLogger("config") + OrderMgr = registerNewSubLogger("order") + PortfolioMgr = registerNewSubLogger("portfolio") + SyncMgr = registerNewSubLogger("sync") + TimeMgr = registerNewSubLogger("timekeeper") + WebsocketMgr = registerNewSubLogger("websocket") + EventMgr = registerNewSubLogger("event") + + ExchangeSys = registerNewSubLogger("exchange") + GRPCSys = registerNewSubLogger("grpc") + RESTSys = registerNewSubLogger("rest") + + Ticker = registerNewSubLogger("ticker") + OrderBook = registerNewSubLogger("orderbook") +} diff --git a/logger/logger_test.go b/logger/logger_test.go index 35d0cd65..7af289e0 100644 --- a/logger/logger_test.go +++ b/logger/logger_test.go @@ -1,8 +1,9 @@ package logger import ( + "bytes" + "io/ioutil" "os" - "path/filepath" "testing" ) @@ -11,77 +12,237 @@ var ( falseptr = func(b bool) *bool { return &b }(false) ) -func TestCloseLogFile(t *testing.T) { - Logger = &Logging{ - Enabled: trueptr, - Level: "DEBUG", - ColourOutput: false, - File: "", - Rotate: false, +func SetupTest() { + logTest := Config{ + Enabled: trueptr, + SubLoggerConfig: SubLoggerConfig{ + Output: "console", + Level: "INFO|WARN|DEBUG|ERROR", + }, + AdvancedSettings: advancedSettings{ + Spacer: " | ", + TimeStampFormat: timestampFormat, + Headers: headers{ + Info: "[INFO]", + Warn: "[WARN]", + Debug: "[DEBUG]", + Error: "[ERROR]", + }, + }, + SubLoggers: []SubLoggerConfig{ + { + Name: "test", + Level: "INFO|DEBUG|WARN|ERROR", + Output: "stdout", + }}, } - SetupLogger() - err := CloseLogFile() - if err != nil { - t.Fatalf("CloseLogFile failed with %v", err) - } - os.Remove(filepath.Join(LogPath, Logger.File)) + + GlobalLogConfig = &logTest + SetupGlobalLogger() + SetupSubLoggers(logTest.SubLoggers) } -func TestSetupOutputsValidPath(t *testing.T) { - Logger.Enabled = trueptr - Logger.File = "debug.txt" - LogPath = "../testdata/" - err := setupOutputs() - if err != nil { - t.Fatalf("SetupOutputs failed expected nil got %v", err) +func SetupDisabled() { + logTest := Config{ + Enabled: falseptr, } - err = CloseLogFile() - if err != nil { - t.Fatalf("CloseLogFile failed with %v", err) - } + GlobalLogConfig = &logTest + SetupGlobalLogger() + SetupSubLoggers(logTest.SubLoggers) +} - err = os.Remove(filepath.Join(LogPath, Logger.File)) - if err != nil { - t.Fatal("Test Failed - SetupOutputsValidPath() error could not remove test file", err) +func BenchmarkInfo(b *testing.B) { + SetupTest() + + b.ResetTimer() + for n := 0; n < b.N; n++ { + Info(Global, "Hello this is an info benchmark") } } -func TestSetupOutputsInValidPath(t *testing.T) { - Logger.Enabled = trueptr - Logger.File = "debug.txt" - LogPath = "../testdataa/" - err := setupOutputs() - if err != nil { - if !os.IsNotExist(err) { - t.Fatalf("SetupOutputs failed expected %v got %v", os.ErrNotExist, err) - } +func SetupTestDisabled(t *testing.T) { + SetupDisabled() +} + +func TestAddWriter(t *testing.T) { + mw := MultiWriter() + m := mw.(*multiWriter) + + m.Add(ioutil.Discard) + m.Add(os.Stdin) + m.Add(os.Stdout) + + total := len(m.writers) + + if total != 3 { + t.Errorf("expected m.Writers to be 3 %v", total) } - err = os.Remove(filepath.Join(LogPath, Logger.File)) +} + +func TestRemoveWriter(t *testing.T) { + mw := MultiWriter() + m := mw.(*multiWriter) + + m.Add(ioutil.Discard) + m.Add(os.Stdin) + m.Add(os.Stdout) + + total := len(m.writers) + + m.Remove(os.Stdin) + m.Remove(os.Stdout) + + if len(m.writers) != total-2 { + t.Errorf("expected m.Writers to be %v got %v", total-2, len(m.writers)) + } +} + +func TestLevel(t *testing.T) { + SetupTest() + + _, err := Level("log") + if err != nil { + t.Errorf("Failed to get log %s levels skippin", err) + } + + _, err = Level("totallyinvalidlogger") if err == nil { - t.Fatal("Test Failed - SetupOutputsInValidPath() error cannot be nil") + t.Error("expected error on invalid logger") } } -func BenchmarkDebugf(b *testing.B) { - Logger = &Logging{ - Enabled: trueptr, - Level: "DEBUG", - ColourOutput: false, - File: "", - Rotate: false, +func TestSetLevel(t *testing.T) { + SetupTest() + + newLevel, err := SetLevel("log", "ERROR") + if err != nil { + t.Skipf("Failed to get log %s levels skipping", err) } - SetupLogger() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Debugf("This is a debug benchmark %d", n) + + if newLevel.Info || newLevel.Debug || newLevel.Warn { + t.Error("failed to set level correctly") + } + + if !newLevel.Error { + t.Error("failed to set level correctly") + } + + _, err = SetLevel("abc12345556665", "ERROR") + if err == nil { + t.Error("SetLevel() Should return error on invalid logger") } } -func BenchmarkDebugfLoggerDisabled(b *testing.B) { - clearAllLoggers() - b.ResetTimer() - for n := 0; n < b.N; n++ { - Debugf("this is a debug benchmark") +func TestValidSubLogger(t *testing.T) { + b, logPtr := validSubLogger("log") + + if !b { + t.Skip("validSubLogger() should return found, pointer if valid logger found") + } + if logPtr == nil { + t.Error("validSubLogger() should return a pointer and not nil ") + } +} + +func TestCloseLogger(t *testing.T) { + err := CloseLogger() + if err != nil { + t.Errorf("CloseLogger() failed %v", err) + } +} + +func TestConfigureSubLogger(t *testing.T) { + err := configureSubLogger("log", "INFO", os.Stdin) + if err != nil { + t.Skipf("configureSubLogger() returned unexpected error %v", err) + } + if (Global.Levels != Levels{ + Info: true, + Debug: false, + }) { + t.Error("configureSubLogger() incorrectly configure subLogger") + } +} + +func TestSplitLevel(t *testing.T) { + levelsInfoDebug := splitLevel("INFO|DEBUG") + + expected := Levels{ + Info: true, + Debug: true, + Warn: false, + Error: false, + } + + if levelsInfoDebug != expected { + t.Errorf("splitLevel() returned invalid data expected: %+v got: %+v", expected, levelsInfoDebug) + } +} + +func BenchmarkInfoDisabled(b *testing.B) { + SetupDisabled() + + b.ResetTimer() + for n := 0; n < b.N; n++ { + Info(Global, "Hello this is an info benchmark") + } +} + +func BenchmarkInfof(b *testing.B) { + SetupTest() + + b.ResetTimer() + for n := 0; n < b.N; n++ { + Infof(Global, "Hello this is an infof benchmark %v %v %v\n", n, 1, 2) + } +} + +func BenchmarkInfoln(b *testing.B) { + SetupTest() + + b.ResetTimer() + for n := 0; n < b.N; n++ { + Infoln(Global, "Hello this is an infoln benchmark") + } +} + +func TestNewLogEvent(t *testing.T) { + w := &bytes.Buffer{} + logger.newLogEvent("out", "header", w) + + if w.String() == "" { + t.Error("newLogEvent() failed expected output got empty string") + } + + err := logger.newLogEvent("out", "header", nil) + if err == nil { + t.Error("Error expected with output is set to nil") + } +} + +func TestInfo(t *testing.T) { + w := &bytes.Buffer{} + + tempSL := subLogger{ + "testymctestalot", + splitLevel("INFO|WARN|DEBUG|ERROR"), + w, + } + + Info(&tempSL, "Hello") + + if w.String() == "" { + t.Error("expected Info() to write output to buffer") + } + + tempSL.output = nil + w.Reset() + + SetLevel("testymctestalot", "INFO") + Debug(&tempSL, "HelloHello") + + if w.String() != "" { + t.Error("Expected output buffer to be empty but Debug wrote to output") } } diff --git a/logger/logger_types.go b/logger/logger_types.go index 970d8900..5ec424da 100644 --- a/logger/logger_types.go +++ b/logger/logger_types.go @@ -2,34 +2,88 @@ package logger import ( "io" - "log" - "os" + "sync" ) -// Logging struct that holds all user configurable options for the logger -type Logging struct { - Enabled *bool `json:"enabled,omitempty"` - File string `json:"file"` - ColourOutput bool `json:"colour"` - ColourOutputOverride bool `json:"colourOverride,omitempty"` - Level string `json:"level"` - Rotate bool `json:"rotate"` +const timestampFormat = " 02/01/2006 15:04:05 " + +const spacer = "|" + +// Config holds configuration settings loaded from bot config +type Config struct { + Enabled *bool `json:"enabled"` + SubLoggerConfig + LoggerFileConfig *loggerFileConfig `json:"fileSettings,omitempty"` + AdvancedSettings advancedSettings `json:"advancedSettings"` + SubLoggers []SubLoggerConfig `json:"subloggers,omitempty"` +} + +type advancedSettings struct { + Spacer string `json:"spacer"` + TimeStampFormat string `json:"timeStampFormat"` + Headers headers `json:"headers"` +} + +type headers struct { + Info string `json:"info"` + Warn string `json:"warn"` + Debug string `json:"debug"` + Error string `json:"error"` +} + +// SubLoggerConfig holds sub logger configuration settings loaded from bot config +type SubLoggerConfig struct { + Name string `json:"name,omitempty"` + Level string `json:"level"` + Output string `json:"output"` +} + +type loggerFileConfig struct { + FileName string `json:"filename,omitempty"` + Rotate *bool `json:"rotate,omitempty"` + MaxSize int64 `json:"maxsize,omitempty"` +} + +// Logger each instance of logger settings +type Logger struct { + Timestamp string + InfoHeader, ErrorHeader, DebugHeader, WarnHeader string + Spacer string +} + +type Levels struct { + Info, Debug, Warn, Error bool +} + +type subLogger struct { + name string + Levels + output io.Writer +} + +type LogEvent struct { + data []byte + output io.Writer +} + +type multiWriter struct { + writers []io.Writer + mu sync.Mutex } var ( - debugLogger *log.Logger - infoLogger *log.Logger - warnLogger *log.Logger - errorLogger *log.Logger - fatalLogger *log.Logger + logger = &Logger{} + FileLoggingConfiguredCorrectly bool + GlobalLogConfig = &Config{} // GlobalLogConfig hold global configuration options for logger + GlobalLogFile = &Rotate{} - logFileHandle *os.File + eventPool = &sync.Pool{ + New: func() interface{} { + return &LogEvent{ + data: make([]byte, 0, 80), + } + }, + } - logOutput io.Writer - - // LogPath location to store logs in LogPath string - - // Logger create a pointer to Logging struct for holding data - Logger = &Logging{} ) diff --git a/logger/loggers.go b/logger/loggers.go index 7e6c1f4f..e8fdfb45 100644 --- a/logger/loggers.go +++ b/logger/loggers.go @@ -2,79 +2,160 @@ package logger import ( "fmt" - "log" - "os" ) -// Info handler takes any input returns unformatted output to infoLogger writer -func Info(v ...interface{}) { - infoLogger.Print(v...) +// Info takes a pointer subLogger struct and string sends to newLogEvent +func Info(sl *subLogger, data string) { + if sl == nil { + return + } + + if !sl.Info { + return + } + + logger.newLogEvent(data, logger.InfoHeader, sl.output) } -// Infof handler takes any input infoLogger returns formatted output to infoLogger writer -func Infof(data string, v ...interface{}) { - infoLogger.Printf(data, v...) +// Infoln takes a pointer subLogger struct and interface sends to newLogEvent +func Infoln(sl *subLogger, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Info { + return + } + + logger.newLogEvent(fmt.Sprintln(v...), logger.InfoHeader, sl.output) } -// Infoln handler takes any input infoLogger returns formatted output to infoLogger writer -func Infoln(v ...interface{}) { - infoLogger.Println(v...) +// Infof takes a pointer subLogger struct, string & interface formats and sends to Info() +func Infof(sl *subLogger, data string, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Info { + return + } + + Info(sl, fmt.Sprintf(data, v...)) } -// Print aliased to Standard log.Print -var Print = log.Print +// Debug takes a pointer subLogger struct and string sends to multiwriter +func Debug(sl *subLogger, data string) { + if sl == nil { + return + } -// Printf aliased to Standard log.Printf -var Printf = log.Printf + if !sl.Debug { + return + } -// Println aliased to Standard log.Println -var Println = log.Println - -// Debug handler takes any input returns unformatted output to infoLogger writer -func Debug(v ...interface{}) { - debugLogger.Print(v...) + logger.newLogEvent(data, logger.DebugHeader, sl.output) } -// Debugf handler takes any input infoLogger returns formatted output to infoLogger writer -func Debugf(data string, v ...interface{}) { - debugLogger.Printf(data, v...) +// Debugln takes a pointer subLogger struct, string and interface sends to newLogEvent +func Debugln(sl *subLogger, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Debug { + return + } + + logger.newLogEvent(fmt.Sprintln(v...), logger.DebugHeader, sl.output) } -// Debugln handler takes any input infoLogger returns formatted output to infoLogger writer -func Debugln(v ...interface{}) { - debugLogger.Println(v...) +// Debugf takes a pointer subLogger struct, string & interface formats and sends to Info() +func Debugf(sl *subLogger, data string, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Debug { + return + } + + Debug(sl, fmt.Sprintf(data, v...)) } -// Warn handler takes any input returns unformatted output to warnLogger writer -func Warn(v ...interface{}) { - warnLogger.Print(v...) +// Warn takes a pointer subLogger struct & string and sends to newLogEvent() +func Warn(sl *subLogger, data string) { + if sl == nil { + return + } + + if !sl.Warn { + return + } + + logger.newLogEvent(data, logger.WarnHeader, sl.output) } -// Warnf handler takes any input returns unformatted output to warnLogger writer -func Warnf(data string, v ...interface{}) { - warnLogger.Printf(data, v...) +// Warnln takes a pointer subLogger struct & interface formats and sends to newLogEvent() +func Warnln(sl *subLogger, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Warn { + return + } + + logger.newLogEvent(fmt.Sprintln(v...), logger.WarnHeader, sl.output) } -// Error handler takes any input returns unformatted output to errorLogger writer -func Error(v ...interface{}) { - errorLogger.Print(v...) +// Warnf takes a pointer subLogger struct, string & interface formats and sends to Warn() +func Warnf(sl *subLogger, data string, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Warn { + return + } + + Warn(sl, fmt.Sprintf(data, v...)) } -// Errorf handler takes any input returns unformatted output to errorLogger writer -func Errorf(data string, v ...interface{}) { - errorLogger.Printf(data, v...) +// Error takes a pointer subLogger struct & interface formats and sends to newLogEvent() +func Error(sl *subLogger, data ...interface{}) { + if sl == nil { + return + } + + if !sl.Error { + return + } + + logger.newLogEvent(fmt.Sprint(data...), logger.ErrorHeader, sl.output) } -// Fatal handler takes any input returns unformatted output to fatalLogger writer -func Fatal(v ...interface{}) { - // Send to Output instead of Fatal to allow us to increase the output depth by 1 to make sure the correct file is displayed - fatalLogger.Output(2, fmt.Sprint(v...)) - os.Exit(1) +// Errorln takes a pointer subLogger struct, string & interface formats and sends to newLogEvent() +func Errorln(sl *subLogger, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Error { + return + } + + logger.newLogEvent(fmt.Sprintln(v...), logger.ErrorHeader, sl.output) } -// Fatalf handler takes any input returns unformatted output to fatalLogger writer -func Fatalf(data string, v ...interface{}) { - // Send to Output instead of Fatal to allow us to increase the output depth by 1 to make sure the correct file is displayed - fatalLogger.Output(2, fmt.Sprintf(data, v...)) - os.Exit(1) +// Errorf takes a pointer subLogger struct, string & interface formats and sends to Debug() +func Errorf(sl *subLogger, data string, v ...interface{}) { + if sl == nil { + return + } + + if !sl.Error { + return + } + + Error(sl, fmt.Sprintf(data, v...)) } diff --git a/logger/sublogger_types.go b/logger/sublogger_types.go new file mode 100644 index 00000000..f49ae474 --- /dev/null +++ b/logger/sublogger_types.go @@ -0,0 +1,23 @@ +package logger + +var ( + subLoggers = map[string]*subLogger{} + + Global *subLogger + ConnectionMgr *subLogger + CommunicationMgr *subLogger + ConfigMgr *subLogger + OrderMgr *subLogger + PortfolioMgr *subLogger + SyncMgr *subLogger + TimeMgr *subLogger + WebsocketMgr *subLogger + EventMgr *subLogger + + ExchangeSys *subLogger + GRPCSys *subLogger + RESTSys *subLogger + + Ticker *subLogger + OrderBook *subLogger +) diff --git a/main.go b/main.go index 5ffba2af..7550599e 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,8 @@ import ( func main() { defaultPath, err := config.GetFilePath("") if err != nil { - log.Fatal(err) + log.Errorln(log.Global, err) + os.Exit(1) } // Handle flags @@ -89,7 +90,8 @@ func main() { engine.Bot, err = engine.NewFromSettings(&settings) if engine.Bot == nil || err != nil { - log.Fatalf("Unable to initialise bot engine. Err: %s", err) + log.Errorf(log.Global, "Unable to initialise bot engine. Err: %s\n", err) + os.Exit(1) } engine.PrintSettings(&engine.Bot.Settings) diff --git a/ntpclient/ntpclient.go b/ntpclient/ntpclient.go index 99015cbd..ec52072b 100644 --- a/ntpclient/ntpclient.go +++ b/ntpclient/ntpclient.go @@ -32,7 +32,7 @@ func NTPClient(pool []string) (time.Time, error) { for i := range pool { con, err := net.Dial("udp", pool[i]) if err != nil { - log.Warnf("Unable to connect to hosts %v attempting next", pool[i]) + log.Warnf(log.TimeMgr, "Unable to connect to hosts %v attempting next", pool[i]) continue } diff --git a/portfolio/portfolio.go b/portfolio/portfolio.go index e8862592..9e8002c3 100644 --- a/portfolio/portfolio.go +++ b/portfolio/portfolio.go @@ -416,7 +416,7 @@ func (p *Base) Seed(port Base) { // StartPortfolioWatcher observes the portfolio object func StartPortfolioWatcher() { addrCount := len(Portfolio.Addresses) - log.Debugf( + log.Debugf(log.PortfolioMgr, "PortfolioWatcher started: Have %d entries in portfolio.\n", addrCount, ) for { @@ -424,7 +424,7 @@ func StartPortfolioWatcher() { for key, value := range data { success := Portfolio.UpdatePortfolio(value, key) if success { - log.Debugf( + log.Debugf(log.PortfolioMgr, "PortfolioWatcher: Successfully updated address balance for %s address(es) %s\n", key, value, ) diff --git a/testdata/configtest.json b/testdata/configtest.json index 8ccdff17..786f0365 100644 --- a/testdata/configtest.json +++ b/testdata/configtest.json @@ -1349,4 +1349,4 @@ "checkInterval": 1000000000 }, "fiatDispayCurrency": "" -} \ No newline at end of file +}