Commit 525179eb by Torkel Ödegaard

Added on wire event format

parent dace35d3
package events package events
import (
"reflect"
"time"
)
// Events can be passed to external systems via for example AMPQ // Events can be passed to external systems via for example AMPQ
// Treat these events as basically DTOs so changes has to be backward compatible // Treat these events as basically DTOs so changes has to be backward compatible
type Priority string
const (
PRIO_DEBUG Priority = "DEBUG"
PRIO_INFO Priority = "INFO"
PRIO_ERROR Priority = "ERROR"
)
type Event struct {
Timestamp time.Time `json:"timestamp"`
}
type OnTheWireEvent struct {
EventType string `json:"event_type"`
Priority Priority `json:"priority"`
Timestamp time.Time `json:"timestamp"`
Payload interface{} `json:"payload"`
}
type EventBase interface {
ToOnWriteEvent() *OnTheWireEvent
}
func ToOnWriteEvent(event interface{}) (*OnTheWireEvent, error) {
eventType := reflect.TypeOf(event)
wireEvent := OnTheWireEvent{
Priority: PRIO_INFO,
EventType: eventType.Name(),
Payload: event,
}
baseField := reflect.ValueOf(event).FieldByName("Timestamp")
if baseField.IsValid() {
wireEvent.Timestamp = baseField.Interface().(time.Time)
} else {
wireEvent.Timestamp = time.Now()
}
return &wireEvent, nil
}
type AccountCreated struct { type AccountCreated struct {
Name string `json:"name"` Timestamp time.Time `json:"timestamp"`
Id int64 `json:"id"`
Name string `json:"name"`
}
type AccountUpdated struct {
Timestamp time.Time `json:"timestamp"`
Id int64 `json:"id"`
Name string `json:"name"`
} }
package events package events
import ( import (
"encoding/json"
"testing" "testing"
"time"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
) )
type TestEvent struct {
Timestamp time.Time
}
func TestEventCreation(t *testing.T) { func TestEventCreation(t *testing.T) {
Convey("When generating slug", t, func() { Convey("Event to wire event", t, func() {
dashboard := NewDashboard("Grafana Play Home") e := TestEvent{
dashboard.UpdateSlug() Timestamp: time.Unix(1231421123, 223),
}
wire, _ := ToOnWriteEvent(e)
So(e.Timestamp.Unix(), ShouldEqual, wire.Timestamp.Unix())
So(wire.EventType, ShouldEqual, "TestEvent")
So(dashboard.Slug, ShouldEqual, "grafana-play-home") json, _ := json.Marshal(wire)
So(string(json), ShouldEqual, `{"event_type":"TestEvent","priority":"INFO","timestamp":"2009-01-08T14:25:23.000000223+01:00","payload":{"Timestamp":"2009-01-08T14:25:23.000000223+01:00"}}`)
}) })
} }
...@@ -4,11 +4,11 @@ import ( ...@@ -4,11 +4,11 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"reflect"
"time" "time"
"github.com/streadway/amqp" "github.com/streadway/amqp"
"github.com/torkelo/grafana-pro/pkg/bus" "github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/events"
"github.com/torkelo/grafana-pro/pkg/setting" "github.com/torkelo/grafana-pro/pkg/setting"
) )
...@@ -131,14 +131,17 @@ func publish(routingKey string, msgString []byte) { ...@@ -131,14 +131,17 @@ func publish(routingKey string, msgString []byte) {
} }
func eventListener(event interface{}) error { func eventListener(event interface{}) error {
msgString, err := json.Marshal(event) wireEvent, err := events.ToOnWriteEvent(event)
if err != nil { if err != nil {
return err return err
} }
eventType := reflect.TypeOf(event) msgString, err := json.Marshal(wireEvent)
if err != nil {
return err
}
routingKey := fmt.Sprintf("%s.%s", "INFO", eventType.Name()) routingKey := fmt.Sprintf("%s.%s", wireEvent.Priority, wireEvent.EventType)
// this is run in a greenthread and we expect that publish will keep // this is run in a greenthread and we expect that publish will keep
// retrying until the message gets sent. // retrying until the message gets sent.
go publish(routingKey, msgString) go publish(routingKey, msgString)
......
...@@ -3,8 +3,6 @@ package sqlstore ...@@ -3,8 +3,6 @@ package sqlstore
import ( import (
"time" "time"
"github.com/go-xorm/xorm"
"github.com/torkelo/grafana-pro/pkg/bus" "github.com/torkelo/grafana-pro/pkg/bus"
"github.com/torkelo/grafana-pro/pkg/events" "github.com/torkelo/grafana-pro/pkg/events"
m "github.com/torkelo/grafana-pro/pkg/models" m "github.com/torkelo/grafana-pro/pkg/models"
...@@ -73,15 +71,9 @@ func CreateAccount(cmd *m.CreateAccountCommand) error { ...@@ -73,15 +71,9 @@ func CreateAccount(cmd *m.CreateAccountCommand) error {
cmd.Result = account cmd.Result = account
sess.publishAfterCommit(&events.AccountCreated{ sess.publishAfterCommit(&events.AccountCreated{
Name: account.Name,
})
// silently ignore failures to publish events.
_ = bus.Publish(&m.Notification{
EventType: "account.create",
Timestamp: account.Created, Timestamp: account.Created,
Priority: m.PRIO_INFO, Id: account.Id,
Payload: account, Name: account.Name,
}) })
return err return err
...@@ -89,24 +81,23 @@ func CreateAccount(cmd *m.CreateAccountCommand) error { ...@@ -89,24 +81,23 @@ func CreateAccount(cmd *m.CreateAccountCommand) error {
} }
func UpdateAccount(cmd *m.UpdateAccountCommand) error { func UpdateAccount(cmd *m.UpdateAccountCommand) error {
return inTransaction(func(sess *xorm.Session) error { return inTransaction2(func(sess *session) error {
account := m.Account{ account := m.Account{
Name: cmd.Name, Name: cmd.Name,
Updated: time.Now(), Updated: time.Now(),
} }
_, err := sess.Id(cmd.AccountId).Update(&account) if _, err := sess.Id(cmd.AccountId).Update(&account); err != nil {
if err == nil { return err
// silently ignore failures to publish events.
account.Id = cmd.AccountId
_ = bus.Publish(&m.Notification{
EventType: "account.update",
Timestamp: account.Updated,
Priority: m.PRIO_INFO,
Payload: account,
})
} }
return err
sess.publishAfterCommit(events.AccountUpdated{
Timestamp: account.Updated,
Id: account.Id,
Name: account.Name,
})
return nil
}) })
} }
...@@ -219,17 +219,6 @@ func NewConfigContext() { ...@@ -219,17 +219,6 @@ func NewConfigContext() {
LogRootPath = Cfg.Section("log").Key("root_path").MustString(path.Join(WorkDir, "/data/log")) LogRootPath = Cfg.Section("log").Key("root_path").MustString(path.Join(WorkDir, "/data/log"))
// Notifications
NotificationsEnabled = Cfg.Section("notifications").Key("enabled").MustBool(false)
RabbitmqUrl = Cfg.Section("notifications").Key("rabbitmq_url").MustString("amqp://localhost/")
// validate rabbitmqUrl.
_, err = url.Parse(RabbitmqUrl)
if err != nil {
log.Fatal(4, "Invalid rabbitmq_url(%s): %s", RabbitmqUrl, err)
}
NotificationsExchange = Cfg.Section("notifications").Key("notifications_exchange").MustString("notifications")
readSessionConfig() readSessionConfig()
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment