Skip to content

Commit

Permalink
Merge pull request #1 from LiveRamp/attributes
Browse files Browse the repository at this point in the history
New Attributes Collector and Status Collector bugfix.
  • Loading branch information
blaubaer authored Jun 20, 2017
2 parents 9b0165f + 6dfaa6b commit 0b48abd
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 42 deletions.
82 changes: 82 additions & 0 deletions Attributes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"fmt"
"github.com/golang/protobuf/proto"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)

type Attributes struct {
CurrentStatus *CurrentStatus
}

func NewAttributesFor(currentStatus *CurrentStatus) *Attributes {
return &Attributes{
CurrentStatus: currentStatus,
}
}

func (instance *Attributes) Describe(ch chan<- *prometheus.Desc) {
ch <- instance.Desc()
}

func (instance *Attributes) Desc() *prometheus.Desc {
return prometheus.NewDesc(
fmt.Sprintf("%s_monitor_attribute", namespace),
"Attributes of the target monitor",
[]string{},
prometheus.Labels{},
)
}

func (instance *Attributes) Collect(ch chan<- prometheus.Metric) {
for _, monitor := range (*instance).CurrentStatus.Data.Monitors {
element := &AttributesElement{
Parent: instance,
Monitor: monitor,
}
ch <- element
}
for _, monitorGroup := range (*instance).CurrentStatus.Data.MonitorGroups {
for _, monitor := range monitorGroup.Monitors {
element := &AttributesElement{
Parent: instance,
MonitorGroup: monitorGroup,
Monitor: monitor,
}
ch <- element
}
}
}

type AttributesElement struct {
Parent *Attributes
MonitorGroup CurrentStatusMonitorGroup
Monitor CurrentStatusMonitor
}

func (instance *AttributesElement) Write(out *dto.Metric) error {
var attrValue, err = instance.Monitor.AttributeValue()
// Eat the error by setting |attrValue| to something invalid. We don't want
// a '-' entry to prevent collecting other metrics, and we must write
// something to |out| in this pass.
if err != nil {
attrValue = -1
}

out.Gauge = &dto.Gauge{Value: proto.Float64(float64(attrValue))}
label := []*dto.LabelPair{
labelPairFor("attributeKey", instance.Monitor.AttributeKey),
labelPairFor("monitorId", instance.Monitor.Id),
labelPairFor("monitorDisplayName", instance.Monitor.Name),
labelPairFor("monitorGroupId", instance.MonitorGroup.Id),
labelPairFor("monitorGroupDisplayName", instance.MonitorGroup.Name),
}
out.Label = label
return nil
}

func (instance *AttributesElement) Desc() *prometheus.Desc {
return instance.Parent.Desc()
}
57 changes: 42 additions & 15 deletions CurrentStatus.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,60 @@
package main

import (
"encoding/json"
"errors"
)

var (
// String value returned by current_status API to indicate 'no value'.
dashValue = `"-"`

// Error value returned by AttributeValue() in case |dashValue| is observed.
errUndefined = errors.New("no metric value")
)

type CurrentStatus struct {
Code int `json:"code"`
ErrorCode int `json:"error_code"`
Message string `json:"message"`
Data CurrentStatusData `json:"data"`
Code int `json:"code"`
ErrorCode int `json:"error_code"`
Message string `json:"message"`
Data CurrentStatusData `json:"data"`
}

type CurrentStatusData struct {
Monitors []CurrentStatusMonitor `json:"monitors"`
Monitors []CurrentStatusMonitor `json:"monitors"`
MonitorGroups []CurrentStatusMonitorGroup `json:"monitor_groups"`
}

type CurrentStatusMonitorGroup struct {
Id string `json:"group_id"`
Name string `json:"group_name"`
Status int `json:"status"`
Id string `json:"group_id"`
Name string `json:"group_name"`
Status int `json:"status"`
Monitors []CurrentStatusMonitor `json:"monitors"`
}

type CurrentStatusMonitor struct {
Id string `json:"monitor_id"`
Name string `json:"name"`
Type string `json:"monitor_type"`
Status int `json:"status"`
Locations []CurrentStatusLocation `json:"locations"`
Id string `json:"monitor_id"`
Name string `json:"name"`
Type string `json:"monitor_type"`
Status int `json:"status"`
AttributeKey string `json:"attribute_key"`
RawAttributeValue json.RawMessage `json:"attribute_value"`
Locations []CurrentStatusLocation `json:"locations"`
}

