add prometheus endpoint (#236)

generate metrics for Users, Appconfig and Session services
This commit is contained in:
Victor Vrantchan 2016-09-28 07:35:15 -04:00 committed by GitHub
parent a97e5d7874
commit 24b9baec1f
11 changed files with 380 additions and 23 deletions

View file

@ -10,12 +10,14 @@ import (
"github.com/WatchBeam/clock"
kitlog "github.com/go-kit/kit/log"
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
"github.com/kolide/kolide-ose/server/config"
"github.com/kolide/kolide-ose/server/datastore"
"github.com/kolide/kolide-ose/server/kolide"
"github.com/kolide/kolide-ose/server/mail"
"github.com/kolide/kolide-ose/server/service"
"github.com/kolide/kolide-ose/server/version"
"github.com/prometheus/client_golang/prometheus"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)
@ -128,14 +130,30 @@ the way that the kolide server works.
}
}
fieldKeys := []string{"method", "error"}
requestCount := kitprometheus.NewCounterFrom(prometheus.CounterOpts{
Namespace: "api",
Subsystem: "service",
Name: "request_count",
Help: "Number of requests received.",
}, fieldKeys)
requestLatency := kitprometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: "api",
Subsystem: "service",
Name: "request_latency_microseconds",
Help: "Total duration of requests in microseconds.",
}, fieldKeys)
svcLogger := kitlog.NewContext(logger).With("component", "service")
svc = service.NewLoggingService(svc, svcLogger)
svc = service.NewMetricsService(svc, requestCount, requestLatency)
httpLogger := kitlog.NewContext(logger).With("component", "http")
apiHandler := service.MakeHandler(ctx, svc, config.Auth.JwtKey, httpLogger)
http.Handle("/api/", accessControl(apiHandler))
http.Handle("/version", version.Handler())
http.Handle("/metrics", prometheus.Handler())
http.Handle("/assets/", service.ServeStaticAssets("/assets/"))
http.Handle("/", service.ServeFrontend())

31
glide.lock generated
View file

@ -1,5 +1,5 @@
hash: 3bf651074168b7611aabf854ebba43d0a41dd3cb3fbd0892268f9163e4240f9f
updated: 2016-09-20T11:30:44.994118865-07:00
hash: 0ed5871e7b062bd45449c789a58a5b8d2df91c275af984b344b109b232ca1bb3
updated: 2016-09-24T21:21:01.057881898-04:00
imports:
- name: github.com/alecthomas/template
version: a0175ee3bccc567396460bf5acd36800cb10c49c
@ -7,6 +7,10 @@ imports:
- parse
- name: github.com/alecthomas/units
version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a
- name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
subpackages:
- quantile
- name: github.com/davecgh/go-spew
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
subpackages:
@ -35,6 +39,9 @@ imports:
subpackages:
- endpoint
- log
- metrics
- metrics/internal/lv
- metrics/prometheus
- transport/http
- name: github.com/go-logfmt/logfmt
version: d4327190ff838312623b09bfeb50d7c93c8d9c1d
@ -84,6 +91,10 @@ imports:
version: ee05b128a739a0fb76c7ebd3ae4810c1de808d6d
- name: github.com/mattn/go-sqlite3
version: e118d4451349065b8e7ce0f0af32e033995363f8
- name: github.com/matttproud/golang_protobuf_extensions
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
subpackages:
- pbutil
- name: github.com/mitchellh/mapstructure
version: ca63d7c062ee3c9f34db231e352b60012b4fd0c1
- name: github.com/pelletier/go-buffruneio
@ -98,6 +109,22 @@ imports:
version: 792786c7400a136282c1664665ae0a8db921c6c2
subpackages:
- difflib
- name: github.com/prometheus/client_golang
version: c5b7fccd204277076155f10851dad72b76a49317
subpackages:
- prometheus
- name: github.com/prometheus/client_model
version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6
subpackages:
- go
- name: github.com/prometheus/common
version: 9a94032291f2192936512bab367bc45e77990d6a
subpackages:
- expfmt
- internal/bitbucket.org/ww/goautoneg
- model
- name: github.com/prometheus/procfs
version: abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
- name: github.com/Sirupsen/logrus
version: a283a10442df8dc09befd873fab202bf8a253d6a
- name: github.com/spf13/afero

View file

@ -79,3 +79,7 @@ import:
version: v2.0
- package: github.com/golang/mock
- package: github.com/WatchBeam/clock
- package: github.com/prometheus/client_golang
version: ~0.8.0
subpackages:
- prometheus

View file

