Skip to content

Commit

Permalink
feat/groundwork-output: improve plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Pavlo Sumkin committed Jul 4, 2022
1 parent cbc75a2 commit 36f9e1c
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 61 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ require (
github.com/gorilla/websocket v1.4.2
github.com/gosnmp/gosnmp v1.34.0
github.com/grid-x/modbus v0.0.0-20211113184042-7f2251c342c9
github.com/gwos/tcg/sdk v0.0.0-20211223101342-35fbd1ae683c
github.com/gwos/tcg/sdk v0.0.0-20220621192633-df0eac0a1a4c
github.com/harlow/kinesis-consumer v0.3.6-0.20210911031324-5a873d6e9fec
github.com/hashicorp/consul/api v1.12.0
github.com/hashicorp/go-uuid v1.0.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1256,8 +1256,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.14.5/go.mod h1:UJ0EZAp832vCd54Wev9N1BM
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/gwos/tcg/sdk v0.0.0-20211223101342-35fbd1ae683c h1:befb5xGUwNCoBuN/akLFCKekUzr0ixyws3aAX/7TaOk=
github.com/gwos/tcg/sdk v0.0.0-20211223101342-35fbd1ae683c/go.mod h1:OjlJNRXwlEjznVfU3YtLWH8FyM7KWHUevXDI47UeZeM=
github.com/gwos/tcg/sdk v0.0.0-20220621192633-df0eac0a1a4c h1:pVr0TkSFnMP4BWSsEak/4bxD8/K+foJ9V8DGyZ6PIDE=
github.com/gwos/tcg/sdk v0.0.0-20220621192633-df0eac0a1a4c/go.mod h1:4yzxLBACr76Is0AMAkE0F/fqWBk28p2tzeO06yDGR/Y=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/harlow/kinesis-consumer v0.3.6-0.20210911031324-5a873d6e9fec h1:ya+kv1eNnd5QhcHuaj5g5eMq5Ra3VCNaPY2ZI7Aq91o=
Expand Down
2 changes: 1 addition & 1 deletion plugins/outputs/groundwork/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ GW8+
* status - to define the status of the service. Supported statuses:
"SERVICE_OK", "SERVICE_WARNING", "SERVICE_UNSCHEDULED_CRITICAL",
"SERVICE_PENDING", "SERVICE_SCHEDULED_CRITICAL", "SERVICE_UNKNOWN".
* message - to provide any message you want.
* message - to provide any message you want, it overrides message field value.
* unitType - to use in monitoring contexts(subset of The Unified Code for Units
of Measure standard). Supported types: "1", "%cpu", "KB", "GB", "MB".
* warning - to define warning threshold value.
Expand Down
53 changes: 31 additions & 22 deletions plugins/outputs/groundwork/groundwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,6 @@ func (g *Groundwork) parseMetric(metric telegraf.Metric) (metricMeta, *transit.M
status = value
}

message := ""
if m, ok := metric.GetTag("message"); ok {
message = m
}
if m, ok := metric.GetField("message"); ok {
message = m.(string)
}

unitType := string(transit.UnitCounter)
if value, present := metric.GetTag("unitType"); present {
unitType = value
Expand Down Expand Up @@ -267,15 +259,38 @@ func (g *Groundwork) parseMetric(metric telegraf.Metric) (metricMeta, *transit.M
Owner: resource,
},
MonitoredInfo: transit.MonitoredInfo{
Status: transit.MonitorStatus(status),
LastCheckTime: lastCheckTime,
NextCheckTime: lastCheckTime, // if not added, GW will make this as LastCheckTime + 5 mins
LastPluginOutput: message,
Status: transit.MonitorStatus(status),
LastCheckTime: lastCheckTime,
NextCheckTime: lastCheckTime, // if not added, GW will make this as LastCheckTime + 5 mins
},
Metrics: nil,
}

for _, value := range metric.FieldList() {
if value.Key == "message" {
switch m := value.Value.(type) {
case string:
serviceObject.LastPluginOutput = m
case []byte:
serviceObject.LastPluginOutput = string(m)
default:
serviceObject.LastPluginOutput = fmt.Sprintf("%v", m)
}
continue
}

switch value.Value.(type) {
case string, []byte:
g.Log.Warnf("string values are not supported, skipping field %s: %q", value.Key, value.Value)
continue
}

typedValue := transit.NewTypedValue(value.Value)
if typedValue == nil {
g.Log.Warnf("could not convert type %T, skipping field %s: %v", value.Value, value.Key, value.Value)
continue
}

var thresholds []transit.ThresholdValue
if warningPresent {
thresholds = append(thresholds, transit.ThresholdValue{
Expand All @@ -298,16 +313,6 @@ func (g *Groundwork) parseMetric(metric telegraf.Metric) (metricMeta, *transit.M
})
}

typedValue := transit.NewTypedValue(value.Value)
if typedValue == nil {
g.Log.Warnf("could not convert type %T, skipping field %s: %v", value.Value, value.Key, value.Value)
continue
}
if typedValue.ValueType == transit.StringType {
g.Log.Warnf("string values are not supported, skipping field %s: %q", value.Key, value.Value)
continue
}

serviceObject.Metrics = append(serviceObject.Metrics, transit.TimeSeries{
MetricName: value.Key,
SampleType: transit.Value,
Expand All @@ -329,6 +334,10 @@ func (g *Groundwork) parseMetric(metric telegraf.Metric) (metricMeta, *transit.M
serviceObject.Status = serviceStatus
}

if m, ok := metric.GetTag("message"); ok {
serviceObject.LastPluginOutput = m
}

return metricMeta{resource: resource, group: group}, &serviceObject, nil
}

Expand Down
94 changes: 59 additions & 35 deletions plugins/outputs/groundwork/groundwork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/gwos/tcg/sdk/clients"
"github.com/gwos/tcg/sdk/transit"
"github.com/stretchr/testify/require"

"github.com/influxdata/telegraf"
Expand All @@ -32,23 +33,24 @@ func TestWriteWithDefaults(t *testing.T) {
require.NoError(t, err)

// Decode body to use in assertions below
var obj groundworkObject
var obj transit.ResourcesWithServicesRequest
err = json.Unmarshal(body, &obj)
require.NoError(t, err)

// Check if server gets valid metrics object
// Check if server gets proper data
require.Equal(t, defaultTestAgentID, obj.Context.AgentID)
require.Equal(t, customAppType, obj.Context.AppType)
require.Equal(t, defaultHost, obj.Resources[0].Name)
require.Equal(t, "IntMetric", obj.Resources[0].Services[0].Name)
require.Equal(t, int64(42), obj.Resources[0].Services[0].Metrics[0].Value.IntegerValue)
require.Equal(t, int64(42), *obj.Resources[0].Services[0].Metrics[0].Value.IntegerValue)
require.Equal(t, 0, len(obj.Groups))

_, err = fmt.Fprintln(w, `OK`)
_, err = fmt.Fprintln(w, "OK")
require.NoError(t, err)
}))

i := Groundwork{
Log: testutil.Logger{},
Server: server.URL,
AgentID: defaultTestAgentID,
DefaultHost: defaultHost,
Expand All @@ -68,9 +70,56 @@ func TestWriteWithDefaults(t *testing.T) {
defer server.Close()
}

func TestWriteWithFields(t *testing.T) {
// Generate test metric with fields to test Write logic
floatMetric := testutil.TestMetric(1.0, "FloatMetric")
floatMetric.AddField("message", "Test Message")

// Simulate Groundwork server that should receive custom metrics
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)

// Decode body to use in assertions below
var obj transit.ResourcesWithServicesRequest
err = json.Unmarshal(body, &obj)
require.NoError(t, err)

// Check if server gets proper data
require.Equal(t, "Test Message", obj.Resources[0].Services[0].MonitoredInfo.LastPluginOutput)

_, err = fmt.Fprintln(w, "OK")
require.NoError(t, err)
}))

