From 21f02714f952f4a14f14d347dbff655f14d9e15a Mon Sep 17 00:00:00 2001 From: smithclay Date: Thu, 13 Jun 2024 15:24:33 -0700 Subject: [PATCH 1/3] update event payload to send JSON object --- collector/components/servicenowexporter/servicenow.go | 9 ++------- .../components/servicenowexporter/servicenow_event.go | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/collector/components/servicenowexporter/servicenow.go b/collector/components/servicenowexporter/servicenow.go index 1a5104d..dd85dd7 100644 --- a/collector/components/servicenowexporter/servicenow.go +++ b/collector/components/servicenowexporter/servicenow.go @@ -3,7 +3,6 @@ package servicenowexporter import ( "bytes" "context" - "encoding/json" "strconv" "strings" @@ -362,7 +361,7 @@ func buildPath(name string, attributes pcommon.Map) string { return buf.String() } -func formatAdditionalInfo(attrs map[string]string, resourceAttrs map[string]string) (string, error) { +func formatAdditionalInfo(attrs map[string]string, resourceAttrs map[string]string) (map[string]string, error) { // merge attrs + resource attrs newAttrs := make(map[string]string) for k, v := range resourceAttrs { @@ -383,11 +382,7 @@ func formatAdditionalInfo(attrs map[string]string, resourceAttrs map[string]stri newAttrs[k] = v } - bytes, err := json.Marshal(newAttrs) - if err != nil { - return "", err - } - return string(bytes), nil + return newAttrs, nil } func formatNode(resourceAttrs map[string]string) string { diff --git a/collector/components/servicenowexporter/servicenow_event.go b/collector/components/servicenowexporter/servicenow_event.go index 3447f80..f1ae84c 100644 --- a/collector/components/servicenowexporter/servicenow_event.go +++ b/collector/components/servicenowexporter/servicenow_event.go @@ -15,6 +15,6 @@ type ServiceNowEvent struct { Description string `json:"description"` Timestamp string `json:"time_of_event"` // yyyy-MM-dd HH:mm:ss // k8s.cluster.name:test-cluster,k8s.cluster.uid=12345 - AdditionalInfo string `json:"additional_info,omitempty"` // actually a json string - Source string `json:"source"` + AdditionalInfo map[string]string `json:"additional_info,omitempty"` // actually a json string + Source string `json:"source"` } From c8deb934579c22b543555a064f7d97e25c13f7be Mon Sep 17 00:00:00 2001 From: smithclay Date: Thu, 13 Jun 2024 15:46:53 -0700 Subject: [PATCH 2/3] normalize metadata --- .../components/servicenowexporter/servicenow.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/collector/components/servicenowexporter/servicenow.go b/collector/components/servicenowexporter/servicenow.go index dd85dd7..08731c0 100644 --- a/collector/components/servicenowexporter/servicenow.go +++ b/collector/components/servicenowexporter/servicenow.go @@ -202,7 +202,17 @@ func (e *serviceNowProducer) writeNumberDataPoints(metricName string, scope stri func ci2metricAttrs(rAttrs pcommon.Map) map[string]string { attrs := make(map[string]string) rAttrs.Range(func(k string, v pcommon.Value) bool { - attrs[k] = v.AsString() + if v.Type() == pcommon.ValueTypeStr { + attrs[k] = v.AsString() + } + if v.Type() == pcommon.ValueTypeMap { + v.Map().Range(func(k2 string, v2 pcommon.Value) bool { + if v2.Type() == pcommon.ValueTypeStr { + attrs[k+"."+k2] = v2.AsString() + } + return true + }) + } return true }) return attrs @@ -347,6 +357,9 @@ func buildPath(name string, attributes pcommon.Map) string { buf.WriteString(name) attributes.Range(func(k string, v pcommon.Value) bool { + if v.Type() != pcommon.ValueTypeStr { + return true + } value := v.AsString() if value == "" { value = tagValueEmptyPlaceholder From bdd2d8f8e2868017c7d41f0b08bf065f410ef2c6 Mon Sep 17 00:00:00 2001 From: smithclay Date: Fri, 14 Jun 2024 18:35:31 -0700 Subject: [PATCH 3/3] flatten json payload --- .../components/servicenowexporter/client.go | 42 ++++++++++--------- .../servicenowexporter/servicenow_event.go | 4 -- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/collector/components/servicenowexporter/client.go b/collector/components/servicenowexporter/client.go index e11e6a7..cc012ed 100644 --- a/collector/components/servicenowexporter/client.go +++ b/collector/components/servicenowexporter/client.go @@ -45,29 +45,31 @@ func (c *midClient) Close() { c.httpClient.CloseIdleConnections() } -func (c *midClient) sendEvents(payload []ServiceNowEvent) error { +func (c *midClient) sendEvents(events []ServiceNowEvent) error { url := c.config.PushEventsURL - request := ServiceNowEventRequestBody{Records: payload} - c.logger.Info("Sending events to ServiceNow", zap.String("url", url), zap.Any("request", request)) - body, err := json.Marshal(request) - if err != nil { - return err - } - r, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) - if err != nil { - return err - } - r.Header.Set("Content-Type", "application/json") - r.SetBasicAuth(c.config.Username, string(c.config.Password)) - res, err := c.httpClient.Do(r) - if err != nil { - return err - } - defer res.Body.Close() + for e := range events { + c.logger.Info("Sending event to ServiceNow", zap.String("url", url), zap.Any("event", e)) + body, err := json.Marshal(e) + if err != nil { + return err + } + r, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) + if err != nil { + return err + } + r.Header.Set("Content-Type", "application/json") + r.SetBasicAuth(c.config.Username, string(c.config.Password)) - if res.StatusCode != 200 { - return handleNon200Response(res) + res, err := c.httpClient.Do(r) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + handleNon200Response(res) + } } return nil diff --git a/collector/components/servicenowexporter/servicenow_event.go b/collector/components/servicenowexporter/servicenow_event.go index f1ae84c..70f55f5 100644 --- a/collector/components/servicenowexporter/servicenow_event.go +++ b/collector/components/servicenowexporter/servicenow_event.go @@ -1,9 +1,5 @@ package servicenowexporter -type ServiceNowEventRequestBody struct { - Records []ServiceNowEvent `json:"records"` -} - // https://docs.servicenow.com/bundle/vancouver-it-operations-management/page/product/event-management/task/send-events-via-web-service.html type ServiceNowEvent struct { // The resource on the node impacted