From bff14dcc8252dccaf41f22a2b46b34dddb90cb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=8C=E6=B5=B7=E4=BB=B2=E5=AD=90?= Date: Sat, 13 Aug 2022 22:04:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0exceptionless,=E6=94=AF?= =?UTF-8?q?=E6=8C=81error=E5=8E=9F=E7=94=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exceptionless/api.go | 85 +++++++++++++++++ exceptionless/builder.go | 143 ++++++++++++++++++++++++++++ exceptionless/exceptionless.go | 126 +++++++++--------------- exceptionless/exceptionless_test.go | 13 --- exceptionless/log.go | 6 ++ exceptionless/userdescription.go | 7 ++ exceptionless/useridentity.go | 7 ++ go.mod | 3 +- 8 files changed, 296 insertions(+), 94 deletions(-) create mode 100644 exceptionless/api.go create mode 100644 exceptionless/builder.go delete mode 100644 exceptionless/exceptionless_test.go create mode 100644 exceptionless/log.go create mode 100644 exceptionless/userdescription.go create mode 100644 exceptionless/useridentity.go diff --git a/exceptionless/api.go b/exceptionless/api.go new file mode 100644 index 0000000..ee58132 --- /dev/null +++ b/exceptionless/api.go @@ -0,0 +1,85 @@ +package exceptionless + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" +) + +// Post posts to the Exceptionless Server +func Post(endpoint string, postBody string, authorization string) string { + exceptionless := GetClient() + // err := godotenv.Load(".env") + + // if err != nil { + // log.Fatalf("Error loading .env file") + // } + + var baseURL string = os.Getenv("BASE_API_URL") + if exceptionless.ServerURL != "" { + baseURL = exceptionless.ServerURL + } + + url := baseURL + endpoint + var jsonStr = []byte(postBody) + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) + req.Header.Set("Authorization", "Bearer "+authorization) + req.Header.Set("Content-Type", "application/json") + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + panic(err) + } + defer resp.Body.Close() + // body, _ := ioutil.ReadAll(resp.Body) + return string(resp.Status) +} + +// GET makes api GET requests +func Get(endpoint string, authorization string) map[string]interface{} { + exceptionless := GetClient() + // err := godotenv.Load(".env") + + // if err != nil { + // log.Fatalf("Error loading .env file") + // } + + var baseURL string = os.Getenv("BASE_API_URL") + if exceptionless.ServerURL != "" { + baseURL = exceptionless.ServerURL + } + + url := baseURL + endpoint + + httpClient := &http.Client{} + req, err := http.NewRequest("GET", url, nil) + + if err != nil { + fmt.Println(err) + // return "Error" + } + + req.Header.Add("accept", "application/json") + req.Header.Add("Authorization", "Bearer "+authorization) + + res, err := httpClient.Do(req) + if err != nil { + fmt.Println(err) + // return "Error" + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + // return "Error" + } + + // resp := string(body) + var result map[string]interface{} + json.Unmarshal([]byte(body), &result) + return result +} diff --git a/exceptionless/builder.go b/exceptionless/builder.go new file mode 100644 index 0000000..7daf196 --- /dev/null +++ b/exceptionless/builder.go @@ -0,0 +1,143 @@ +package exceptionless + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/google/uuid" +) + +// Event is the main model for events +type Event struct { + EventType string `json:"type"` + Source string `json:"source,omitempty"` + Date string `json:"date,omitempty"` + Tags []string `json:"tags,omitempty"` + Message string `json:"message,omitempty"` + Geo string `json:"geo,omitempty"` + Value uint `json:"value,omitempty"` + Data map[string]interface{} `json:"data,omitempty"` + ReferenceID uuid.UUID `json:"reference_id,omitempty"` + Count uint `json:"count,omitempty"` +} + +// GetBaseEvent returns an empty Event struct that can be built into any type of event. +func GetBaseEvent(eventType string, message string, date string) Event { + return Event{ + EventType: eventType, + Message: message, + Date: date, + } +} + +// AddSource adds a string value source to an event +func AddSource(event Event, source string) Event { + event.Source = source + return event +} + +// AddTags adds a string array of tags for the event +func AddTags(event Event, tags []string) Event { + event.Tags = tags + return event +} + +// AddGeo adds the lat and long location of the user the event impacted +func AddGeo(event Event, geo string) Event { + event.Geo = geo + return event +} + +// AddValue adds an arbitrary number value to the event +func AddValue(event Event, value uint) Event { + event.Value = value + return event +} + +// AddReferenceID adds an indentifier to later refer to this event +func AddReferenceID(event Event, referenceID uuid.UUID) Event { + event.ReferenceID = referenceID + return event +} + +// AddCount adds a number to help track the number of times the event has occurred +func AddCount(event Event, count uint) Event { + event.Count = count + return event +} + +func AddLogLevel(event Event, level string) Event { + var updatedEvent Event + if event.Data != nil { + event.Data["@level"] = level + updatedEvent = event + } else { + data := map[string]interface{}{} + data["@level"] = level + updatedEvent = AddData(event, data) + } + return updatedEvent +} + +// AddData adds a string mapping to create a data object of additional values +func AddData(event Event, data map[string]interface{}) Event { + event.Data = data + return event +} + +// SubmitError is a convenience wrapper to quickly build and submit an error +func SubmitError(err error) string { + exceptionlessClient := GetClient() + if exceptionlessClient.UpdateSettingsWhenIdleInterval > 0 { + config := GetConfig() + fmt.Println(config) + // We are stripping out info accoring to the config settings + } + referenceID := uuid.Must(uuid.NewUUID()) + errorMap := map[string]interface{}{} + errorMap["type"] = "error" + errorMap["message"] = err.Error() + errorMap["date"] = time.Now().Format(time.RFC3339) + data := map[string]interface{}{} + data["@simple_error"] = errorMap + var mainEvent = Event{ + EventType: "error", + Message: err.Error(), + Data: data, + ReferenceID: referenceID, + } + json, err := json.Marshal(mainEvent) + if err != nil { + fmt.Println(err) + return err.Error() + } + resp := SubmitEvent(string(json)) + return resp +} + +func SubmitLog(message string, level string) string { + exceptionlessClient := GetClient() + referenceID := uuid.Must(uuid.NewUUID()) + if exceptionlessClient.UpdateSettingsWhenIdleInterval > 0 { + config := GetConfig() + fmt.Println(config) + // We are stripping out info accoring to the config settings + // We would also prevent logs of levels below the log level set by the settings + } + var event Event + date := time.Now().Format(time.RFC3339) + event = GetBaseEvent("log", message, date) + event = AddReferenceID(event, referenceID) + data := map[string]interface{}{} + data["@level"] = level + event = AddData(event, data) + + json, err := json.Marshal(event) + if err != nil { + fmt.Println(err) + return err.Error() + } + resp := SubmitEvent(string(json)) + return resp +} diff --git a/exceptionless/exceptionless.go b/exceptionless/exceptionless.go index b23d958..d95b44c 100644 --- a/exceptionless/exceptionless.go +++ b/exceptionless/exceptionless.go @@ -1,99 +1,67 @@ package exceptionless import ( - "crypto/tls" - "encoding/json" - "errors" "fmt" - "io/ioutil" - "net/http" - "strings" + "math/rand" "time" ) -type Config struct { - URL string - Token string +var config map[string]interface{} = nil + +// Exceptionless type defines the client configuration structure +type Exceptionless struct { + ApiKey string + ServerURL string + UpdateSettingsWhenIdleInterval int32 + IncludePrivateInformation bool } -var conf *Config +var client = Exceptionless{} -func Init(config *Config) error { - if config == nil { - return errors.New("nil of Config") - } - conf = config - conf.Token = "Bearer " + conf.Token - return nil +func main() { + handlePolling() } -func post(uri string, body interface{}) (*[]byte, error) { - url := fmt.Sprintf(`%s/%s`, conf.URL, uri) - reqbody, _ := json.Marshal(body) - req, err := http.NewRequest("POST", url, strings.NewReader(string(reqbody))) - if err != nil { - return nil, err +func handlePolling() { + if client.ApiKey != "" && client.UpdateSettingsWhenIdleInterval > 0 { + fmt.Println("polling!") + poll() } - - req.Header.Add("Authorization", conf.Token) - req.Header.Add("Content-Type", "application/json") - - tr := &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - } - client := &http.Client{Transport: tr} - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode == 202 { - return nil, nil - } - respBody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - return &respBody, nil } -func WriteMessages(msg string) { - message := &struct { - Message string - }{ - Message: msg, - } - post("api/v2/events", message) +// Configure is the function that creates an Exceptionless client +func Configure(config Exceptionless) Exceptionless { + client = config + handlePolling() + return client } -func WriteLogs(msg string) { - message := &struct { - Message string - Type string - Date string - }{ - Type: "log", - Message: msg, - Date: time.Now().Format("2006-01-02 15:04:05"), - } - post("api/v2/events", message) +// GetClient returns the Exceptionless client +func GetClient() Exceptionless { + return client } -func WriteErrors(msg string) { - message := &struct { - SimpleError interface{} - Type string - Date string - }{ - Type: "error", - SimpleError: &struct { - Message string - }{ - Message: msg, - }, - Date: time.Now().Format("2006-01-02 15:04:05"), - } - post("api/v2/events", message) +// GetConfig returns the project configuration +func GetConfig() map[string]interface{} { + return config +} + +// SubmitEvent sends log events to Exceptionless +func SubmitEvent(eventBody string) string { + if client.ApiKey == "" { + fmt.Println("is zero value") + } + resp := Post("events", eventBody, client.ApiKey) + return resp +} + +func poll() { + r := rand.New(rand.NewSource(99)) + c := time.Tick(10 * time.Second) + for _ = range c { + resp := Get("projects/config", client.ApiKey) + config = resp + jitter := time.Duration(r.Int31n(client.UpdateSettingsWhenIdleInterval)) * time.Millisecond + time.Sleep(jitter) + } } diff --git a/exceptionless/exceptionless_test.go b/exceptionless/exceptionless_test.go deleted file mode 100644 index 76d24e8..0000000 --- a/exceptionless/exceptionless_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package exceptionless - -import "testing" - -func TestWriteMessage(t *testing.T) { - Init(&Config{ - URL: "https://api.exceptionless.com", - Token: "MyNc2Rmfymq1XJ52rJdPW021zbQiAbzdxV92znbm", - }) - // WriteMessages("adfasdfadsfsdf") - // WriteLogs("aaasfas222rwerwer") - WriteErrors("bbbbbb") -} diff --git a/exceptionless/log.go b/exceptionless/log.go new file mode 100644 index 0000000..8d7a42e --- /dev/null +++ b/exceptionless/log.go @@ -0,0 +1,6 @@ +package exceptionless + +func createLog(source string, message string, level string, geo string, referenceID string, date string, value uint) { + // event := BuildEvent("log", message, source, nil, nil, nil, nil, nil, nil) + // fmt.Println(event) +} diff --git a/exceptionless/userdescription.go b/exceptionless/userdescription.go new file mode 100644 index 0000000..1083c38 --- /dev/null +++ b/exceptionless/userdescription.go @@ -0,0 +1,7 @@ +package exceptionless + +type UserDescription struct { + email string + description string + data string +} diff --git a/exceptionless/useridentity.go b/exceptionless/useridentity.go new file mode 100644 index 0000000..2750cd3 --- /dev/null +++ b/exceptionless/useridentity.go @@ -0,0 +1,7 @@ +package exceptionless + +type UserIdentity struct { + identity string + name string + data string +} diff --git a/go.mod b/go.mod index 196de7b..a17ff02 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,10 @@ go 1.17 require ( github.com/eclipse/paho.mqtt.golang v1.2.0 github.com/gin-gonic/gin v1.7.4 - github.com/gofrs/uuid v3.3.0+incompatible github.com/gomodule/redigo v1.8.5 + github.com/google/uuid v1.1.2 github.com/hashicorp/consul/api v1.10.1 github.com/influxdata/influxdb v1.9.5 - github.com/sirupsen/logrus v1.7.0 github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.0 go.mongodb.org/mongo-driver v1.7.4