diff --git a/go.mod b/go.mod index 8cd17089f..9031fd3fb 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,19 @@ module github.com/ncarlier/reader require ( github.com/Masterminds/squirrel v1.1.0 + github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05 github.com/brianvoe/gofakeit v3.17.0+incompatible github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448 // indirect github.com/getsentry/raven-go v0.2.0 + github.com/go-sql-driver/mysql v1.4.1 // indirect github.com/graphql-go/graphql v0.7.7 github.com/graphql-go/handler v0.2.3 github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.0.0 + github.com/mattn/go-sqlite3 v1.10.0 // indirect github.com/pkg/errors v0.8.1 // indirect + github.com/prometheus/client_golang v0.9.2 github.com/rs/zerolog v1.12.0 + github.com/stretchr/testify v1.3.0 // indirect + google.golang.org/appengine v1.5.0 // indirect ) diff --git a/go.sum b/go.sum index 2029559ca..2f795bcde 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,22 @@ github.com/Masterminds/squirrel v1.1.0 h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs= github.com/Masterminds/squirrel v1.1.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05 h1:Shem5lRG4gJyrrg9YMIl7dOQazyWCq0Daz4LjompZ28= +github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/brianvoe/gofakeit v3.17.0+incompatible h1:C1+30+c0GtjgGDtRC+iePZeP1WMiwsWCELNJhmc7aIc= github.com/brianvoe/gofakeit v3.17.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc= github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448 h1:8tNk6SPXzLDnATTrWoI5Bgw9s/x4uf0kmBpk21NZgI4= github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/graphql-go/graphql v0.7.7 h1:nwEsJGwPq9N6cElOO+NYyoWuELAQZ4GuJks0Rlco5og= github.com/graphql-go/graphql v0.7.7/go.mod h1:k6yrAYQaSP59DC5UVxbgxESlmVyojThKdORUqGDGmrI= github.com/graphql-go/handler v0.2.3 h1:CANh8WPnl5M9uA25c2GBhPqJhE53Fg0Iue/fRNla71E= @@ -22,9 +32,32 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rs/zerolog v1.12.0 h1:aqZ1XRadoS8IBknR5IDFvGzbHly1X9ApIqOroooQF/c= github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go new file mode 100644 index 000000000..6026a7485 --- /dev/null +++ b/pkg/api/metrics.go @@ -0,0 +1,12 @@ +package api + +import ( + "net/http" + + "github.com/ncarlier/reader/pkg/config" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func metrics(conf *config.Config) http.Handler { + return promhttp.Handler() +} diff --git a/pkg/api/routes.go b/pkg/api/routes.go index 9304d5759..911cea484 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -57,4 +57,10 @@ var routes = Routes{ true, varz, }, + Route{ + []string{"GET"}, + "/metrics", + true, + metrics, + }, } diff --git a/pkg/event/article-metrics.go b/pkg/event/article-metrics.go new file mode 100644 index 000000000..0725a9558 --- /dev/null +++ b/pkg/event/article-metrics.go @@ -0,0 +1,14 @@ +package event + +import ( + "github.com/ncarlier/reader/pkg/metric" + "github.com/ncarlier/reader/pkg/model" +) + +func init() { + bus.Subscribe(CreateArticle, func(payload ...interface{}) { + if article, ok := payload[0].(model.Article); ok { + metric.IncNewArticlesCounter(article) + } + }) +} diff --git a/pkg/event/main.go b/pkg/event/main.go new file mode 100644 index 000000000..d24508f71 --- /dev/null +++ b/pkg/event/main.go @@ -0,0 +1,23 @@ +package event + +import ( + "github.com/asaskevich/EventBus" +) + +var bus = EventBus.New() + +const ( + // CreateUser is the create event on an user + CreateUser = "user:create" + // UpdateUser is the update event on an user + UpdateUser = "user:update" + // DeleteUser is the delete event on an user + DeleteUser = "user:delete" + // CreateArticle is the create event on an article + CreateArticle = "article:create" +) + +// Emit trigger an event to events listenners +func Emit(event string, payload ...interface{}) { + bus.Publish(event, payload...) +} diff --git a/pkg/metric/articles.go b/pkg/metric/articles.go new file mode 100644 index 000000000..6fe08f776 --- /dev/null +++ b/pkg/metric/articles.go @@ -0,0 +1,21 @@ +package metric + +import ( + "fmt" + + "github.com/ncarlier/reader/pkg/model" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + createdArticles = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "articles_created_total", + Help: "The total number of created articles by user", + }, []string{"uid"}) +) + +// IncNewArticlesCounter increments the counter of new articles +func IncNewArticlesCounter(article model.Article) { + createdArticles.With(prometheus.Labels{"uid": fmt.Sprint(article.UserID)}).Inc() +} diff --git a/pkg/metric/runtime.go b/pkg/metric/runtime.go new file mode 100644 index 000000000..eb805c98f --- /dev/null +++ b/pkg/metric/runtime.go @@ -0,0 +1,23 @@ +package metric + +import ( + "expvar" + "runtime" + "time" +) + +var startTime = time.Now().UTC() + +func goroutines() interface{} { + return runtime.NumGoroutine() +} + +func uptime() interface{} { + uptime := time.Since(startTime) + return int64(uptime) +} + +func init() { + expvar.Publish("goroutines", expvar.Func(goroutines)) + expvar.Publish("uptime", expvar.Func(uptime)) +} diff --git a/pkg/service/articles.go b/pkg/service/articles.go index 03b58cb31..4651a1e11 100644 --- a/pkg/service/articles.go +++ b/pkg/service/articles.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" + "github.com/ncarlier/reader/pkg/event" + "github.com/ncarlier/reader/pkg/model" ) @@ -34,6 +36,7 @@ func (reg *Registry) CreateArticles(ctx context.Context, data []model.ArticleFor reg.logger.Info().Uint( "uid", uid, ).Str("title", article.Title).Uint("id", *article.ID).Msg("article created") + event.Emit(event.CreateArticle, *article) } } var err error diff --git a/pkg/service/users.go b/pkg/service/users.go index 8a8f02c12..0ebef0dbe 100644 --- a/pkg/service/users.go +++ b/pkg/service/users.go @@ -7,6 +7,7 @@ import ( "time" "github.com/ncarlier/reader/pkg/constant" + "github.com/ncarlier/reader/pkg/event" "github.com/ncarlier/reader/pkg/model" "github.com/ncarlier/reader/pkg/tooling" ) @@ -67,6 +68,7 @@ func (reg *Registry) GetOrRegisterUser(ctx context.Context, username string) (*m reg.logger.Debug().Uint( "uid", *user.ID, ).Str("username", username).Msg("user registered") + event.Emit(event.CreateUser, *user) return user, nil }