@ -1,6 +1,6 @@
package kolide
import "context"
import "golang.org/x/net/context"
// AppConfigStore contains method for saving and retrieving
// application configuration
@ -13,9 +13,9 @@ type AppConfigStore interface {
// AppConfigService provides methods for configuring
// the Kolide application
type AppConfigService interface {
NewOrgInfo(ctx context.Context, p OrgInfoPayload) (*OrgInfo, error)
OrgInfo(ctx context.Context) (*OrgInfo, error)
ModifyOrgInfo(ctx context.Context, p OrgInfoPayload) (*OrgInfo, error)
NewOrgInfo(ctx context.Context, p OrgInfoPayload) (info *OrgInfo, err error)
OrgInfo(ctx context.Context) (info *OrgInfo, err error)
ModifyOrgInfo(ctx context.Context, p OrgInfoPayload) (info *OrgInfo, err error)
}
// OrgInfo holds information about the current

View file

@ -56,14 +56,14 @@ type SessionStore interface {
}
type SessionService interface {
Login(ctx context.Context, username, password string) (*User, string, error)
Logout(ctx context.Context) error
DestroySession(ctx context.Context) error
GetInfoAboutSessionsForUser(ctx context.Context, id uint) ([]*Session, error)
DeleteSessionsForUser(ctx context.Context, id uint) error
GetInfoAboutSession(ctx context.Context, id uint) (*Session, error)
GetSessionByKey(ctx context.Context, key string) (*Session, error)
DeleteSession(ctx context.Context, id uint) error
Login(ctx context.Context, username, password string) (user *User, token string, err error)
Logout(ctx context.Context) (err error)
DestroySession(ctx context.Context) (err error)
GetInfoAboutSessionsForUser(ctx context.Context, id uint) (sessions []*Session, err error)
DeleteSessionsForUser(ctx context.Context, id uint) (err error)
GetInfoAboutSession(ctx context.Context, id uint) (session *Session, err error)
GetSessionByKey(ctx context.Context, key string) (session *Session, err error)
DeleteSession(ctx context.Context, id uint) (err error)
}
// Session is the model object which represents what an active session is

View file

@ -21,30 +21,30 @@ type UserStore interface {
// UserService contains methods for managing a Kolide User
type UserService interface {
// NewUser creates a new User from a request Payload
NewUser(ctx context.Context, p UserPayload) (*User, error)
NewUser(ctx context.Context, p UserPayload) (user *User, err error)
// User returns a valid User given a User ID
User(ctx context.Context, id uint) (*User, error)
User(ctx context.Context, id uint) (user *User, err error)
// AuthenticatedUser returns the current user
// from the viewer context
AuthenticatedUser(ctx context.Context) (*User, error)
AuthenticatedUser(ctx context.Context) (user *User, err error)
// Users returns all users
Users(ctx context.Context) ([]*User, error)
Users(ctx context.Context) (users []*User, err error)
// RequestPasswordReset generates a password reset request for
// a user. The request results in a token emailed to the user.
// If the person making the request is an admin the AdminForcedPasswordReset
// parameter is enabled instead of sending an email with a password reset token
RequestPasswordReset(ctx context.Context, email string) error
RequestPasswordReset(ctx context.Context, email string) (err error)
// ResetPassword validate a password reset token and updates
// a user's password
ResetPassword(ctx context.Context, token, password string) error
ResetPassword(ctx context.Context, token, password string) (err error)
// ModifyUser updates a user's parameters given a UserPayload
ModifyUser(ctx context.Context, userID uint, p UserPayload) (*User, error)
ModifyUser(ctx context.Context, userID uint, p UserPayload) (user *User, err error)
}
// User is the model struct which represents a kolide user

26
server/service/metrics.go Normal file
View file

@ -0,0 +1,26 @@
package service
import (
"github.com/go-kit/kit/metrics"
"github.com/kolide/kolide-ose/server/kolide"
)
type metricsMiddleware struct {
kolide.Service
requestCount metrics.Counter
requestLatency metrics.Histogram
}
// NewMetrics service takes an existing service and wraps it
// with instrumentation middleware.
func NewMetricsService(
svc kolide.Service,
requestCount metrics.Counter,
requestLatency metrics.Histogram,
) kolide.Service {
return metricsMiddleware{
Service: svc,
requestCount: requestCount,
requestLatency: requestLatency,
}
}

View file

@ -0,0 +1,51 @@
package service
import (
"fmt"
"time"
"github.com/kolide/kolide-ose/server/kolide"
"golang.org/x/net/context"
)
func (mw metricsMiddleware) NewOrgInfo(ctx context.Context, p kolide.OrgInfoPayload) (*kolide.OrgInfo, error) {
var (
info *kolide.OrgInfo
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "NewOrgInfo", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
info, err = mw.Service.NewOrgInfo(ctx, p)
return info, err
}
func (mw metricsMiddleware) OrgInfo(ctx context.Context) (*kolide.OrgInfo, error) {
var (
info *kolide.OrgInfo
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "OrgInfo", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
info, err = mw.Service.OrgInfo(ctx)
return info, err
}
func (mw metricsMiddleware) ModifyOrgInfo(ctx context.Context, p kolide.OrgInfoPayload) (*kolide.OrgInfo, error) {
var (
info *kolide.OrgInfo
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "ModifyOrgInfo", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
info, err = mw.Service.ModifyOrgInfo(ctx, p)
return info, err
}

View file

@ -0,0 +1,118 @@
package service
import (
"fmt"
"time"
"github.com/kolide/kolide-ose/server/kolide"
"golang.org/x/net/context"
)
func (mw metricsMiddleware) Login(ctx context.Context, username string, password string) (*kolide.User, string, error) {
var (
user *kolide.User
token string
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "Login", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
user, token, err = mw.Service.Login(ctx, username, password)
return user, token, err
}
func (mw metricsMiddleware) Logout(ctx context.Context) error {
var (
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "Logout", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
err = mw.Service.Logout(ctx)
return err
}
func (mw metricsMiddleware) DestroySession(ctx context.Context) error {
var (
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "DestroySession", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
err = mw.Service.DestroySession(ctx)
return err
}
func (mw metricsMiddleware) GetInfoAboutSessionsForUser(ctx context.Context, id uint) ([]*kolide.Session, error) {
var (
sessions []*kolide.Session
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "GetInfoAboutSessionsForUser", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
sessions, err = mw.Service.GetInfoAboutSessionsForUser(ctx, id)
return sessions, err
}
func (mw metricsMiddleware) DeleteSessionsForUser(ctx context.Context, id uint) error {
var (
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "DeleteSessionsForUser", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
err = mw.Service.DeleteSessionsForUser(ctx, id)
return err
}
func (mw metricsMiddleware) GetInfoAboutSession(ctx context.Context, id uint) (*kolide.Session, error) {
var (
session *kolide.Session
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "GetInfoAboutSession", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
session, err = mw.Service.GetInfoAboutSession(ctx, id)
return session, err
}
func (mw metricsMiddleware) GetSessionByKey(ctx context.Context, key string) (*kolide.Session, error) {
var (
session *kolide.Session
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "GetSessionByKey", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
session, err = mw.Service.GetSessionByKey(ctx, key)
return session, err
}
func (mw metricsMiddleware) DeleteSession(ctx context.Context, id uint) error {
var (
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "DeleteSession", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
err = mw.Service.DeleteSession(ctx, id)
return err
}

View file

@ -0,0 +1,114 @@
package service
import (
"fmt"
"time"
"github.com/kolide/kolide-ose/server/kolide"
"golang.org/x/net/context"
)
func (mw metricsMiddleware) NewUser(ctx context.Context, p kolide.UserPayload) (*kolide.User, error) {
var (
user *kolide.User
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "NewUser", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
user, err = mw.Service.NewUser(ctx, p)
return user, err
}
func (mw metricsMiddleware) ModifyUser(ctx context.Context, userID uint, p kolide.UserPayload) (*kolide.User, error) {
var (
user *kolide.User
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "ModifyUser", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
user, err = mw.Service.ModifyUser(ctx, userID, p)
return user, err
}
func (mw metricsMiddleware) User(ctx context.Context, id uint) (*kolide.User, error) {
var (
user *kolide.User
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "User", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
user, err = mw.Service.User(ctx, id)
return user, err
}
func (mw metricsMiddleware) Users(ctx context.Context) ([]*kolide.User, error) {
var (
users []*kolide.User
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "Users", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
users, err = mw.Service.Users(ctx)
return users, err
}
func (mw metricsMiddleware) AuthenticatedUser(ctx context.Context) (*kolide.User, error) {
var (
user *kolide.User
err error
)
defer func(begin time.Time) {
lvs := []string{"method", "AuthenticatedUser", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
user, err = mw.Service.AuthenticatedUser(ctx)
return user, err
}
func (mw metricsMiddleware) ResetPassword(ctx context.Context, token, password string) error {
var err error
defer func(begin time.Time) {
lvs := []string{"method", "ResetPassword", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
err = mw.Service.ResetPassword(ctx, token, password)
return err
}
func (mw metricsMiddleware) RequestPasswordReset(ctx context.Context, email string) error {
var err error
defer func(begin time.Time) {
lvs := []string{"method", "RequestPasswordReset", "error", fmt.Sprint(err != nil)}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
}(time.Now())
err = mw.Service.RequestPasswordReset(ctx, email)
return err
}

View file

@ -1,9 +1,8 @@
package service
import (
"context"
"github.com/kolide/kolide-ose/server/kolide"
"golang.org/x/net/context"
)
func (svc service) NewOrgInfo(ctx context.Context, p kolide.OrgInfoPayload) (*kolide.OrgInfo, error) {