i := Groundwork{
Log: testutil.Logger{},
Server: server.URL,
AgentID: defaultTestAgentID,
DefaultHost: defaultHost,
DefaultAppType: defaultAppType,
GroupTag: "group",
ResourceTag: "host",
client: clients.GWClient{
AppName: "telegraf",
AppType: defaultAppType,
GWConnection: &clients.GWConnection{
HostName: server.URL,
},
},
}

err := i.Write([]telegraf.Metric{floatMetric})
require.NoError(t, err)

defer server.Close()
}

func TestWriteWithTags(t *testing.T) {
// Generate test metric with tags to test Write logic
floatMetric := testutil.TestMetric(1.0, "FloatMetric")
floatMetric.AddField("message", "Test Message")
floatMetric.AddTag("message", "Test Tag")
floatMetric.AddTag("host", "Host01")
floatMetric.AddTag("group", "Group01")

Expand All @@ -80,24 +129,26 @@ func TestWriteWithTags(t *testing.T) {
require.NoError(t, err)

// Decode body to use in assertions below
var obj groundworkObject
var obj transit.ResourcesWithServicesRequest
err = json.Unmarshal(body, &obj)
require.NoError(t, err)

// Check if server gets valid metrics object
// Check if server gets proper data
require.Equal(t, defaultTestAgentID, obj.Context.AgentID)
require.Equal(t, defaultAppType, obj.Context.AppType)
require.Equal(t, "Host01", obj.Resources[0].Name)
require.Equal(t, "FloatMetric", obj.Resources[0].Services[0].Name)
require.Equal(t, 1.0, obj.Resources[0].Services[0].Metrics[0].Value.DoubleValue)
require.Equal(t, 1.0, *obj.Resources[0].Services[0].Metrics[0].Value.DoubleValue)
require.Equal(t, "Group01", obj.Groups[0].GroupName)
require.Equal(t, "Host01", obj.Groups[0].Resources[0].Name)
require.Equal(t, "Test Tag", obj.Resources[0].Services[0].MonitoredInfo.LastPluginOutput)

_, err = fmt.Fprintln(w, `OK`)
_, err = fmt.Fprintln(w, "OK")
require.NoError(t, err)
}))

i := Groundwork{
Log: testutil.Logger{},
Server: server.URL,
AgentID: defaultTestAgentID,
DefaultHost: defaultHost,
Expand All @@ -118,30 +169,3 @@ func TestWriteWithTags(t *testing.T) {

defer server.Close()
}

type groundworkObject struct {
Context struct {
AgentID string `json:"agentId"`
AppType string `json:"appType"`
} `json:"context"`
Resources []struct {
Name string `json:"name"`
Services []struct {
Name string `json:"name"`
Metrics []struct {
Value struct {
DoubleValue float64 `json:"doubleValue"`
IntegerValue int64 `json:"integerValue"`
} `json:"value"`
}
} `json:"services"`
} `json:"resources"`
Groups []struct {
Type string `json:"type"`
GroupName string `json:"groupName"`
Resources []struct {
Name string `json:"name"`
Type string `json:"type"`
} `json:"resources"`
} `json:"groups"`
}
3 changes: 3 additions & 0 deletions plugins/outputs/groundwork/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
username = ""
password = ""

## Default application type to use in GroundWork client
# default_app_type = "TELEGRAF"

## Default display name for the host with services(metrics).
# default_host = "telegraf"

Expand Down

0 comments on commit 36f9e1c

Please sign in to comment.