diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 04f4706ad..c49bdcd5c 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -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" }, diff --git a/Godeps/_workspace/src/github.com/amir/raidman/README.md b/Godeps/_workspace/src/github.com/amir/raidman/README.md new file mode 100644 index 000000000..5dbe8684e --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/README.md @@ -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() +} + +``` diff --git a/Godeps/_workspace/src/github.com/amir/raidman/UNLICENSE b/Godeps/_workspace/src/github.com/amir/raidman/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/UNLICENSE @@ -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 diff --git a/Godeps/_workspace/src/github.com/amir/raidman/proto/Makefile b/Godeps/_workspace/src/github.com/amir/raidman/proto/Makefile new file mode 100644 index 000000000..5349cc839 --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/proto/Makefile @@ -0,0 +1,6 @@ +proto.pb.go: proto.proto + mkdir -p _pb + protoc --go_out=_pb $< + cat _pb/$@\ + |gofmt >$@ + rm -rf _pb diff --git a/Godeps/_workspace/src/github.com/amir/raidman/proto/proto.pb.go b/Godeps/_workspace/src/github.com/amir/raidman/proto/proto.pb.go new file mode 100644 index 000000000..42eea684d --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/proto/proto.pb.go @@ -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() { +} diff --git a/Godeps/_workspace/src/github.com/amir/raidman/proto/proto.proto b/Godeps/_workspace/src/github.com/amir/raidman/proto/proto.proto new file mode 100644 index 000000000..3e946a3a0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/proto/proto.proto @@ -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; +} diff --git a/Godeps/_workspace/src/github.com/amir/raidman/raidman.go b/Godeps/_workspace/src/github.com/amir/raidman/raidman.go new file mode 100644 index 000000000..87c82777c --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/raidman.go @@ -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() +} diff --git a/Godeps/_workspace/src/github.com/amir/raidman/raidman_test.go b/Godeps/_workspace/src/github.com/amir/raidman/raidman_test.go new file mode 100644 index 000000000..8a824ee3c --- /dev/null +++ b/Godeps/_workspace/src/github.com/amir/raidman/raidman_test.go @@ -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() +} diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/.gitignore b/Godeps/_workspace/src/github.com/shirou/gopsutil/.gitignore deleted file mode 100644 index 194eab896..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*~ -#* -_obj -*.tmp \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/LICENSE b/Godeps/_workspace/src/github.com/shirou/gopsutil/LICENSE deleted file mode 100644 index 602b2c098..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/LICENSE +++ /dev/null @@ -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. diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/README.rst b/Godeps/_workspace/src/github.com/shirou/gopsutil/README.rst deleted file mode 100644 index a858ff09e..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/README.rst +++ /dev/null @@ -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 `_ - -.. 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. diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/coverall.sh b/Godeps/_workspace/src/github.com/shirou/gopsutil/coverall.sh deleted file mode 100644 index 35aa298ba..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/coverall.sh +++ /dev/null @@ -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 diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/doc.go b/Godeps/_workspace/src/github.com/shirou/gopsutil/doc.go deleted file mode 100644 index 6a65fe268..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/doc.go +++ /dev/null @@ -1 +0,0 @@ -package gopsutil diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/mktypes.sh b/Godeps/_workspace/src/github.com/shirou/gopsutil/mktypes.sh deleted file mode 100644 index 7bf2e2412..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/mktypes.sh +++ /dev/null @@ -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 - - diff --git a/Godeps/_workspace/src/github.com/shirou/gopsutil/windows_memo.rst b/Godeps/_workspace/src/github.com/shirou/gopsutil/windows_memo.rst deleted file mode 100644 index 38abed819..000000000 --- a/Godeps/_workspace/src/github.com/shirou/gopsutil/windows_memo.rst +++ /dev/null @@ -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 \ No newline at end of file diff --git a/Makefile b/Makefile index 49e571ef8..58b5b1560 100644 --- a/Makefile +++ b/Makefile @@ -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