Godep: Add raidman riemann client

This commit is contained in:
Cameron Sparr 2015-11-18 14:27:10 -07:00
parent 0823eed546
commit a8294c2c34
16 changed files with 1051 additions and 404 deletions

46
Godeps/Godeps.json generated
View File

@ -22,6 +22,10 @@
"Comment": "v0.8.6-7-g9c060de",
"Rev": "9c060de643590dae45da9d7c26276463bfc46fa0"
},
{
"ImportPath": "github.com/amir/raidman",
"Rev": "6a8e089bbe32e6b907feae5ba688841974b3c339"
},
{
"ImportPath": "github.com/armon/go-metrics",
"Rev": "b2d95e5291cdbc26997d1301a5e467ecbb240e25"
@ -164,7 +168,47 @@
"Rev": "5bb5cfc093ad18a28148c578f8632cfdb4d802e4"
},
{
"ImportPath": "github.com/shirou/gopsutil",
"ImportPath": "github.com/shirou/gopsutil/common",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/cpu",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/disk",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/docker",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/host",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/load",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/mem",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/net",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},
{
"ImportPath": "github.com/shirou/gopsutil/process",
"Comment": "1.0.0-173-g1e9aabb",
"Rev": "1e9aabb3c8132314662698c9d1c0aef68d9da617"
},

View File

@ -0,0 +1,73 @@
Raidman
=======
Go Riemann client
```go
package main
import (
"github.com/amir/raidman"
)
func main() {
c, err := raidman.Dial("tcp", "localhost:5555")
if err != nil {
panic(err)
}
var event = &raidman.Event{
State: "success",
Host: "raidman",
Service: "raidman-sample",
Metric: 100,
Ttl: 10,
}
// send one event
err = c.Send(event)
if err != nil {
panic(err)
}
// send multiple events at once
err = c.SendMulti([]*raidman.Event{
&raidman.Event{
State: "success",
Host: "raidman",
Service: "raidman-sample",
Metric: 100,
Ttl: 10,
},
&raidman.Event{
State: "failure",
Host: "raidman",
Service: "raidman-sample",
Metric: 100,
Ttl: 10,
},
&raidman.Event{
State: "success",
Host: "raidman",
Service: "raidman-sample",
Metric: 100,
Ttl: 10,
},
})
if err != nil {
panic(err)
}
events, err := c.Query("host = \"raidman\"")
if err != nil {
panic(err)
}
if len(events) < 1 {
panic("Submitted event not found")
}
c.Close()
}
```

View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View File

@ -0,0 +1,6 @@
proto.pb.go: proto.proto
mkdir -p _pb
protoc --go_out=_pb $<
cat _pb/$@\
|gofmt >$@
rm -rf _pb

View File

@ -0,0 +1,273 @@
// Code generated by protoc-gen-go.
// source: proto.proto
// DO NOT EDIT!
package proto
import proto1 "github.com/golang/protobuf/proto"
import json "encoding/json"
import math "math"
// Reference proto, json, and math imports to suppress error if they are not otherwise used.
var _ = proto1.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf
type State struct {
Time *int64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
State *string `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"`
Service *string `protobuf:"bytes,3,opt,name=service" json:"service,omitempty"`
Host *string `protobuf:"bytes,4,opt,name=host" json:"host,omitempty"`
Description *string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"`
Once *bool `protobuf:"varint,6,opt,name=once" json:"once,omitempty"`
Tags []string `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
Ttl *float32 `protobuf:"fixed32,8,opt,name=ttl" json:"ttl,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (this *State) Reset() { *this = State{} }
func (this *State) String() string { return proto1.CompactTextString(this) }
func (*State) ProtoMessage() {}
func (this *State) GetTime() int64 {
if this != nil && this.Time != nil {
return *this.Time
}
return 0
}
func (this *State) GetState() string {
if this != nil && this.State != nil {
return *this.State
}
return ""
}
func (this *State) GetService() string {
if this != nil && this.Service != nil {
return *this.Service
}
return ""
}
func (this *State) GetHost() string {
if this != nil && this.Host != nil {
return *this.Host
}
return ""
}
func (this *State) GetDescription() string {
if this != nil && this.Description != nil {
return *this.Description
}
return ""
}
func (this *State) GetOnce() bool {
if this != nil && this.Once != nil {
return *this.Once
}
return false
}
func (this *State) GetTags() []string {
if this != nil {
return this.Tags
}
return nil
}
func (this *State) GetTtl() float32 {
if this != nil && this.Ttl != nil {
return *this.Ttl
}
return 0
}
type Event struct {
Time *int64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
State *string `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"`
Service *string `protobuf:"bytes,3,opt,name=service" json:"service,omitempty"`
Host *string `protobuf:"bytes,4,opt,name=host" json:"host,omitempty"`
Description *string `protobuf:"bytes,5,opt,name=description" json:"description,omitempty"`
Tags []string `protobuf:"bytes,7,rep,name=tags" json:"tags,omitempty"`
Ttl *float32 `protobuf:"fixed32,8,opt,name=ttl" json:"ttl,omitempty"`
Attributes []*Attribute `protobuf:"bytes,9,rep,name=attributes" json:"attributes,omitempty"`
MetricSint64 *int64 `protobuf:"zigzag64,13,opt,name=metric_sint64" json:"metric_sint64,omitempty"`
MetricD *float64 `protobuf:"fixed64,14,opt,name=metric_d" json:"metric_d,omitempty"`
MetricF *float32 `protobuf:"fixed32,15,opt,name=metric_f" json:"metric_f,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (this *Event) Reset() { *this = Event{} }
func (this *Event) String() string { return proto1.CompactTextString(this) }
func (*Event) ProtoMessage() {}
func (this *Event) GetTime() int64 {
if this != nil && this.Time != nil {
return *this.Time
}
return 0
}
func (this *Event) GetState() string {
if this != nil && this.State != nil {
return *this.State
}
return ""
}
func (this *Event) GetService() string {
if this != nil && this.Service != nil {
return *this.Service
}
return ""
}
func (this *Event) GetHost() string {
if this != nil && this.Host != nil {
return *this.Host
}
return ""
}
func (this *Event) GetDescription() string {
if this != nil && this.Description != nil {
return *this.Description
}
return ""
}
func (this *Event) GetTags() []string {
if this != nil {
return this.Tags
}
return nil
}
func (this *Event) GetTtl() float32 {
if this != nil && this.Ttl != nil {
return *this.Ttl
}
return 0
}
func (this *Event) GetAttributes() []*Attribute {
if this != nil {
return this.Attributes
}
return nil
}
func (this *Event) GetMetricSint64() int64 {
if this != nil && this.MetricSint64 != nil {
return *this.MetricSint64
}
return 0
}
func (this *Event) GetMetricD() float64 {
if this != nil && this.MetricD != nil {
return *this.MetricD
}
return 0
}
func (this *Event) GetMetricF() float32 {
if this != nil && this.MetricF != nil {
return *this.MetricF
}
return 0
}
type Query struct {
String_ *string `protobuf:"bytes,1,opt,name=string" json:"string,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (this *Query) Reset() { *this = Query{} }
func (this *Query) String() string { return proto1.CompactTextString(this) }
func (*Query) ProtoMessage() {}
func (this *Query) GetString_() string {
if this != nil && this.String_ != nil {
return *this.String_
}
return ""
}
type Msg struct {
Ok *bool `protobuf:"varint,2,opt,name=ok" json:"ok,omitempty"`
Error *string `protobuf:"bytes,3,opt,name=error" json:"error,omitempty"`
States []*State `protobuf:"bytes,4,rep,name=states" json:"states,omitempty"`
Query *Query `protobuf:"bytes,5,opt,name=query" json:"query,omitempty"`
Events []*Event `protobuf:"bytes,6,rep,name=events" json:"events,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (this *Msg) Reset() { *this = Msg{} }
func (this *Msg) String() string { return proto1.CompactTextString(this) }
func (*Msg) ProtoMessage() {}
func (this *Msg) GetOk() bool {
if this != nil && this.Ok != nil {
return *this.Ok
}
return false
}
func (this *Msg) GetError() string {
if this != nil && this.Error != nil {
return *this.Error
}
return ""
}
func (this *Msg) GetStates() []*State {
if this != nil {
return this.States
}
return nil
}
func (this *Msg) GetQuery() *Query {
if this != nil {
return this.Query
}
return nil
}
func (this *Msg) GetEvents() []*Event {
if this != nil {
return this.Events
}
return nil
}
type Attribute struct {
Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (this *Attribute) Reset() { *this = Attribute{} }
func (this *Attribute) String() string { return proto1.CompactTextString(this) }
func (*Attribute) ProtoMessage() {}
func (this *Attribute) GetKey() string {
if this != nil && this.Key != nil {
return *this.Key
}
return ""
}
func (this *Attribute) GetValue() string {
if this != nil && this.Value != nil {
return *this.Value
}
return ""
}
func init() {
}

View File

@ -0,0 +1,45 @@
option java_package = "com.aphyr.riemann";
option java_outer_classname = "Proto";
message State {
optional int64 time = 1;
optional string state = 2;
optional string service = 3;
optional string host = 4;
optional string description = 5;
optional bool once = 6;
repeated string tags = 7;
optional float ttl = 8;
}
message Event {
optional int64 time = 1;
optional string state = 2;
optional string service = 3;
optional string host = 4;
optional string description = 5;
repeated string tags = 7;
optional float ttl = 8;
repeated Attribute attributes = 9;
optional sint64 metric_sint64 = 13;
optional double metric_d = 14;
optional float metric_f = 15;
}
message Query {
optional string string = 1;
}
message Msg {
optional bool ok = 2;
optional string error = 3;
repeated State states = 4;
optional Query query = 5;
repeated Event events = 6;
}
message Attribute {
required string key = 1;
optional string value = 2;
}

View File

@ -0,0 +1,313 @@
// Go Riemann client
package raidman
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"os"
"reflect"
"sync"
"time"
"github.com/amir/raidman/proto"
pb "github.com/golang/protobuf/proto"
)
type network interface {
Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}
type tcp struct{}
type udp struct{}
// Client represents a connection to a Riemann server
type Client struct {
sync.Mutex
net network
connection net.Conn
timeout time.Duration
}
// An Event represents a single Riemann event
type Event struct {
Ttl float32
Time int64
Tags []string
Host string // Defaults to os.Hostname()
State string
Service string
Metric interface{} // Could be Int, Float32, Float64
Description string
Attributes map[string]string
}
// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk, with a timeout of timeout
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func DialWithTimeout(netwrk, addr string, timeout time.Duration) (c *Client, err error) {
c = new(Client)
var cnet network
switch netwrk {
case "tcp", "tcp4", "tcp6":
cnet = new(tcp)
case "udp", "udp4", "udp6":
cnet = new(udp)
default:
return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
}
c.net = cnet
c.timeout = timeout
c.connection, err = net.Dial(netwrk, addr)
if err != nil {
return nil, err
}
return c, nil
}
// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
return DialWithTimeout(netwrk, addr, 0)
}
func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
msg := &proto.Msg{}
data, err := pb.Marshal(message)
if err != nil {
return msg, err
}
b := new(bytes.Buffer)
if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
return msg, err
}
if _, err = conn.Write(b.Bytes()); err != nil {
return msg, err
}
if _, err = conn.Write(data); err != nil {
return msg, err
}
var header uint32
if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
return msg, err
}
response := make([]byte, header)
if err = readFully(conn, response); err != nil {
return msg, err
}
if err = pb.Unmarshal(response, msg); err != nil {
return msg, err
}
if msg.GetOk() != true {
return msg, errors.New(msg.GetError())
}
return msg, nil
}
func readFully(r io.Reader, p []byte) error {
for len(p) > 0 {
n, err := r.Read(p)
p = p[n:]
if err != nil {
return err
}
}
return nil
}
func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
data, err := pb.Marshal(message)
if err != nil {
return nil, err
}
if _, err = conn.Write(data); err != nil {
return nil, err
}
return nil, nil
}
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Map:
return v.IsNil()
case reflect.Slice:
zero := true
for i := 0; i < v.Len(); i++ {
zero = zero && isZero(v.Index(i))
}
return zero
}
zero := reflect.Zero(v.Type())
return v.Interface() == zero.Interface()
}
func eventToPbEvent(event *Event) (*proto.Event, error) {
var e proto.Event
if event.Host == "" {
event.Host, _ = os.Hostname()
}
t := reflect.ValueOf(&e).Elem()
s := reflect.ValueOf(event).Elem()
typeOfEvent := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
value := reflect.ValueOf(f.Interface())
if !isZero(f) {
name := typeOfEvent.Field(i).Name
switch name {
case "State", "Service", "Host", "Description":
tmp := reflect.ValueOf(pb.String(value.String()))
t.FieldByName(name).Set(tmp)
case "Ttl":
tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
t.FieldByName(name).Set(tmp)
case "Time":
tmp := reflect.ValueOf(pb.Int64(value.Int()))
t.FieldByName(name).Set(tmp)
case "Tags":
tmp := reflect.ValueOf(value.Interface().([]string))
t.FieldByName(name).Set(tmp)
case "Metric":
switch reflect.TypeOf(f.Interface()).Kind() {
case reflect.Int:
tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
t.FieldByName("MetricSint64").Set(tmp)
case reflect.Int64:
tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
t.FieldByName("MetricSint64").Set(tmp)
case reflect.Float32:
tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
t.FieldByName("MetricF").Set(tmp)
case reflect.Float64:
tmp := reflect.ValueOf(pb.Float64(value.Float()))
t.FieldByName("MetricD").Set(tmp)
default:
return nil, fmt.Errorf("Metric of invalid type (type %v)",
reflect.TypeOf(f.Interface()).Kind())
}
case "Attributes":
var attrs []*proto.Attribute
for k, v := range value.Interface().(map[string]string) {
// Copy k,v so we can take
// pointers to the new
// temporaries
k_, v_ := k, v
attrs = append(attrs, &proto.Attribute{
Key: &k_,
Value: &v_,
})
}
t.FieldByName(name).Set(reflect.ValueOf(attrs))
}
}
}
return &e, nil
}
func pbEventsToEvents(pbEvents []*proto.Event) []Event {
var events []Event
for _, event := range pbEvents {
e := Event{
State: event.GetState(),
Service: event.GetService(),
Host: event.GetHost(),
Description: event.GetDescription(),
Ttl: event.GetTtl(),
Time: event.GetTime(),
Tags: event.GetTags(),
}
if event.MetricF != nil {
e.Metric = event.GetMetricF()
} else if event.MetricD != nil {
e.Metric = event.GetMetricD()
} else {
e.Metric = event.GetMetricSint64()
}
if event.Attributes != nil {
e.Attributes = make(map[string]string, len(event.GetAttributes()))
for _, attr := range event.GetAttributes() {
e.Attributes[attr.GetKey()] = attr.GetValue()
}
}
events = append(events, e)
}
return events
}
// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
return c.SendMulti([]*Event{event})
}
// SendMulti sends multiple events to Riemann
func (c *Client) SendMulti(events []*Event) error {
message := &proto.Msg{}
for _, event := range events {
e, err := eventToPbEvent(event)
if err != nil {
return err
}
message.Events = append(message.Events, e)
}
c.Lock()
defer c.Unlock()
if c.timeout > 0 {
err := c.connection.SetDeadline(time.Now().Add(c.timeout))
if err != nil {
return err
}
}
_, err := c.net.Send(message, c.connection)
if err != nil {
return err
}
return nil
}
// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
switch c.net.(type) {
case *udp:
return nil, errors.New("Querying over UDP is not supported")
}
query := &proto.Query{}
query.String_ = pb.String(q)
message := &proto.Msg{}
message.Query = query
c.Lock()
defer c.Unlock()
response, err := c.net.Send(message, c.connection)
if err != nil {
return nil, err
}
return pbEventsToEvents(response.GetEvents()), nil
}
// Close closes the connection to Riemann
func (c *Client) Close() {
c.Lock()
c.connection.Close()
c.Unlock()
}

View File

@ -0,0 +1,268 @@
package raidman
import (
"reflect"
"testing"
)
func TestTCP(t *testing.T) {
c, err := Dial("tcp", "localhost:5555")
if err != nil {
t.Fatal(err.Error())
}
var event = &Event{
State: "success",
Host: "raidman",
Service: "tcp",
Metric: 42,
Ttl: 1,
Tags: []string{"tcp", "test", "raidman"},
Attributes: map[string]string{"type": "test"},
}
err = c.Send(event)
if err != nil {
t.Error(err.Error())
}
events, err := c.Query("tagged \"test\"")
if err != nil {
t.Error(err.Error())
}
if len(events) < 1 {
t.Error("Submitted event not found")
}
testAttributeExists := false
for _, event := range events {
if val, ok := event.Attributes["type"]; ok && val == "test" {
testAttributeExists = true
}
}
if !testAttributeExists {
t.Error("Attribute \"type\" is missing")
}
c.Close()
}
func TestMultiTCP(t *testing.T) {
c, err := Dial("tcp", "localhost:5555")
if err != nil {
t.Fatal(err.Error())
}
err = c.SendMulti([]*Event{
&Event{
State: "success",
Host: "raidman",
Service: "tcp-multi-1",
Metric: 42,
Ttl: 1,
Tags: []string{"tcp", "test", "raidman", "multi"},
Attributes: map[string]string{"type": "test"},
},
&Event{
State: "success",
Host: "raidman",
Service: "tcp-multi-2",
Metric: 42,
Ttl: 1,
Tags: []string{"tcp", "test", "raidman", "multi"},
Attributes: map[string]string{"type": "test"},
},
})
if err != nil {
t.Error(err.Error())
}
events, err := c.Query("tagged \"test\" and tagged \"multi\"")
if err != nil {
t.Error(err.Error())
}
if len(events) != 2 {
t.Error("Submitted event not found")
}
c.Close()
}
func TestMetricIsInt64(t *testing.T) {
c, err := Dial("tcp", "localhost:5555")
if err != nil {
t.Fatal(err.Error())
}
var int64metric int64 = 9223372036854775807
var event = &Event{
State: "success",
Host: "raidman",
Service: "tcp",
Metric: int64metric,
Ttl: 1,
Tags: []string{"tcp", "test", "raidman"},
Attributes: map[string]string{"type": "test"},
}
err = c.Send(event)
if err != nil {
t.Error(err.Error())
}
}
func TestUDP(t *testing.T) {
c, err := Dial("udp", "localhost:5555")
if err != nil {
t.Fatal(err.Error())
}
var event = &Event{
State: "warning",
Host: "raidman",
Service: "udp",
Metric: 3.4,
Ttl: 10.7,
}
err = c.Send(event)
if err != nil {
t.Error(err.Error())
}
c.Close()
}
func TestTCPWithoutHost(t *testing.T) {
c, err := Dial("tcp", "localhost:5555")
if err != nil {
t.Fatal(err.Error())
}
defer c.Close()
var event = &Event{
State: "success",
Service: "tcp-host-not-set",
Ttl: 5,
}
err = c.Send(event)
if err != nil {
t.Error(err.Error())
}
events, err := c.Query("service = \"tcp-host-not-set\"")
if err != nil {
t.Error(err.Error())
}
if len(events) < 1 {
t.Error("Submitted event not found")
}
for _, e := range events {
if e.Host == "" {
t.Error("Default host name is not set")
}
}
}
func TestIsZero(t *testing.T) {
event := &Event{
Time: 1,
}
elem := reflect.ValueOf(event).Elem()
eventType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
field := elem.Field(i)
name := eventType.Field(i).Name
if name == "Time" {
if isZero(field) {
t.Error("Time should not be zero")
}
} else {
if !isZero(field) {
t.Errorf("%s should be zero", name)
}
}
}
}
func BenchmarkTCP(b *testing.B) {
c, err := Dial("tcp", "localhost:5555")
var event = &Event{
State: "good",
Host: "raidman",
Service: "benchmark",
}
if err == nil {
for i := 0; i < b.N; i++ {
c.Send(event)
}
}
c.Close()
}
func BenchmarkUDP(b *testing.B) {
c, err := Dial("udp", "localhost:5555")
var event = &Event{
State: "good",
Host: "raidman",
Service: "benchmark",
}
if err == nil {
for i := 0; i < b.N; i++ {
c.Send(event)
}
}
c.Close()
}
func BenchmarkConcurrentTCP(b *testing.B) {
c, err := Dial("tcp", "localhost:5555")
var event = &Event{
Host: "raidman",
Service: "tcp_concurrent",
Tags: []string{"concurrent", "tcp", "benchmark"},
}
ch := make(chan int, b.N)
for i := 0; i < b.N; i++ {
go func(metric int) {
event.Metric = metric
err = c.Send(event)
ch <- i
}(i)
}
<-ch
c.Close()
}
func BenchmarkConcurrentUDP(b *testing.B) {
c, err := Dial("udp", "localhost:5555")
var event = &Event{
Host: "raidman",
Service: "udp_concurrent",
Tags: []string{"concurrent", "udp", "benchmark"},
}
ch := make(chan int, b.N)
for i := 0; i < b.N; i++ {
go func(metric int) {
event.Metric = metric
err = c.Send(event)
ch <- i
}(i)
}
<-ch
c.Close()
}

View File

@ -1,4 +0,0 @@
*~
#*
_obj
*.tmp

View File

@ -1,27 +0,0 @@
gopsutil is distributed under BSD license reproduced below.
Copyright (c) 2014, WAKAYAMA Shirou
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the gopsutil authors nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,270 +0,0 @@
gopsutil: psutil for golang
==============================
.. image:: https://drone.io/github.com/shirou/gopsutil/status.png
:target: https://drone.io/github.com/shirou/gopsutil
.. image:: https://coveralls.io/repos/shirou/gopsutil/badge.png?branch=master
:target: https://coveralls.io/r/shirou/gopsutil?branch=master
This is a port of psutil (http://pythonhosted.org/psutil/). The challenge is porting all
psutil functions on some architectures...
.. highlights:: Package Structure Changed!
Package (a.k.a. directory) structure has been changed!! see `issue 24 <https://github.com/shirou/gopsutil/issues/24>`_
.. highlights:: golang 1.4 will become REQUIRED!
Since syscall package becomes frozen, we should use golang/x/sys of golang 1.4 as soon as possible.
Available Architectures
------------------------------------
- FreeBSD i386/amd64
- Linux i386/amd64/arm(raspberry pi)
- Windows/amd64
- Darwin/amd64
All works are implemented without cgo by porting c struct to golang struct.
Usage
---------
.. code:: go
import (
"fmt"
"github.com/shirou/gopsutil/mem"
)
func main() {
v, _ := mem.VirtualMemory()
// almost every return value is a struct
fmt.Printf("Total: %v, Free:%v, UsedPercent:%f%%\n", v.Total, v.Free, v.UsedPercent)
// convert to JSON. String() is also implemented
fmt.Println(v)
}
The output is below.
::
Total: 3179569152, Free:284233728, UsedPercent:84.508194%
{"total":3179569152,"available":492572672,"used":2895335424,"usedPercent":84.50819439828305, (snip)}
You can set an alternative location to /proc by setting the HOST_PROC environment variable.
Documentation
------------------------
see http://godoc.org/github.com/shirou/gopsutil
More Info
--------------------
Several methods have been added which are not present in psutil, but will provide useful information.
- host/HostInfo() (linux)
- Hostname
- Uptime
- Procs
- OS (ex: "linux")
- Platform (ex: "ubuntu", "arch")
- PlatformFamily (ex: "debian")
- PlatformVersion (ex: "Ubuntu 13.10")
- VirtualizationSystem (ex: "LXC")
- VirtualizationRole (ex: "guest"/"host")
- cpu/CPUInfo() (linux, freebsd)
- CPU (ex: 0, 1, ...)
- VendorID (ex: "GenuineIntel")
- Family
- Model
- Stepping
- PhysicalID
- CoreID
- Cores (ex: 2)
- ModelName (ex: "Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz")
- Mhz
- CacheSize
- Flags (ex: "fpu vme de pse tsc msr pae mce cx8 ...")
- load/LoadAvg() (linux, freebsd)
- Load1
- Load5
- Load15
- docker/GetDockerIDList() (linux only)
- container id list ([]string)
- docker/CgroupCPU() (linux only)
- user
- system
- docker/CgroupMem() (linux only)
- various status
Some codes are ported from Ohai. many thanks.
Current Status
------------------
- x: work
- b: almost work but something broken
================= ====== ======= ====== =======
name Linux FreeBSD MacOSX Windows
cpu_times x x x x
cpu_count x x x x
cpu_percent x x x x
cpu_times_percent x x x x
virtual_memory x x x x
swap_memory x x x
disk_partitions x x x x
disk_io_counters x x
disk_usage x x x x
net_io_counters x x b x
boot_time x x x x
users x x x x
pids x x x x
pid_exists x x x x
net_connections x x
net_if_addrs
net_if_stats
================= ====== ======= ====== =======
Process class
^^^^^^^^^^^^^^^
================ ===== ======= ====== =======
name Linux FreeBSD MacOSX Windows
pid x x x x
ppid x x x x
name x x x x
cmdline x x x
create_time x
status x x x
cwd x
exe x x x
uids x x x
gids x x x
terminal x x x
io_counters x
nice x x x
num_fds x
num_ctx_switches x
num_threads x x x x
cpu_times x
memory_info x x x
memory_info_ex x
memory_maps x
open_files x
send_signal x x x
suspend x x x
resume x x x
terminate x x x
kill x x x
username x
ionice
rlimit
num_handlres
threads
cpu_percent x x
cpu_affinity
memory_percent
parent x x
children
connections x x
is_running
================ ===== ======= ====== =======
Original Metrics
^^^^^^^^^^^^^^^^^^^
================== ===== ======= ====== =======
item Linux FreeBSD MacOSX Windows
**HostInfo**
hostname x x x x
uptime x x x
proces x x
os x x x x
platform x x x
platformfamiliy x x x
virtualization x
**CPU**
VendorID x x x x
Family x x x x
Model x x x x
Stepping x x x x
PhysicalID x
CoreID x
Cores x x
ModelName x x x x
**LoadAvg**
Load1 x x x
Load5 x x x
Load15 x x x
**GetDockerID**
container id x no no no
**CgroupsCPU**
user x no no no
system x no no no
**CgroupsMem**
various x no no no
================== ===== ======= ====== =======
- future work
- process_iter
- wait_procs
- Process class
- as_dict
- wait
License
------------
New BSD License (same as psutil)
Related Works
-----------------------
I have been influenced by the following great works:
- psutil: http://pythonhosted.org/psutil/
- dstat: https://github.com/dagwieers/dstat
- gosigar: https://github.com/cloudfoundry/gosigar/
- goprocinfo: https://github.com/c9s/goprocinfo
- go-ps: https://github.com/mitchellh/go-ps
- ohai: https://github.com/opscode/ohai/
- bosun: https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector/collectors
- mackerel: https://github.com/mackerelio/mackerel-agent/tree/master/metrics
How to Contribute
---------------------------
1. Fork it
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create new Pull Request
My English is terrible, so documentation or correcting comments are also
welcome.

View File

@ -1,26 +0,0 @@
#/bin/sh
# see http://www.songmu.jp/riji/entry/2015-01-15-goveralls-multi-package.html
set -e
# cleanup
cleanup() {
if [ $tmpprof != "" ] && [ -f $tmpprof ]; then
rm -f $tmpprof
fi
exit
}
trap cleanup INT QUIT TERM EXIT
# メインの処理
prof=${1:-".profile.cov"}
echo "mode: count" > $prof
gopath1=$(echo $GOPATH | cut -d: -f1)
for pkg in $(go list ./...); do
tmpprof=$gopath1/src/$pkg/profile.tmp
go test -covermode=count -coverprofile=$tmpprof $pkg
if [ -f $tmpprof ]; then
cat $tmpprof | tail -n +2 >> $prof
rm $tmpprof
fi
done

View File

@ -1 +0,0 @@
package gopsutil

View File

@ -1,37 +0,0 @@
DIRS="cpu disk docker host load mem net process"
GOOS=`uname | tr '[:upper:]' '[:lower:]'`
ARCH=`uname -m`
case $ARCH in
amd64)
GOARCH="amd64"
;;
x86_64)
GOARCH="amd64"
;;
i386)
GOARCH="386"
;;
i686)
GOARCH="386"
;;
arm)
GOARCH="arm"
;;
*)
echo "unknown arch: $ARCH"
exit 1
esac
for DIR in $DIRS
do
if [ -e ${DIR}/types_${GOOS}.go ]; then
echo "// +build $GOOS" > ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
echo "// +build $GOARCH" >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
go tool cgo -godefs ${DIR}/types_${GOOS}.go >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
fi
done