type CurrentStatusLocation struct {
Name string `json:"location_name"`
Status int `json:"status"`
Name string `json:"location_name"`
Status int `json:"status"`
}

// If the raw |AttributeValue| equals the empty "-", coerce to -1.
// Otherwise unmarshal as an integer.
func (csm CurrentStatusMonitor) AttributeValue() (int, error) {
if string(csm.RawAttributeValue) == dashValue {
return 0, errUndefined
} else {
var i int
var err = json.Unmarshal(csm.RawAttributeValue, &i)
return i, err
}
}
20 changes: 8 additions & 12 deletions Status.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (
)

type Status struct {
CurrentStatus *CurrentStatus
CurrentStatus *CurrentStatus
}

func NewStatusFor(currentStatus *CurrentStatus) *Status {
return &Status{
CurrentStatus: currentStatus,
CurrentStatus: currentStatus,
}
}

Expand All @@ -33,17 +33,17 @@ func (instance *Status) Desc() *prometheus.Desc {
func (instance *Status) Collect(ch chan<- prometheus.Metric) {
for _, monitor := range (*instance).CurrentStatus.Data.Monitors {
element := &StatusElement{
Parent: instance,
Parent: instance,
Monitor: monitor,
}
ch <- element
}
for _, monitorGroup := range (*instance).CurrentStatus.Data.MonitorGroups {
for _, monitor := range monitorGroup.Monitors {
element := &StatusElement{
Parent: instance,
Parent: instance,
MonitorGroup: monitorGroup,
Monitor: monitor,
Monitor: monitor,
}
ch <- element
}
Expand All @@ -57,16 +57,12 @@ type StatusElement struct {
}

func (instance *StatusElement) Write(out *dto.Metric) error {
out.Counter = &dto.Counter{Value: proto.Float64(float64(instance.Monitor.Status))}
out.Gauge = &dto.Gauge{Value: proto.Float64(float64(instance.Monitor.Status))}
label := []*dto.LabelPair{
labelPairFor("monitorId", instance.Monitor.Id),
labelPairFor("monitorDisplayName", instance.Monitor.Name),
}
if instance.MonitorGroup.Id != "" {
label = append(label,
labelPairFor("monitorGroupId", instance.MonitorGroup.Id),
labelPairFor("monitorGroupDisplayName", instance.MonitorGroup.Name),
)
labelPairFor("monitorGroupId", instance.MonitorGroup.Id),
labelPairFor("monitorGroupDisplayName", instance.MonitorGroup.Name),
}
out.Label = label
return nil
Expand Down
21 changes: 6 additions & 15 deletions exporter.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package main

import (
"crypto/tls"
"encoding/json"
"fmt"
"github.com/echocat/site24x7_exporter/utils"
"github.com/prometheus/client_golang/prometheus"
"log"
"net"
"net/http"
"net/url"
"sync"
"time"
"crypto/tls"
"github.com/echocat/site24x7_exporter/utils"
)

var (
Expand Down Expand Up @@ -107,16 +107,6 @@ func (instance *Site24x7Exporter) retrieveCurrentStatus() (*CurrentStatus, error
return &restObject, nil
}

func (instance *Site24x7Exporter) retrieveStatus() (*Status, error) {
currentStatus, err := instance.retrieveCurrentStatus()
if err != nil {
return nil, err
}
return NewStatusFor(
currentStatus,
), nil
}

// Describe describes all the metrics ever exported by the
// exporter. It implements prometheus.Collector.
func (instance *Site24x7Exporter) Describe(ch chan<- *prometheus.Desc) {
Expand All @@ -130,11 +120,12 @@ func (instance *Site24x7Exporter) Collect(ch chan<- prometheus.Metric) {
instance.mutex.Lock() // To protect metrics from concurrent collects.
defer instance.mutex.Unlock()

status, err := instance.retrieveStatus()
currentStatus, err := instance.retrieveCurrentStatus()
if err != nil {
log.Printf("Failed to retreive status. Cause: %v", err)
log.Printf("Failed to retreive current status. Cause: %v", err)
return
}

status.Collect(ch)
NewStatusFor(currentStatus).Collect(ch)
NewAttributesFor(currentStatus).Collect(ch)
}

0 comments on commit 0b48abd

Please sign in to comment.