View File

@ -1,36 +0,0 @@
Windows memo
=====================
Size
----------
DWORD
32-bit unsigned integer
DWORDLONG
64-bit unsigned integer
DWORD_PTR
unsigned long type for pointer precision
DWORD32
32-bit unsigned integer
DWORD64
64-bit unsigned integer
HALF_PTR
_WIN64 = int, else short
INT
32-bit signed integer
INT_PTR
_WIN64 = __int64 else int
LONG
32-bit signed integer
LONGLONG
64-bit signed integer
LONG_PTR
_WIN64 = __int64 else long
SHORT
16-bit integer
SIZE_T
maximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T;
SSIZE_T
signed version of SIZE_T. typedef LONG_PTR SSIZE_T;
WORD
16-bit unsigned integer

View File

@ -57,6 +57,7 @@ endif
docker run --name aerospike -p "3000:3000" -d aerospike
docker run --name nsq -p "4150:4150" -d nsqio/nsq /nsqd
docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt
docker run --name riemann -p "5555:5555" -d blalor/riemann
# Run docker containers necessary for CircleCI unit tests
docker-run-circle:
@ -69,11 +70,12 @@ docker-run-circle:
docker run --name aerospike -p "3000:3000" -d aerospike
docker run --name nsq -p "4150:4150" -d nsqio/nsq /nsqd
docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt
docker run --name riemann -p "5555:5555" -d blalor/riemann
# Kill all docker containers, ignore errors
docker-kill:
-docker kill nsq aerospike redis opentsdb rabbitmq postgres memcached mysql kafka mqtt
-docker rm nsq aerospike redis opentsdb rabbitmq postgres memcached mysql kafka mqtt
-docker kill nsq aerospike redis opentsdb rabbitmq postgres memcached mysql kafka mqtt riemann
-docker rm nsq aerospike redis opentsdb rabbitmq postgres memcached mysql kafka mqtt riemann
# Run full unit tests using docker containers (includes setup and teardown)
test: docker-kill prepare docker-run