mirror of
https://github.com/foomo/keel.git
synced 2025-10-16 12:35:34 +00:00
feat: add GoRoutine service
moves all services into the service package
This commit is contained in:
parent
dfef906811
commit
07f0c394d5
@ -25,6 +25,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -39,7 +40,7 @@ func main() {
|
|||||||
svs := newService()
|
svs := newService()
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", ":8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -5,6 +5,5 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrServerNotRunning = errors.New("server not running")
|
ErrServerNotRunning = errors.New("server not running")
|
||||||
ErrServiceNotRunning = errors.New("service not running")
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/config"
|
"github.com/foomo/keel/config"
|
||||||
@ -85,7 +86,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8081", svs),
|
service.NewHTTP(l, "demo", "localhost:8081", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
@ -32,7 +33,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/examples/healthz/handler"
|
"github.com/foomo/keel/examples/healthz/handler"
|
||||||
|
"github.com/foomo/keel/healthz"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// See k8s for probe documentation
|
// See k8s for probe documentation
|
||||||
@ -46,7 +48,7 @@ func main() {
|
|||||||
svr.AddReadinessHealthzers(rh)
|
svr.AddReadinessHealthzers(rh)
|
||||||
|
|
||||||
// add inline probe e.g. in case you start go routines
|
// add inline probe e.g. in case you start go routines
|
||||||
svr.AddAlwaysHealthzers(keel.NewHealthzerFn(func(ctx context.Context) error {
|
svr.AddAlwaysHealthzers(healthz.NewHealthzerFn(func(ctx context.Context) error {
|
||||||
l.Info("healther fn")
|
l.Info("healther fn")
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
@ -69,7 +71,7 @@ func main() {
|
|||||||
|
|
||||||
// add services
|
// add services
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
// start serer
|
// start serer
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/log"
|
"github.com/foomo/keel/log"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CustomError struct {
|
type CustomError struct {
|
||||||
@ -46,7 +47,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/log"
|
"github.com/foomo/keel/log"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
httputils "github.com/foomo/keel/utils/net/http"
|
httputils "github.com/foomo/keel/utils/net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ func main() {
|
|||||||
log.Must(l, err, "failed to hash password")
|
log.Must(l, err, "failed to hash password")
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.BasicAuth(
|
middleware.BasicAuth(
|
||||||
username,
|
username,
|
||||||
passwordHash,
|
passwordHash,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
keelhttp "github.com/foomo/keel/net/http"
|
keelhttp "github.com/foomo/keel/net/http"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -22,7 +23,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.CORS(
|
middleware.CORS(
|
||||||
middleware.CORSWithAllowOrigins("example.com"),
|
middleware.CORSWithAllowOrigins("example.com"),
|
||||||
middleware.CORSWithAllowMethods(http.MethodGet, http.MethodPost),
|
middleware.CORSWithAllowMethods(http.MethodGet, http.MethodPost),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
jwt2 "github.com/golang-jwt/jwt"
|
jwt2 "github.com/golang-jwt/jwt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Skip(
|
middleware.Skip(
|
||||||
middleware.JWT(
|
middleware.JWT(
|
||||||
jwtInst,
|
jwtInst,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
jwt2 "github.com/golang-jwt/jwt"
|
jwt2 "github.com/golang-jwt/jwt"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
@ -66,7 +67,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Skip(
|
middleware.Skip(
|
||||||
middleware.JWT(
|
middleware.JWT(
|
||||||
jwtInst,
|
jwtInst,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
keelhttp "github.com/foomo/keel/net/http"
|
keelhttp "github.com/foomo/keel/net/http"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -22,7 +23,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Logger(),
|
middleware.Logger(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -23,7 +24,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Recover(
|
middleware.Recover(
|
||||||
middleware.RecoverWithDisablePrintStack(true),
|
middleware.RecoverWithDisablePrintStack(true),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
keelhttp "github.com/foomo/keel/net/http"
|
keelhttp "github.com/foomo/keel/net/http"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -27,7 +28,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.RequestID(
|
middleware.RequestID(
|
||||||
middleware.RequestIDWithSetResponseHeader(true),
|
middleware.RequestIDWithSetResponseHeader(true),
|
||||||
middleware.RequestIDWithGenerator(requestIDGenerator),
|
middleware.RequestIDWithGenerator(requestIDGenerator),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -27,7 +28,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.ResponseTime(
|
middleware.ResponseTime(
|
||||||
// automatically set cookie if not exists
|
// automatically set cookie if not exists
|
||||||
middleware.ResponseTimeWithMaxDuration(time.Millisecond*500),
|
middleware.ResponseTimeWithMaxDuration(time.Millisecond*500),
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
keelhttp "github.com/foomo/keel/net/http"
|
keelhttp "github.com/foomo/keel/net/http"
|
||||||
"github.com/foomo/keel/net/http/cookie"
|
"github.com/foomo/keel/net/http/cookie"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -44,7 +45,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.SessionID(
|
middleware.SessionID(
|
||||||
// automatically set cookie if not exists
|
// automatically set cookie if not exists
|
||||||
middleware.SessionIDWithSetCookie(true),
|
middleware.SessionIDWithSetCookie(true),
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
@ -28,7 +29,7 @@ func main() {
|
|||||||
|
|
||||||
svr.AddServices(
|
svr.AddServices(
|
||||||
// with URI blacklist
|
// with URI blacklist
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Skip(
|
middleware.Skip(
|
||||||
func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
||||||
return http.NotFoundHandler()
|
return http.NotFoundHandler()
|
||||||
@ -38,7 +39,7 @@ func main() {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// with URI whitelist
|
// with URI whitelist
|
||||||
keel.NewServiceHTTP(l, "demo", ":8081", svs,
|
service.NewHTTP(l, "demo", "localhost:8081", svs,
|
||||||
middleware.Skip(
|
middleware.Skip(
|
||||||
func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
||||||
return http.NotFoundHandler()
|
return http.NotFoundHandler()
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -23,7 +24,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Telemetry(
|
middleware.Telemetry(
|
||||||
middleware.TelemetryWithInjectPropagationHeader(true),
|
middleware.TelemetryWithInjectPropagationHeader(true),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -26,7 +27,7 @@ func main() {
|
|||||||
tokenProvider := middleware.CookieTokenProvider("keel-token")
|
tokenProvider := middleware.CookieTokenProvider("keel-token")
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.TokenAuth(
|
middleware.TokenAuth(
|
||||||
token,
|
token,
|
||||||
middleware.TokenAuthWithTokenProvider(tokenProvider),
|
middleware.TokenAuthWithTokenProvider(tokenProvider),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -29,7 +30,7 @@ func main() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.TokenAuth(
|
middleware.TokenAuth(
|
||||||
token,
|
token,
|
||||||
middleware.TokenAuthWithTokenProvider(tokenProvider),
|
middleware.TokenAuthWithTokenProvider(tokenProvider),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/config"
|
"github.com/foomo/keel/config"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -42,7 +43,7 @@ func main() {
|
|||||||
|
|
||||||
// curl localhost:8080
|
// curl localhost:8080
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", http.HandlerFunc(
|
service.NewHTTP(l, "demo", "localhost:8080", http.HandlerFunc(
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Println("current foo:", fooFn()) //nolint:forbidigo
|
fmt.Println("current foo:", fooFn()) //nolint:forbidigo
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func server() {
|
func server() {
|
||||||
@ -26,7 +27,7 @@ func server() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
keelhttp "github.com/foomo/keel/net/http"
|
keelhttp "github.com/foomo/keel/net/http"
|
||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
"github.com/foomo/keel/net/http/roundtripware"
|
"github.com/foomo/keel/net/http/roundtripware"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
httputils "github.com/foomo/keel/utils/net/http"
|
httputils "github.com/foomo/keel/utils/net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
// add middleware
|
// add middleware
|
||||||
middleware.RequestID(),
|
middleware.RequestID(),
|
||||||
// add middleware
|
// add middleware
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func server() {
|
func server() {
|
||||||
@ -27,7 +28,7 @@ func server() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
"github.com/foomo/keel/config"
|
"github.com/foomo/keel/config"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -23,7 +24,7 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
svr.AddServices(
|
svr.AddServices(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080",
|
service.NewHTTP(l, "demo", "localhost:8080",
|
||||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
c.Set("service.enabled", !enabled())
|
c.Set("service.enabled", !enabled())
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
@ -32,7 +33,7 @@ func main() {
|
|||||||
),
|
),
|
||||||
keel.NewServiceEnabler(l, "service-enabler",
|
keel.NewServiceEnabler(l, "service-enabler",
|
||||||
func() keel.Service {
|
func() keel.Service {
|
||||||
return keel.NewServiceHTTP(l, "service", "localhost:8081", svs)
|
return service.NewHTTP(l, "service", "localhost:8081", svs)
|
||||||
},
|
},
|
||||||
enabled,
|
enabled,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
@ -29,24 +28,11 @@ func main() {
|
|||||||
keel.WithHTTPPProfService(false),
|
keel.WithHTTPPProfService(false),
|
||||||
)
|
)
|
||||||
|
|
||||||
l := svr.Logger()
|
|
||||||
|
|
||||||
// alternatively you can add them manually
|
// alternatively you can add them manually
|
||||||
// svr.AddServices(keel.NewDefaultServiceHTTPZap())
|
// svr.AddServices(keel.NewDefaultServiceHTTPZap())
|
||||||
// svr.AddServices(keel.NewDefaultServiceHTTPViper())
|
// svr.AddServices(keel.NewDefaultServiceHTTPViper())
|
||||||
// svr.AddServices(keel.NewDefaultServiceHTTPPProf())
|
// svr.AddServices(keel.NewDefaultServiceHTTPPProf())
|
||||||
// svr.AddServices(keel.NewDefaultServiceHTTPPrometheus())
|
// svr.AddServices(keel.NewDefaultServiceHTTPPrometheus())
|
||||||
|
|
||||||
// create demo service
|
|
||||||
svs := http.NewServeMux()
|
|
||||||
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
_, _ = w.Write([]byte("OK"))
|
|
||||||
})
|
|
||||||
|
|
||||||
svr.AddService(
|
|
||||||
keel.NewServiceHTTP(l, "demo", ":8080", svs),
|
|
||||||
)
|
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -89,7 +90,7 @@ func main() {
|
|||||||
svr.AddClosers(subscription, stream)
|
svr.AddClosers(subscription, stream)
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
|
|
||||||
"github.com/foomo/keel"
|
"github.com/foomo/keel"
|
||||||
@ -73,7 +74,7 @@ func main() {
|
|||||||
svr.AddClosers(subscription, stream.Conn())
|
svr.AddClosers(subscription, stream.Conn())
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
)
|
)
|
||||||
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/metric/instrument"
|
"go.opentelemetry.io/otel/metric/instrument"
|
||||||
|
|
||||||
@ -58,6 +61,14 @@ func main() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
promauto.NewCounter(prometheus.CounterOpts{
|
||||||
|
Namespace: "foo",
|
||||||
|
Subsystem: "",
|
||||||
|
Name: "bar",
|
||||||
|
Help: "blubb",
|
||||||
|
ConstLabels: nil,
|
||||||
|
})
|
||||||
|
|
||||||
{ // up down
|
{ // up down
|
||||||
upDown, err := meter.SyncInt64().UpDownCounter(
|
upDown, err := meter.SyncInt64().UpDownCounter(
|
||||||
"a.updown",
|
"a.updown",
|
||||||
@ -92,7 +103,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
svr.AddService(
|
svr.AddService(
|
||||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||||
middleware.Telemetry(),
|
middleware.Telemetry(),
|
||||||
middleware.Recover(),
|
middleware.Recover(),
|
||||||
),
|
),
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.20
|
|||||||
require (
|
require (
|
||||||
github.com/avast/retry-go v3.0.0+incompatible
|
github.com/avast/retry-go v3.0.0+incompatible
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
|
github.com/fbiville/markdown-table-formatter v0.3.0
|
||||||
github.com/foomo/gotsrpc/v2 v2.7.2
|
github.com/foomo/gotsrpc/v2 v2.7.2
|
||||||
github.com/go-logr/logr v1.2.4
|
github.com/go-logr/logr v1.2.4
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -117,6 +117,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
|||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
|
github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho=
|
||||||
|
github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY=
|
||||||
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||||
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/foomo/gotsrpc/v2 v2.7.2 h1:a94V/a8LSssq+aRN3Fv1lJPjWoyMilOvRq+yEaDTHVM=
|
github.com/foomo/gotsrpc/v2 v2.7.2 h1:a94V/a8LSssq+aRN3Fv1lJPjWoyMilOvRq+yEaDTHVM=
|
||||||
|
|||||||
1
healthz/docs.go
Normal file
1
healthz/docs.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package healthz
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package healthz
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
@ -16,6 +16,10 @@ func (h healther) Healthz(ctx context.Context) error {
|
|||||||
return h.handle(ctx)
|
return h.handle(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h healther) Close(ctx context.Context) error {
|
||||||
|
return h.handle(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// BoolHealthzer interface
|
// BoolHealthzer interface
|
||||||
type BoolHealthzer interface {
|
type BoolHealthzer interface {
|
||||||
Healthz() bool
|
Healthz() bool
|
||||||
@ -1,31 +1,31 @@
|
|||||||
package keel
|
package healthz
|
||||||
|
|
||||||
// HealthzType type
|
// Type type
|
||||||
// https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
// https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
|
||||||
type HealthzType string
|
type Type string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// HealthzTypeAlways will run on any checks
|
// TypeAlways will run on any checks
|
||||||
HealthzTypeAlways HealthzType = "always"
|
TypeAlways Type = "always"
|
||||||
// HealthzTypeStartup will run on /healthz/startup checks
|
// TypeStartup will run on /healthz/startup checks
|
||||||
// > The kubelet uses startup probes to know when a container application has started. If such a probe is configured,
|
// > The kubelet uses startup probes to know when a container application has started. If such a probe is configured,
|
||||||
// > it disables liveness and readiness checks until it succeeds, making sure those probes don't interfere with the
|
// > it disables liveness and readiness checks until it succeeds, making sure those probes don't interfere with the
|
||||||
// > application startup. This can be used to adopt liveness checks on slow starting containers, avoiding them getting
|
// > application startup. This can be used to adopt liveness checks on slow starting containers, avoiding them getting
|
||||||
// > killed by the kubelet before they are up and running.
|
// > killed by the kubelet before they are up and running.
|
||||||
HealthzTypeStartup HealthzType = "startup"
|
TypeStartup Type = "startup"
|
||||||
// HealthzTypeReadiness will run on /healthz/readiness checks
|
// TypeReadiness will run on /healthz/readiness checks
|
||||||
// > The kubelet uses readiness probes to know when a container is ready to start accepting traffic.
|
// > The kubelet uses readiness probes to know when a container is ready to start accepting traffic.
|
||||||
// > A Pod is considered ready when all of its containers are ready. One use of this signal is to control
|
// > A Pod is considered ready when all of its containers are ready. One use of this signal is to control
|
||||||
// > which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.
|
// > which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.
|
||||||
HealthzTypeReadiness HealthzType = "readiness"
|
TypeReadiness Type = "readiness"
|
||||||
// HealthzTypeLiveness will run on /healthz/liveness checks
|
// TypeLiveness will run on /healthz/liveness checks
|
||||||
// > The kubelet uses liveness probes to know when to restart a container. For example, liveness probes could catch
|
// > The kubelet uses liveness probes to know when to restart a container. For example, liveness probes could catch
|
||||||
// > a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state
|
// > a deadlock, where an application is running, but unable to make progress. Restarting a container in such a state
|
||||||
// > can help to make the application more available despite bugs.
|
// > can help to make the application more available despite bugs.
|
||||||
HealthzTypeLiveness HealthzType = "liveness"
|
TypeLiveness Type = "liveness"
|
||||||
)
|
)
|
||||||
|
|
||||||
// String interface
|
// String interface
|
||||||
func (t HealthzType) String() string {
|
func (t Type) String() string {
|
||||||
return string(t)
|
return string(t)
|
||||||
}
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
package keel
|
package interfaces
|
||||||
|
|
||||||
import "context"
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
type closer struct {
|
type closer struct {
|
||||||
handle func(context.Context) error
|
handle func(context.Context) error
|
||||||
@ -12,10 +14,6 @@ func NewCloserFn(handle func(context.Context) error) closer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h healther) Close(ctx context.Context) error {
|
|
||||||
return h.handle(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Closer interface
|
// Closer interface
|
||||||
type Closer interface {
|
type Closer interface {
|
||||||
Close()
|
Close()
|
||||||
1
interfaces/doc.go
Normal file
1
interfaces/doc.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package interfaces
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package interfaces
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package interfaces
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package interfaces
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package interfaces
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
11
log/fields_keel.go
Normal file
11
log/fields_keel.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KeelServiceTypeKey = attribute.Key("keel.service.type")
|
||||||
|
KeelServiceNameKey = attribute.Key("keel.service.name")
|
||||||
|
KeelServiceInstKey = attribute.Key("keel.service.inst")
|
||||||
|
)
|
||||||
@ -15,6 +15,8 @@ func FPeerService(name string) zap.Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
ServiceTypeKey = "service_type"
|
||||||
|
|
||||||
// ServiceNameKey represents the NameKey of the service.
|
// ServiceNameKey represents the NameKey of the service.
|
||||||
ServiceNameKey = "service_name"
|
ServiceNameKey = "service_name"
|
||||||
|
|
||||||
@ -35,6 +37,10 @@ const (
|
|||||||
ServiceVersionKey = "service_version"
|
ServiceVersionKey = "service_version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func FServiceType(name string) zap.Field {
|
||||||
|
return zap.String(ServiceTypeKey, name)
|
||||||
|
}
|
||||||
|
|
||||||
func FServiceName(name string) zap.Field {
|
func FServiceName(name string) zap.Field {
|
||||||
return zap.String(ServiceNameKey, name)
|
return zap.String(ServiceNameKey, name)
|
||||||
}
|
}
|
||||||
|
|||||||
12
log/with.go
12
log/with.go
@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
@ -20,6 +21,17 @@ func With(l *zap.Logger, fields ...zap.Field) *zap.Logger {
|
|||||||
return l.With(fields...)
|
return l.With(fields...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithAttributes(l *zap.Logger, attrs ...attribute.KeyValue) *zap.Logger {
|
||||||
|
if l == nil {
|
||||||
|
l = Logger()
|
||||||
|
}
|
||||||
|
fields := make([]zap.Field, len(attrs))
|
||||||
|
for i, attr := range attrs {
|
||||||
|
fields[i] = zap.Any(strings.ReplaceAll(string(attr.Key), ".", "_"), attr.Value.AsInterface())
|
||||||
|
}
|
||||||
|
return l.With(fields...)
|
||||||
|
}
|
||||||
|
|
||||||
func WithError(l *zap.Logger, err error) *zap.Logger {
|
func WithError(l *zap.Logger, err error) *zap.Logger {
|
||||||
return With(l, FErrorType(err), FError(err))
|
return With(l, FErrorType(err), FError(err))
|
||||||
}
|
}
|
||||||
|
|||||||
31
option.go
31
option.go
@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
@ -72,9 +73,9 @@ func WithShutdownTimeout(shutdownTimeout time.Duration) Option {
|
|||||||
func WithHTTPZapService(enabled bool) Option {
|
func WithHTTPZapService(enabled bool) Option {
|
||||||
return func(inst *Server) {
|
return func(inst *Server) {
|
||||||
if config.GetBool(inst.Config(), "service.zap.enabled", enabled)() {
|
if config.GetBool(inst.Config(), "service.zap.enabled", enabled)() {
|
||||||
service := NewDefaultServiceHTTPZap()
|
svs := service.NewDefaultHTTPZap()
|
||||||
inst.initServices = append(inst.initServices, service)
|
inst.initServices = append(inst.initServices, svs)
|
||||||
inst.AddAlwaysHealthzers(service)
|
inst.AddAlwaysHealthzers(svs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,9 +84,9 @@ func WithHTTPZapService(enabled bool) Option {
|
|||||||
func WithHTTPViperService(enabled bool) Option {
|
func WithHTTPViperService(enabled bool) Option {
|
||||||
return func(inst *Server) {
|
return func(inst *Server) {
|
||||||
if config.GetBool(inst.Config(), "service.viper.enabled", enabled)() {
|
if config.GetBool(inst.Config(), "service.viper.enabled", enabled)() {
|
||||||
service := NewDefaultServiceHTTPViper()
|
svs := service.NewDefaultHTTPViper()
|
||||||
inst.initServices = append(inst.initServices, service)
|
inst.initServices = append(inst.initServices, svs)
|
||||||
inst.AddAlwaysHealthzers(service)
|
inst.AddAlwaysHealthzers(svs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,9 +150,9 @@ func WithPrometheusMeter(enabled bool) Option {
|
|||||||
func WithHTTPPrometheusService(enabled bool) Option {
|
func WithHTTPPrometheusService(enabled bool) Option {
|
||||||
return func(inst *Server) {
|
return func(inst *Server) {
|
||||||
if config.GetBool(inst.Config(), "service.prometheus.enabled", enabled)() {
|
if config.GetBool(inst.Config(), "service.prometheus.enabled", enabled)() {
|
||||||
service := NewDefaultServiceHTTPPrometheus()
|
svs := service.NewDefaultHTTPPrometheus()
|
||||||
inst.initServices = append(inst.initServices, service)
|
inst.initServices = append(inst.initServices, svs)
|
||||||
inst.AddAlwaysHealthzers(service)
|
inst.AddAlwaysHealthzers(svs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,9 +161,9 @@ func WithHTTPPrometheusService(enabled bool) Option {
|
|||||||
func WithHTTPPProfService(enabled bool) Option {
|
func WithHTTPPProfService(enabled bool) Option {
|
||||||
return func(inst *Server) {
|
return func(inst *Server) {
|
||||||
if config.GetBool(inst.Config(), "service.pprof.enabled", enabled)() {
|
if config.GetBool(inst.Config(), "service.pprof.enabled", enabled)() {
|
||||||
service := NewDefaultServiceHTTPPProf()
|
svs := service.NewDefaultHTTPPProf()
|
||||||
inst.initServices = append(inst.initServices, service)
|
inst.initServices = append(inst.initServices, svs)
|
||||||
inst.AddAlwaysHealthzers(service)
|
inst.AddAlwaysHealthzers(svs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,9 +172,9 @@ func WithHTTPPProfService(enabled bool) Option {
|
|||||||
func WithHTTPHealthzService(enabled bool) Option {
|
func WithHTTPHealthzService(enabled bool) Option {
|
||||||
return func(inst *Server) {
|
return func(inst *Server) {
|
||||||
if config.GetBool(inst.Config(), "service.healthz.enabled", enabled)() {
|
if config.GetBool(inst.Config(), "service.healthz.enabled", enabled)() {
|
||||||
service := NewDefaultServiceHTTPProbes(inst.probes)
|
svs := service.NewDefaultHTTPProbes(inst.probes)
|
||||||
inst.initServices = append(inst.initServices, service)
|
inst.initServices = append(inst.initServices, svs)
|
||||||
inst.AddAlwaysHealthzers(service)
|
inst.AddAlwaysHealthzers(svs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
97
server.go
97
server.go
@ -1,3 +1,6 @@
|
|||||||
|
//go:build !docs
|
||||||
|
// +build !docs
|
||||||
|
|
||||||
package keel
|
package keel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -10,6 +13,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/healthz"
|
||||||
|
"github.com/foomo/keel/interfaces"
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -40,7 +45,7 @@ type Server struct {
|
|||||||
shutdownTimeout time.Duration
|
shutdownTimeout time.Duration
|
||||||
running atomic.Bool
|
running atomic.Bool
|
||||||
closers []interface{}
|
closers []interface{}
|
||||||
probes map[HealthzType][]interface{}
|
probes map[healthz.Type][]interface{}
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel context.Context
|
ctxCancel context.Context
|
||||||
ctxCancelFn context.CancelFunc
|
ctxCancelFn context.CancelFunc
|
||||||
@ -54,7 +59,7 @@ func NewServer(opts ...Option) *Server {
|
|||||||
inst := &Server{
|
inst := &Server{
|
||||||
shutdownTimeout: 30 * time.Second,
|
shutdownTimeout: 30 * time.Second,
|
||||||
shutdownSignals: []os.Signal{os.Interrupt, syscall.SIGTERM},
|
shutdownSignals: []os.Signal{os.Interrupt, syscall.SIGTERM},
|
||||||
probes: map[HealthzType][]interface{}{},
|
probes: map[healthz.Type][]interface{}{},
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
c: config.Config(),
|
c: config.Config(),
|
||||||
l: log.Logger(),
|
l: log.Logger(),
|
||||||
@ -83,51 +88,51 @@ func NewServer(opts ...Option) *Server {
|
|||||||
for _, closer := range closers {
|
for _, closer := range closers {
|
||||||
l := inst.l.With(log.FName(fmt.Sprintf("%T", closer)))
|
l := inst.l.With(log.FName(fmt.Sprintf("%T", closer)))
|
||||||
switch c := closer.(type) {
|
switch c := closer.(type) {
|
||||||
case Closer:
|
case interfaces.Closer:
|
||||||
c.Close()
|
c.Close()
|
||||||
case ErrorCloser:
|
case interfaces.ErrorCloser:
|
||||||
if err := c.Close(); err != nil {
|
if err := c.Close(); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorCloser")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorCloser")
|
||||||
}
|
}
|
||||||
case CloserWithContext:
|
case interfaces.CloserWithContext:
|
||||||
c.Close(timeoutCtx)
|
c.Close(timeoutCtx)
|
||||||
case ErrorCloserWithContext:
|
case interfaces.ErrorCloserWithContext:
|
||||||
if err := c.Close(timeoutCtx); err != nil {
|
if err := c.Close(timeoutCtx); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorCloserWithContext")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorCloserWithContext")
|
||||||
}
|
}
|
||||||
case Shutdowner:
|
case interfaces.Shutdowner:
|
||||||
c.Shutdown()
|
c.Shutdown()
|
||||||
case ErrorShutdowner:
|
case interfaces.ErrorShutdowner:
|
||||||
if err := c.Shutdown(); err != nil {
|
if err := c.Shutdown(); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorShutdowner")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorShutdowner")
|
||||||
}
|
}
|
||||||
case ShutdownerWithContext:
|
case interfaces.ShutdownerWithContext:
|
||||||
c.Shutdown(timeoutCtx)
|
c.Shutdown(timeoutCtx)
|
||||||
case ErrorShutdownerWithContext:
|
case interfaces.ErrorShutdownerWithContext:
|
||||||
if err := c.Shutdown(timeoutCtx); err != nil {
|
if err := c.Shutdown(timeoutCtx); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorShutdownerWithContext")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorShutdownerWithContext")
|
||||||
}
|
}
|
||||||
case Stopper:
|
case interfaces.Stopper:
|
||||||
c.Stop()
|
c.Stop()
|
||||||
case ErrorStopper:
|
case interfaces.ErrorStopper:
|
||||||
if err := c.Stop(); err != nil {
|
if err := c.Stop(); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorStopper")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorStopper")
|
||||||
}
|
}
|
||||||
case StopperWithContext:
|
case interfaces.StopperWithContext:
|
||||||
c.Stop(timeoutCtx)
|
c.Stop(timeoutCtx)
|
||||||
case ErrorStopperWithContext:
|
case interfaces.ErrorStopperWithContext:
|
||||||
if err := c.Stop(timeoutCtx); err != nil {
|
if err := c.Stop(timeoutCtx); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorStopperWithContext")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorStopperWithContext")
|
||||||
}
|
}
|
||||||
case Unsubscriber:
|
case interfaces.Unsubscriber:
|
||||||
c.Unsubscribe()
|
c.Unsubscribe()
|
||||||
case ErrorUnsubscriber:
|
case interfaces.ErrorUnsubscriber:
|
||||||
if err := c.Unsubscribe(); err != nil {
|
if err := c.Unsubscribe(); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriber")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriber")
|
||||||
}
|
}
|
||||||
case UnsubscriberWithContext:
|
case interfaces.UnsubscriberWithContext:
|
||||||
c.Unsubscribe(timeoutCtx)
|
c.Unsubscribe(timeoutCtx)
|
||||||
case ErrorUnsubscriberWithContext:
|
case interfaces.ErrorUnsubscriberWithContext:
|
||||||
if err := c.Unsubscribe(timeoutCtx); err != nil {
|
if err := c.Unsubscribe(timeoutCtx); err != nil {
|
||||||
log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriberWithContext")
|
log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriberWithContext")
|
||||||
}
|
}
|
||||||
@ -229,22 +234,22 @@ func (s *Server) AddCloser(closer interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch closer.(type) {
|
switch closer.(type) {
|
||||||
case Closer,
|
case interfaces.Closer,
|
||||||
ErrorCloser,
|
interfaces.ErrorCloser,
|
||||||
CloserWithContext,
|
interfaces.CloserWithContext,
|
||||||
ErrorCloserWithContext,
|
interfaces.ErrorCloserWithContext,
|
||||||
Shutdowner,
|
interfaces.Shutdowner,
|
||||||
ErrorShutdowner,
|
interfaces.ErrorShutdowner,
|
||||||
ShutdownerWithContext,
|
interfaces.ShutdownerWithContext,
|
||||||
ErrorShutdownerWithContext,
|
interfaces.ErrorShutdownerWithContext,
|
||||||
Stopper,
|
interfaces.Stopper,
|
||||||
ErrorStopper,
|
interfaces.ErrorStopper,
|
||||||
StopperWithContext,
|
interfaces.StopperWithContext,
|
||||||
ErrorStopperWithContext,
|
interfaces.ErrorStopperWithContext,
|
||||||
Unsubscriber,
|
interfaces.Unsubscriber,
|
||||||
ErrorUnsubscriber,
|
interfaces.ErrorUnsubscriber,
|
||||||
UnsubscriberWithContext,
|
interfaces.UnsubscriberWithContext,
|
||||||
ErrorUnsubscriberWithContext:
|
interfaces.ErrorUnsubscriberWithContext:
|
||||||
s.closers = append(s.closers, closer)
|
s.closers = append(s.closers, closer)
|
||||||
default:
|
default:
|
||||||
s.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer)))
|
s.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer)))
|
||||||
@ -259,14 +264,14 @@ func (s *Server) AddClosers(closers ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddHealthzer adds a probe to be called on healthz checks
|
// AddHealthzer adds a probe to be called on healthz checks
|
||||||
func (s *Server) AddHealthzer(typ HealthzType, probe interface{}) {
|
func (s *Server) AddHealthzer(typ healthz.Type, probe interface{}) {
|
||||||
switch probe.(type) {
|
switch probe.(type) {
|
||||||
case BoolHealthzer,
|
case healthz.BoolHealthzer,
|
||||||
BoolHealthzerWithContext,
|
healthz.BoolHealthzerWithContext,
|
||||||
ErrorHealthzer,
|
healthz.ErrorHealthzer,
|
||||||
ErrorHealthzWithContext,
|
healthz.ErrorHealthzWithContext,
|
||||||
ErrorPinger,
|
interfaces.ErrorPinger,
|
||||||
ErrorPingerWithContext:
|
interfaces.ErrorPingerWithContext:
|
||||||
s.probes[typ] = append(s.probes[typ], probe)
|
s.probes[typ] = append(s.probes[typ], probe)
|
||||||
default:
|
default:
|
||||||
s.l.Debug("not a healthz probe", log.FValue(fmt.Sprintf("%T", probe)))
|
s.l.Debug("not a healthz probe", log.FValue(fmt.Sprintf("%T", probe)))
|
||||||
@ -274,7 +279,7 @@ func (s *Server) AddHealthzer(typ HealthzType, probe interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddHealthzers adds the given probes to be called on healthz checks
|
// AddHealthzers adds the given probes to be called on healthz checks
|
||||||
func (s *Server) AddHealthzers(typ HealthzType, probes ...interface{}) {
|
func (s *Server) AddHealthzers(typ healthz.Type, probes ...interface{}) {
|
||||||
for _, probe := range probes {
|
for _, probe := range probes {
|
||||||
s.AddHealthzer(typ, probe)
|
s.AddHealthzer(typ, probe)
|
||||||
}
|
}
|
||||||
@ -282,22 +287,22 @@ func (s *Server) AddHealthzers(typ HealthzType, probes ...interface{}) {
|
|||||||
|
|
||||||
// AddAlwaysHealthzers adds the probes to be called on any healthz checks
|
// AddAlwaysHealthzers adds the probes to be called on any healthz checks
|
||||||
func (s *Server) AddAlwaysHealthzers(probes ...interface{}) {
|
func (s *Server) AddAlwaysHealthzers(probes ...interface{}) {
|
||||||
s.AddHealthzers(HealthzTypeAlways, probes...)
|
s.AddHealthzers(healthz.TypeAlways, probes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddStartupHealthzers adds the startup probes to be called on healthz checks
|
// AddStartupHealthzers adds the startup probes to be called on healthz checks
|
||||||
func (s *Server) AddStartupHealthzers(probes ...interface{}) {
|
func (s *Server) AddStartupHealthzers(probes ...interface{}) {
|
||||||
s.AddHealthzers(HealthzTypeStartup, probes...)
|
s.AddHealthzers(healthz.TypeStartup, probes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLivenessHealthzers adds the liveness probes to be called on healthz checks
|
// AddLivenessHealthzers adds the liveness probes to be called on healthz checks
|
||||||
func (s *Server) AddLivenessHealthzers(probes ...interface{}) {
|
func (s *Server) AddLivenessHealthzers(probes ...interface{}) {
|
||||||
s.AddHealthzers(HealthzTypeLiveness, probes...)
|
s.AddHealthzers(healthz.TypeLiveness, probes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddReadinessHealthzers adds the readiness probes to be called on healthz checks
|
// AddReadinessHealthzers adds the readiness probes to be called on healthz checks
|
||||||
func (s *Server) AddReadinessHealthzers(probes ...interface{}) {
|
func (s *Server) AddReadinessHealthzers(probes ...interface{}) {
|
||||||
s.AddHealthzers(HealthzTypeReadiness, probes...)
|
s.AddHealthzers(healthz.TypeReadiness, probes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsCanceled returns true if the internal errgroup has been canceled
|
// IsCanceled returns true if the internal errgroup has been canceled
|
||||||
|
|||||||
435
server_docs.go
Normal file
435
server_docs.go
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
//go:build docs
|
||||||
|
// +build docs
|
||||||
|
|
||||||
|
package keel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
markdowntable "github.com/fbiville/markdown-table-formatter/pkg/markdown"
|
||||||
|
"github.com/foomo/keel/config"
|
||||||
|
"github.com/foomo/keel/healthz"
|
||||||
|
"github.com/foomo/keel/interfaces"
|
||||||
|
"github.com/foomo/keel/log"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
|
"github.com/foomo/keel/telemetry/nonrecording"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
otelglobal "go.opentelemetry.io/otel/metric/global"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server struct
|
||||||
|
type Server struct {
|
||||||
|
services []Service
|
||||||
|
initServices []Service
|
||||||
|
meter metric.Meter
|
||||||
|
meterProvider metric.MeterProvider
|
||||||
|
tracer trace.Tracer
|
||||||
|
traceProvider trace.TracerProvider
|
||||||
|
shutdownSignals []os.Signal
|
||||||
|
shutdownTimeout time.Duration
|
||||||
|
closers []interface{}
|
||||||
|
probes map[healthz.Type][]interface{}
|
||||||
|
ctx context.Context
|
||||||
|
gCtx context.Context
|
||||||
|
l *zap.Logger
|
||||||
|
c *viper.Viper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(opts ...Option) *Server {
|
||||||
|
inst := &Server{
|
||||||
|
probes: map[healthz.Type][]interface{}{},
|
||||||
|
meterProvider: nonrecording.NewNoopMeterProvider(),
|
||||||
|
traceProvider: trace.NewNoopTracerProvider(),
|
||||||
|
ctx: context.Background(),
|
||||||
|
c: config.Config(),
|
||||||
|
l: log.Logger(),
|
||||||
|
}
|
||||||
|
|
||||||
|
inst.meter = inst.meterProvider.Meter("")
|
||||||
|
otelglobal.SetMeterProvider(inst.meterProvider)
|
||||||
|
inst.tracer = inst.traceProvider.Tracer("")
|
||||||
|
otel.SetTracerProvider(inst.traceProvider)
|
||||||
|
|
||||||
|
// add probe
|
||||||
|
inst.AddAlwaysHealthzers(inst)
|
||||||
|
|
||||||
|
return inst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger returns server logger
|
||||||
|
func (s *Server) Logger() *zap.Logger {
|
||||||
|
return s.l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meter returns the implementation meter
|
||||||
|
func (s *Server) Meter() metric.Meter {
|
||||||
|
return s.meter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer returns the implementation tracer
|
||||||
|
func (s *Server) Tracer() trace.Tracer {
|
||||||
|
return s.tracer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns server config
|
||||||
|
func (s *Server) Config() *viper.Viper {
|
||||||
|
return s.c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context returns server context
|
||||||
|
func (s *Server) Context() context.Context {
|
||||||
|
return s.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelContext returns server's cancel context
|
||||||
|
func (s *Server) CancelContext() context.Context {
|
||||||
|
return s.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddService add a single service
|
||||||
|
func (s *Server) AddService(service Service) {
|
||||||
|
for _, value := range s.services {
|
||||||
|
if value == service {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.services = append(s.services, service)
|
||||||
|
s.AddAlwaysHealthzers(service)
|
||||||
|
s.AddCloser(service)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddServices adds multiple service
|
||||||
|
func (s *Server) AddServices(services ...Service) {
|
||||||
|
for _, service := range services {
|
||||||
|
s.AddService(service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCloser adds a closer to be called on shutdown
|
||||||
|
func (s *Server) AddCloser(closer interface{}) {
|
||||||
|
for _, value := range s.closers {
|
||||||
|
if value == closer {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch closer.(type) {
|
||||||
|
case interfaces.Closer,
|
||||||
|
interfaces.ErrorCloser,
|
||||||
|
interfaces.CloserWithContext,
|
||||||
|
interfaces.ErrorCloserWithContext,
|
||||||
|
interfaces.Shutdowner,
|
||||||
|
interfaces.ErrorShutdowner,
|
||||||
|
interfaces.ShutdownerWithContext,
|
||||||
|
interfaces.ErrorShutdownerWithContext,
|
||||||
|
interfaces.Stopper,
|
||||||
|
interfaces.ErrorStopper,
|
||||||
|
interfaces.StopperWithContext,
|
||||||
|
interfaces.ErrorStopperWithContext,
|
||||||
|
interfaces.Unsubscriber,
|
||||||
|
interfaces.ErrorUnsubscriber,
|
||||||
|
interfaces.UnsubscriberWithContext,
|
||||||
|
interfaces.ErrorUnsubscriberWithContext:
|
||||||
|
s.closers = append(s.closers, closer)
|
||||||
|
default:
|
||||||
|
s.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddClosers adds the given closers to be called on shutdown
|
||||||
|
func (s *Server) AddClosers(closers ...interface{}) {
|
||||||
|
for _, closer := range closers {
|
||||||
|
s.AddCloser(closer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHealthzer adds a probe to be called on healthz checks
|
||||||
|
func (s *Server) AddHealthzer(typ healthz.Type, probe interface{}) {
|
||||||
|
switch probe.(type) {
|
||||||
|
case healthz.BoolHealthzer,
|
||||||
|
healthz.BoolHealthzerWithContext,
|
||||||
|
healthz.ErrorHealthzer,
|
||||||
|
healthz.ErrorHealthzWithContext,
|
||||||
|
interfaces.ErrorPinger,
|
||||||
|
interfaces.ErrorPingerWithContext:
|
||||||
|
s.probes[typ] = append(s.probes[typ], probe)
|
||||||
|
default:
|
||||||
|
s.l.Debug("not a healthz probe", log.FValue(fmt.Sprintf("%T", probe)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHealthzers adds the given probes to be called on healthz checks
|
||||||
|
func (s *Server) AddHealthzers(typ healthz.Type, probes ...interface{}) {
|
||||||
|
for _, probe := range probes {
|
||||||
|
s.AddHealthzer(typ, probe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAlwaysHealthzers adds the probes to be called on any healthz checks
|
||||||
|
func (s *Server) AddAlwaysHealthzers(probes ...interface{}) {
|
||||||
|
s.AddHealthzers(healthz.TypeAlways, probes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddStartupHealthzers adds the startup probes to be called on healthz checks
|
||||||
|
func (s *Server) AddStartupHealthzers(probes ...interface{}) {
|
||||||
|
s.AddHealthzers(healthz.TypeStartup, probes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLivenessHealthzers adds the liveness probes to be called on healthz checks
|
||||||
|
func (s *Server) AddLivenessHealthzers(probes ...interface{}) {
|
||||||
|
s.AddHealthzers(healthz.TypeLiveness, probes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddReadinessHealthzers adds the readiness probes to be called on healthz checks
|
||||||
|
func (s *Server) AddReadinessHealthzers(probes ...interface{}) {
|
||||||
|
s.AddHealthzers(healthz.TypeReadiness, probes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCanceled returns true if the internal errgroup has been canceled
|
||||||
|
func (s *Server) IsCanceled() bool {
|
||||||
|
return errors.Is(s.gCtx.Err(), context.Canceled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Healthz returns true if the server is running
|
||||||
|
func (s *Server) Healthz() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs the server
|
||||||
|
func (s *Server) Run() {
|
||||||
|
// add init services to closers
|
||||||
|
for _, initService := range s.initServices {
|
||||||
|
s.AddClosers(initService)
|
||||||
|
}
|
||||||
|
|
||||||
|
md := &MD{}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rows [][]string
|
||||||
|
for _, key := range s.Config().AllKeys() {
|
||||||
|
rows = append(rows, []string{
|
||||||
|
code(key),
|
||||||
|
code(s.Config().GetString(key)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(rows) > 0 {
|
||||||
|
md.Println("## Config")
|
||||||
|
md.Println("")
|
||||||
|
md.Println("List of all registered config variabled with their defaults.")
|
||||||
|
md.Println("")
|
||||||
|
md.Table([]string{"Key", "Default"}, rows)
|
||||||
|
md.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rows [][]string
|
||||||
|
for _, value := range s.initServices {
|
||||||
|
if v, ok := value.(*service.HTTP); ok {
|
||||||
|
t := reflect.TypeOf(v)
|
||||||
|
rows = append(rows, []string{
|
||||||
|
code(v.Name()),
|
||||||
|
code(t.String()),
|
||||||
|
stringer(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(rows) > 0 {
|
||||||
|
md.Println("## Init Services")
|
||||||
|
md.Println("")
|
||||||
|
md.Println("List of all registerd init services that are being immediately started.")
|
||||||
|
md.Println("")
|
||||||
|
md.Table([]string{"Name", "Type", "Address"}, rows)
|
||||||
|
md.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rows [][]string
|
||||||
|
for _, value := range s.services {
|
||||||
|
if v, ok := value.(*service.HTTP); ok {
|
||||||
|
t := reflect.TypeOf(v)
|
||||||
|
rows = append(rows, []string{
|
||||||
|
code(v.Name()),
|
||||||
|
code(t.String()),
|
||||||
|
stringer(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(rows) > 0 {
|
||||||
|
md.Println("## Services")
|
||||||
|
md.Println("")
|
||||||
|
md.Println("List of all registered services that are being started.")
|
||||||
|
md.Println("")
|
||||||
|
md.Table([]string{"Name", "Type", "Description"}, rows)
|
||||||
|
md.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rows [][]string
|
||||||
|
for k, probes := range s.probes {
|
||||||
|
for _, probe := range probes {
|
||||||
|
t := reflect.TypeOf(probe)
|
||||||
|
rows = append(rows, []string{
|
||||||
|
code(k.String()),
|
||||||
|
code(t.String()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(rows) > 0 {
|
||||||
|
md.Println("## Health probes")
|
||||||
|
md.Println("")
|
||||||
|
md.Println("List of all registered healthz probes that are being called during startup and runntime.")
|
||||||
|
md.Println("")
|
||||||
|
md.Table([]string{"Name", "Type"}, rows)
|
||||||
|
md.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rows [][]string
|
||||||
|
for _, value := range s.closers {
|
||||||
|
t := reflect.TypeOf(value)
|
||||||
|
var closer string
|
||||||
|
switch value.(type) {
|
||||||
|
case interfaces.Closer:
|
||||||
|
closer = "Closer"
|
||||||
|
case interfaces.ErrorCloser:
|
||||||
|
closer = "ErrorCloser"
|
||||||
|
case interfaces.CloserWithContext:
|
||||||
|
closer = "CloserWithContext"
|
||||||
|
case interfaces.ErrorCloserWithContext:
|
||||||
|
closer = "ErrorCloserWithContext"
|
||||||
|
case interfaces.Shutdowner:
|
||||||
|
closer = "Shutdowner"
|
||||||
|
case interfaces.ErrorShutdowner:
|
||||||
|
closer = "ErrorShutdowner"
|
||||||
|
case interfaces.ShutdownerWithContext:
|
||||||
|
closer = "ShutdownerWithContext"
|
||||||
|
case interfaces.ErrorShutdownerWithContext:
|
||||||
|
closer = "ErrorShutdownerWithContext"
|
||||||
|
case interfaces.Stopper:
|
||||||
|
closer = "Stopper"
|
||||||
|
case interfaces.ErrorStopper:
|
||||||
|
closer = "ErrorStopper"
|
||||||
|
case interfaces.StopperWithContext:
|
||||||
|
closer = "StopperWithContext"
|
||||||
|
case interfaces.ErrorStopperWithContext:
|
||||||
|
closer = "ErrorStopperWithContext"
|
||||||
|
case interfaces.Unsubscriber:
|
||||||
|
closer = "Unsubscriber"
|
||||||
|
case interfaces.ErrorUnsubscriber:
|
||||||
|
closer = "ErrorUnsubscriber"
|
||||||
|
case interfaces.UnsubscriberWithContext:
|
||||||
|
closer = "UnsubscriberWithContext"
|
||||||
|
case interfaces.ErrorUnsubscriberWithContext:
|
||||||
|
closer = "ErrorUnsubscriberWithContext"
|
||||||
|
}
|
||||||
|
rows = append(rows, []string{
|
||||||
|
code(t.String()),
|
||||||
|
code(closer),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(rows) > 0 {
|
||||||
|
md.Println("## Closers")
|
||||||
|
md.Println("")
|
||||||
|
md.Println("List of all registered closers that are being called during graceful shutdown.")
|
||||||
|
md.Println("")
|
||||||
|
md.Table([]string{"Name", "Type"}, rows)
|
||||||
|
md.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var rows [][]string
|
||||||
|
s.meter.AsyncFloat64()
|
||||||
|
|
||||||
|
var names []string
|
||||||
|
values := map[string]nonrecording.Metric{}
|
||||||
|
for _, value := range nonrecording.Metrics() {
|
||||||
|
names = append(names, value.Name)
|
||||||
|
values[value.Name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
gatherer, _ := prometheus.DefaultRegisterer.(*prometheus.Registry).Gather()
|
||||||
|
for _, value := range gatherer {
|
||||||
|
names = append(names, value.GetName())
|
||||||
|
values[value.GetName()] = nonrecording.Metric{
|
||||||
|
Name: value.GetName(),
|
||||||
|
Type: value.GetType().String(),
|
||||||
|
Help: value.GetHelp(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
for _, name := range names {
|
||||||
|
value := values[name]
|
||||||
|
rows = append(rows, []string{
|
||||||
|
code(value.Name),
|
||||||
|
value.Type,
|
||||||
|
value.Help,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(rows) > 0 {
|
||||||
|
md.Println("## Metrics")
|
||||||
|
md.Println("")
|
||||||
|
md.Println("List of all registered metrics than are being exposed.")
|
||||||
|
md.Println("")
|
||||||
|
md.Table([]string{"Name", "Type", "Description"}, rows)
|
||||||
|
md.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(md.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
type MD struct {
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MD) Println(a ...any) {
|
||||||
|
s.value += fmt.Sprintln(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MD) Print(a ...any) {
|
||||||
|
s.value += fmt.Sprint(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MD) String() string {
|
||||||
|
return s.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MD) Table(headers []string, rows [][]string) {
|
||||||
|
table, err := markdowntable.NewTableFormatterBuilder().
|
||||||
|
WithPrettyPrint().
|
||||||
|
Build(headers...).
|
||||||
|
Format(rows)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
s.Print(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
func code(v string) string {
|
||||||
|
if v == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "`" + v + "`"
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringer(v any) string {
|
||||||
|
if i, ok := v.(fmt.Stringer); ok {
|
||||||
|
return i.String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -74,7 +75,7 @@ func (s *KeelTestSuite) TearDownSuite() {}
|
|||||||
|
|
||||||
func (s *KeelTestSuite) TestServiceHTTP() {
|
func (s *KeelTestSuite) TestServiceHTTP() {
|
||||||
s.svr.AddServices(
|
s.svr.AddServices(
|
||||||
keel.NewServiceHTTP(s.l, "test", ":55000", s.mux),
|
service.NewHTTP(s.l, "test", ":55000", s.mux),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.runServer()
|
s.runServer()
|
||||||
@ -86,8 +87,8 @@ func (s *KeelTestSuite) TestServiceHTTP() {
|
|||||||
|
|
||||||
func (s *KeelTestSuite) TestServiceHTTPZap() {
|
func (s *KeelTestSuite) TestServiceHTTPZap() {
|
||||||
s.svr.AddServices(
|
s.svr.AddServices(
|
||||||
keel.NewServiceHTTPZap(s.l, "zap", ":9100", "/log"),
|
service.NewHTTPZap(s.l, "zap", ":9100", "/log"),
|
||||||
keel.NewServiceHTTP(s.l, "test", ":55000", s.mux),
|
service.NewHTTP(s.l, "test", ":55000", s.mux),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.runServer()
|
s.runServer()
|
||||||
@ -141,7 +142,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() {
|
|||||||
|
|
||||||
func (s *KeelTestSuite) TestGraceful() {
|
func (s *KeelTestSuite) TestGraceful() {
|
||||||
s.svr.AddServices(
|
s.svr.AddServices(
|
||||||
keel.NewServiceHTTP(s.l, "test", ":55000", s.mux),
|
service.NewHTTP(s.l, "test", ":55000", s.mux),
|
||||||
)
|
)
|
||||||
|
|
||||||
s.runServer()
|
s.runServer()
|
||||||
|
|||||||
10
service/errors.go
Normal file
10
service/errors.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrServiceNotRunning = errors.New("service not running")
|
||||||
|
ErrServiceShutdown = errors.New("service shutdown")
|
||||||
|
)
|
||||||
94
service/goroutine.go
Normal file
94
service/goroutine.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GoRoutine struct
|
||||||
|
type (
|
||||||
|
GoRoutine struct {
|
||||||
|
running atomic.Bool
|
||||||
|
handler GoRoutineFn
|
||||||
|
cancel context.CancelCauseFunc
|
||||||
|
parallel int
|
||||||
|
name string
|
||||||
|
wg errgroup.Group
|
||||||
|
l *zap.Logger
|
||||||
|
}
|
||||||
|
GoRoutineOption func(*GoRoutine)
|
||||||
|
GoRoutineFn func(ctx context.Context, l *zap.Logger) error
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewGoRoutine(l *zap.Logger, name string, handler GoRoutineFn) *GoRoutine {
|
||||||
|
if l == nil {
|
||||||
|
l = log.Logger()
|
||||||
|
}
|
||||||
|
// enrich the log
|
||||||
|
l = log.WithAttributes(l,
|
||||||
|
log.KeelServiceTypeKey.String("goroutine"),
|
||||||
|
log.KeelServiceNameKey.String(name),
|
||||||
|
)
|
||||||
|
|
||||||
|
return &GoRoutine{
|
||||||
|
handler: handler,
|
||||||
|
name: name,
|
||||||
|
parallel: 1,
|
||||||
|
l: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// ~ Options
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func GoRoutineWithPralllel(v int) GoRoutineOption {
|
||||||
|
return func(o *GoRoutine) {
|
||||||
|
o.parallel = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// ~ Public methods
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func (s *GoRoutine) Name() string {
|
||||||
|
return s.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoRoutine) Healthz() error {
|
||||||
|
if !s.running.Load() {
|
||||||
|
return ErrServiceNotRunning
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoRoutine) String() string {
|
||||||
|
return fmt.Sprintf("parallel: `%d`", s.parallel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoRoutine) Start(ctx context.Context) error {
|
||||||
|
s.l.Info("starting keel service")
|
||||||
|
ctx, cancel := context.WithCancelCause(ctx)
|
||||||
|
s.cancel = cancel
|
||||||
|
for i := 0; i < s.parallel; i++ {
|
||||||
|
i := i
|
||||||
|
l := log.WithAttributes(s.l, log.KeelServiceInstKey.Int(i))
|
||||||
|
s.wg.Go(func() error {
|
||||||
|
return s.handler(ctx, l)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return s.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GoRoutine) Close(ctx context.Context) error {
|
||||||
|
s.l.Info("stopping keel service")
|
||||||
|
s.cancel(ErrServiceShutdown)
|
||||||
|
return s.wg.Wait()
|
||||||
|
}
|
||||||
47
service/goroutine_test.go
Normal file
47
service/goroutine_test.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package service_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNewGoRoutine() {
|
||||||
|
shutdown(3 * time.Second)
|
||||||
|
|
||||||
|
svr := keel.NewServer(
|
||||||
|
keel.WithLogger(zap.NewExample()),
|
||||||
|
)
|
||||||
|
|
||||||
|
svr.AddService(
|
||||||
|
service.NewGoRoutine(svr.Logger(), "demo", func(ctx context.Context, l *zap.Logger) error {
|
||||||
|
for {
|
||||||
|
if err := ctx.Err(); errors.Is(context.Cause(ctx), service.ErrServiceShutdown) {
|
||||||
|
l.Info("context has been canceled du to graceful shutdow")
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return errors.Wrap(err, "unexpected context error")
|
||||||
|
}
|
||||||
|
l.Info("ping")
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
svr.Run()
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// {"level":"info","msg":"starting keel server"}
|
||||||
|
// {"level":"info","msg":"starting keel service","keel_service_type":"goroutine","keel_service_name":"demo"}
|
||||||
|
// {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
|
||||||
|
// {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
|
||||||
|
// {"level":"info","msg":"ping","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
|
||||||
|
// {"level":"debug","msg":"keel graceful shutdown"}
|
||||||
|
// {"level":"info","msg":"stopping keel service","keel_service_type":"goroutine","keel_service_name":"demo"}
|
||||||
|
// {"level":"info","msg":"context has been canceled du to graceful shutdow","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0}
|
||||||
|
// {"level":"info","msg":"keel server stopped"}
|
||||||
|
}
|
||||||
14
service/helper_test.go
Normal file
14
service/helper_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package service_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// shutdown example after the given time
|
||||||
|
func shutdown(duration time.Duration) {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(duration)
|
||||||
|
_ = syscall.Kill(syscall.Getpid(), syscall.SIGINT)
|
||||||
|
}()
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
package keel
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@ -14,22 +15,25 @@ import (
|
|||||||
"github.com/foomo/keel/net/http/middleware"
|
"github.com/foomo/keel/net/http/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceHTTP struct
|
// HTTP struct
|
||||||
type ServiceHTTP struct {
|
type HTTP struct {
|
||||||
running atomic.Bool
|
running atomic.Bool
|
||||||
server *http.Server
|
server *http.Server
|
||||||
name string
|
name string
|
||||||
l *zap.Logger
|
l *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceHTTP(l *zap.Logger, name, addr string, handler http.Handler, middlewares ...middleware.Middleware) *ServiceHTTP {
|
func NewHTTP(l *zap.Logger, name, addr string, handler http.Handler, middlewares ...middleware.Middleware) *HTTP {
|
||||||
if l == nil {
|
if l == nil {
|
||||||
l = log.Logger()
|
l = log.Logger()
|
||||||
}
|
}
|
||||||
// enrich the log
|
// enrich the log
|
||||||
l = log.WithHTTPServerName(l, name)
|
l = log.WithAttributes(l,
|
||||||
|
log.KeelServiceTypeKey.String("http"),
|
||||||
|
log.KeelServiceNameKey.String(name),
|
||||||
|
)
|
||||||
|
|
||||||
return &ServiceHTTP{
|
return &HTTP{
|
||||||
server: &http.Server{
|
server: &http.Server{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
ErrorLog: zap.NewStdLog(l),
|
ErrorLog: zap.NewStdLog(l),
|
||||||
@ -40,18 +44,22 @@ func NewServiceHTTP(l *zap.Logger, name, addr string, handler http.Handler, midd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceHTTP) Name() string {
|
func (s *HTTP) Name() string {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceHTTP) Healthz() error {
|
func (s *HTTP) Healthz() error {
|
||||||
if !s.running.Load() {
|
if !s.running.Load() {
|
||||||
return ErrServiceNotRunning
|
return ErrServiceNotRunning
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceHTTP) Start(ctx context.Context) error {
|
func (s *HTTP) String() string {
|
||||||
|
return fmt.Sprintf("address: `%s`", s.server.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HTTP) Start(ctx context.Context) error {
|
||||||
var fields []zap.Field
|
var fields []zap.Field
|
||||||
if value := strings.Split(s.server.Addr, ":"); len(value) == 2 {
|
if value := strings.Split(s.server.Addr, ":"); len(value) == 2 {
|
||||||
ip, port := value[0], value[1]
|
ip, port := value[0], value[1]
|
||||||
@ -60,20 +68,24 @@ func (s *ServiceHTTP) Start(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
fields = append(fields, log.FNetHostIP(ip), log.FNetHostPort(port))
|
fields = append(fields, log.FNetHostIP(ip), log.FNetHostPort(port))
|
||||||
}
|
}
|
||||||
s.l.Info("starting http service", fields...)
|
s.l.Info("starting keel service", fields...)
|
||||||
s.server.BaseContext = func(_ net.Listener) context.Context { return ctx }
|
s.server.BaseContext = func(_ net.Listener) context.Context { return ctx }
|
||||||
s.server.RegisterOnShutdown(func() {
|
s.server.RegisterOnShutdown(func() {
|
||||||
s.running.Store(false)
|
s.running.Store(false)
|
||||||
})
|
})
|
||||||
s.running.Store(true)
|
s.running.Store(true)
|
||||||
if err := s.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
if err := s.server.ListenAndServe(); errors.Is(err, http.ErrServerClosed) {
|
||||||
log.WithError(s.l, err).Error("service error")
|
return nil
|
||||||
return err
|
} else if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to start service")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceHTTP) Close(ctx context.Context) error {
|
func (s *HTTP) Close(ctx context.Context) error {
|
||||||
s.l.Info("stopping http service")
|
s.l.Info("stopping keel service")
|
||||||
return s.server.Shutdown(ctx)
|
if err := s.server.Shutdown(ctx); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to stop service")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
39
service/http_test.go
Normal file
39
service/http_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package service_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/keel"
|
||||||
|
"github.com/foomo/keel/service"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNewHTTP() {
|
||||||
|
shutdown(3 * time.Second)
|
||||||
|
|
||||||
|
svr := keel.NewServer(
|
||||||
|
keel.WithLogger(zap.NewExample()),
|
||||||
|
)
|
||||||
|
|
||||||
|
l := svr.Logger()
|
||||||
|
// create demo service
|
||||||
|
svs := http.NewServeMux()
|
||||||
|
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write([]byte("OK"))
|
||||||
|
})
|
||||||
|
|
||||||
|
svr.AddService(
|
||||||
|
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||||
|
)
|
||||||
|
|
||||||
|
svr.Run()
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// {"level":"info","msg":"starting keel server"}
|
||||||
|
// {"level":"info","msg":"starting keel service","keel_service_type":"http","keel_service_name":"demo","net_host_ip":"localhost","net_host_port":"8080"}
|
||||||
|
// {"level":"debug","msg":"keel graceful shutdown"}
|
||||||
|
// {"level":"info","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"demo"}
|
||||||
|
// {"level":"info","msg":"keel server stopped"}
|
||||||
|
}
|
||||||
@ -1,19 +1,21 @@
|
|||||||
package keel
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/healthz"
|
||||||
|
"github.com/foomo/keel/interfaces"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/foomo/keel/log"
|
"github.com/foomo/keel/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultServiceHTTPHealthzName = "healthz"
|
DefaultHTTPHealthzName = "healthz"
|
||||||
DefaultServiceHTTPHealthzAddr = ":9400"
|
DefaultHTTPHealthzAddr = ":9400"
|
||||||
DefaultServiceHTTPHealthzPath = "/healthz"
|
DefaultHTTPHealthzPath = "/healthz"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -24,7 +26,7 @@ var (
|
|||||||
ErrStartupProbeFailed = errors.New("startup probe failed")
|
ErrStartupProbeFailed = errors.New("startup probe failed")
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[HealthzType][]interface{}) *ServiceHTTP {
|
func NewHealthz(l *zap.Logger, name, addr, path string, probes map[healthz.Type][]interface{}) *HTTP {
|
||||||
handler := http.NewServeMux()
|
handler := http.NewServeMux()
|
||||||
|
|
||||||
unavailable := func(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) {
|
unavailable := func(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) {
|
||||||
@ -36,17 +38,17 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
|||||||
|
|
||||||
call := func(ctx context.Context, probe interface{}) (bool, error) {
|
call := func(ctx context.Context, probe interface{}) (bool, error) {
|
||||||
switch h := probe.(type) {
|
switch h := probe.(type) {
|
||||||
case BoolHealthzer:
|
case healthz.BoolHealthzer:
|
||||||
return h.Healthz(), nil
|
return h.Healthz(), nil
|
||||||
case BoolHealthzerWithContext:
|
case healthz.BoolHealthzerWithContext:
|
||||||
return h.Healthz(ctx), nil
|
return h.Healthz(ctx), nil
|
||||||
case ErrorHealthzer:
|
case healthz.ErrorHealthzer:
|
||||||
return true, h.Healthz()
|
return true, h.Healthz()
|
||||||
case ErrorHealthzWithContext:
|
case healthz.ErrorHealthzWithContext:
|
||||||
return true, h.Healthz(ctx)
|
return true, h.Healthz(ctx)
|
||||||
case ErrorPinger:
|
case interfaces.ErrorPinger:
|
||||||
return true, h.Ping()
|
return true, h.Ping()
|
||||||
case ErrorPingerWithContext:
|
case interfaces.ErrorPingerWithContext:
|
||||||
return true, h.Ping(ctx)
|
return true, h.Ping(ctx)
|
||||||
default:
|
default:
|
||||||
return false, ErrUnhandledHealthzProbe
|
return false, ErrUnhandledHealthzProbe
|
||||||
@ -55,7 +57,7 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
|||||||
|
|
||||||
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||||
for typ, values := range probes {
|
for typ, values := range probes {
|
||||||
if typ == HealthzTypeStartup {
|
if typ == healthz.TypeStartup {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, p := range values {
|
for _, p := range values {
|
||||||
@ -72,12 +74,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
|||||||
_, _ = w.Write([]byte("OK"))
|
_, _ = w.Write([]byte("OK"))
|
||||||
})
|
})
|
||||||
|
|
||||||
handler.HandleFunc(path+"/"+HealthzTypeLiveness.String(), func(w http.ResponseWriter, r *http.Request) {
|
handler.HandleFunc(path+"/"+healthz.TypeLiveness.String(), func(w http.ResponseWriter, r *http.Request) {
|
||||||
var ps []interface{}
|
var ps []interface{}
|
||||||
if p, ok := probes[HealthzTypeAlways]; ok {
|
if p, ok := probes[healthz.TypeAlways]; ok {
|
||||||
ps = append(ps, p...)
|
ps = append(ps, p...)
|
||||||
}
|
}
|
||||||
if p, ok := probes[HealthzTypeLiveness]; ok {
|
if p, ok := probes[healthz.TypeLiveness]; ok {
|
||||||
ps = append(ps, p...)
|
ps = append(ps, p...)
|
||||||
}
|
}
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
@ -93,12 +95,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
|||||||
_, _ = w.Write([]byte("OK"))
|
_, _ = w.Write([]byte("OK"))
|
||||||
})
|
})
|
||||||
|
|
||||||
handler.HandleFunc(path+"/"+HealthzTypeReadiness.String(), func(w http.ResponseWriter, r *http.Request) {
|
handler.HandleFunc(path+"/"+healthz.TypeReadiness.String(), func(w http.ResponseWriter, r *http.Request) {
|
||||||
var ps []interface{}
|
var ps []interface{}
|
||||||
if p, ok := probes[HealthzTypeAlways]; ok {
|
if p, ok := probes[healthz.TypeAlways]; ok {
|
||||||
ps = append(ps, p...)
|
ps = append(ps, p...)
|
||||||
}
|
}
|
||||||
if p, ok := probes[HealthzTypeReadiness]; ok {
|
if p, ok := probes[healthz.TypeReadiness]; ok {
|
||||||
ps = append(ps, p...)
|
ps = append(ps, p...)
|
||||||
}
|
}
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
@ -114,12 +116,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
|||||||
_, _ = w.Write([]byte("OK"))
|
_, _ = w.Write([]byte("OK"))
|
||||||
})
|
})
|
||||||
|
|
||||||
handler.HandleFunc(path+"/"+HealthzTypeStartup.String(), func(w http.ResponseWriter, r *http.Request) {
|
handler.HandleFunc(path+"/"+healthz.TypeStartup.String(), func(w http.ResponseWriter, r *http.Request) {
|
||||||
var ps []interface{}
|
var ps []interface{}
|
||||||
if p, ok := probes[HealthzTypeAlways]; ok {
|
if p, ok := probes[healthz.TypeAlways]; ok {
|
||||||
ps = append(ps, p...)
|
ps = append(ps, p...)
|
||||||
}
|
}
|
||||||
if p, ok := probes[HealthzTypeStartup]; ok {
|
if p, ok := probes[healthz.TypeStartup]; ok {
|
||||||
ps = append(ps, p...)
|
ps = append(ps, p...)
|
||||||
}
|
}
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
@ -134,15 +136,15 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = w.Write([]byte("OK"))
|
_, _ = w.Write([]byte("OK"))
|
||||||
})
|
})
|
||||||
return NewServiceHTTP(l, name, addr, handler)
|
return NewHTTP(l, name, addr, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultServiceHTTPProbes(probes map[HealthzType][]interface{}) *ServiceHTTP {
|
func NewDefaultHTTPProbes(probes map[healthz.Type][]interface{}) *HTTP {
|
||||||
return NewServiceHTTPHealthz(
|
return NewHealthz(
|
||||||
log.Logger(),
|
log.Logger(),
|
||||||
DefaultServiceHTTPHealthzName,
|
DefaultHTTPHealthzName,
|
||||||
DefaultServiceHTTPHealthzAddr,
|
DefaultHTTPHealthzAddr,
|
||||||
DefaultServiceHTTPHealthzPath,
|
DefaultHTTPHealthzPath,
|
||||||
probes,
|
probes,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
//go:build !pprof
|
//go:build !pprof
|
||||||
|
|
||||||
package keel
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -10,12 +10,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultServiceHTTPPProfName = "pprof"
|
DefaultHTTPPProfName = "pprof"
|
||||||
DefaultServiceHTTPPProfAddr = "localhost:6060"
|
DefaultHTTPPProfAddr = "localhost:6060"
|
||||||
DefaultServiceHTTPPProfPath = "/debug/pprof"
|
DefaultHTTPPProfPath = "/debug/pprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServiceHTTPPProf(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
func NewHTTPPProf(l *zap.Logger, name, addr, path string) *HTTP {
|
||||||
route := func(w http.ResponseWriter, r *http.Request) {
|
route := func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusNotImplemented)
|
w.WriteHeader(http.StatusNotImplemented)
|
||||||
_, _ = w.Write([]byte("To enable pprof, you need to build your binary with the `-tags=pprof` flag"))
|
_, _ = w.Write([]byte("To enable pprof, you need to build your binary with the `-tags=pprof` flag"))
|
||||||
@ -26,14 +26,14 @@ func NewServiceHTTPPProf(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
|||||||
handler.HandleFunc(path+"/profile", route)
|
handler.HandleFunc(path+"/profile", route)
|
||||||
handler.HandleFunc(path+"/symbol", route)
|
handler.HandleFunc(path+"/symbol", route)
|
||||||
handler.HandleFunc(path+"/trace", route)
|
handler.HandleFunc(path+"/trace", route)
|
||||||
return NewServiceHTTP(l, name, addr, handler)
|
return NewHTTP(l, name, addr, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultServiceHTTPPProf() *ServiceHTTP {
|
func NewDefaultHTTPPProf() *HTTP {
|
||||||
return NewServiceHTTPPProf(
|
return NewHTTPPProf(
|
||||||
log.Logger(),
|
log.Logger(),
|
||||||
DefaultServiceHTTPPProfName,
|
DefaultHTTPPProfName,
|
||||||
DefaultServiceHTTPPProfAddr,
|
DefaultHTTPPProfAddr,
|
||||||
DefaultServiceHTTPPProfPath,
|
DefaultHTTPPProfPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
//go:build pprof
|
//go:build pprof
|
||||||
// +build pprof
|
// +build pprof
|
||||||
|
|
||||||
package keel
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -12,12 +12,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultServiceHTTPPProfName = "pprof"
|
DefaultHTTPPProfName = "pprof"
|
||||||
DefaultServiceHTTPPProfAddr = "localhost:6060"
|
DefaultHTTPPProfAddr = "localhost:6060"
|
||||||
DefaultServiceHTTPPProfPath = "/debug/pprof"
|
DefaultHTTPPProfPath = "/debug/pprof"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServiceHTTPPProf(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
func NewHTTPPProf(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
||||||
handler := http.NewServeMux()
|
handler := http.NewServeMux()
|
||||||
handler.HandleFunc(path+"/", pprof.Index)
|
handler.HandleFunc(path+"/", pprof.Index)
|
||||||
handler.HandleFunc(path+"/cmdline", pprof.Cmdline)
|
handler.HandleFunc(path+"/cmdline", pprof.Cmdline)
|
||||||
@ -27,11 +27,11 @@ func NewServiceHTTPPProf(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
|||||||
return NewServiceHTTP(l, name, addr, handler)
|
return NewServiceHTTP(l, name, addr, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultServiceHTTPPProf() *ServiceHTTP {
|
func NewDefaultHTTPPProf() *ServiceHTTP {
|
||||||
return NewServiceHTTPPProf(
|
return NewHTTPPProf(
|
||||||
log.Logger(),
|
log.Logger(),
|
||||||
DefaultServiceHTTPPProfName,
|
DefaultHTTPPProfName,
|
||||||
DefaultServiceHTTPPProfAddr,
|
DefaultHTTPPProfAddr,
|
||||||
DefaultServiceHTTPPProfPath,
|
DefaultHTTPPProfPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
37
service/httpprometheus.go
Normal file
37
service/httpprometheus.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/foomo/keel/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultHTTPPrometheusName = "prometheus"
|
||||||
|
DefaultHTTPPrometheusAddr = ":9200"
|
||||||
|
DefaultHTTPPrometheusPath = "/metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewHTTPPrometheus(l *zap.Logger, name, addr, path string) *HTTP {
|
||||||
|
handler := http.NewServeMux()
|
||||||
|
handler.Handle(path, promhttp.HandlerFor(
|
||||||
|
prometheus.DefaultGatherer,
|
||||||
|
promhttp.HandlerOpts{
|
||||||
|
EnableOpenMetrics: true,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
return NewHTTP(l, name, addr, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultHTTPPrometheus() *HTTP {
|
||||||
|
return NewHTTPPrometheus(
|
||||||
|
log.Logger(),
|
||||||
|
DefaultHTTPPrometheusName,
|
||||||
|
DefaultHTTPPrometheusAddr,
|
||||||
|
DefaultHTTPPrometheusPath,
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -12,12 +12,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultServiceHTTPViperName = "viper"
|
DefaultHTTPViperName = "viper"
|
||||||
DefaultServiceHTTPViperAddr = "localhost:9300"
|
DefaultHTTPViperAddr = "localhost:9300"
|
||||||
DefaultServiceHTTPViperPath = "/config"
|
DefaultHTTPViperPath = "/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServiceHTTPViper(l *zap.Logger, c *viper.Viper, name, addr, path string) *ServiceHTTP {
|
func NewHTTPViper(l *zap.Logger, c *viper.Viper, name, addr, path string) *HTTP {
|
||||||
handler := http.NewServeMux()
|
handler := http.NewServeMux()
|
||||||
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||||
type payload struct {
|
type payload struct {
|
||||||
@ -44,15 +44,15 @@ func NewServiceHTTPViper(l *zap.Logger, c *viper.Viper, name, addr, path string)
|
|||||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return NewServiceHTTP(l, name, addr, handler)
|
return NewHTTP(l, name, addr, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultServiceHTTPViper() *ServiceHTTP {
|
func NewDefaultHTTPViper() *HTTP {
|
||||||
return NewServiceHTTPViper(
|
return NewHTTPViper(
|
||||||
log.Logger(),
|
log.Logger(),
|
||||||
config.Config(),
|
config.Config(),
|
||||||
DefaultServiceHTTPViperName,
|
DefaultHTTPViperName,
|
||||||
DefaultServiceHTTPViperAddr,
|
DefaultHTTPViperAddr,
|
||||||
DefaultServiceHTTPViperPath,
|
DefaultHTTPViperPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package keel
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -12,12 +12,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultServiceHTTPZapName = "zap"
|
DefaultHTTPZapName = "zap"
|
||||||
DefaultServiceHTTPZapAddr = "localhost:9100"
|
DefaultHTTPZapAddr = "localhost:9100"
|
||||||
DefaultServiceHTTPZapPath = "/log"
|
DefaultHTTPZapPath = "/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewServiceHTTPZap(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
func NewHTTPZap(l *zap.Logger, name, addr, path string) *HTTP {
|
||||||
handler := http.NewServeMux()
|
handler := http.NewServeMux()
|
||||||
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||||
type errorResponse struct {
|
type errorResponse struct {
|
||||||
@ -91,14 +91,14 @@ func NewServiceHTTPZap(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return NewServiceHTTP(l, name, addr, handler)
|
return NewHTTP(l, name, addr, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultServiceHTTPZap() *ServiceHTTP {
|
func NewDefaultHTTPZap() *HTTP {
|
||||||
return NewServiceHTTPZap(
|
return NewHTTPZap(
|
||||||
log.Logger(),
|
log.Logger(),
|
||||||
DefaultServiceHTTPZapName,
|
DefaultHTTPZapName,
|
||||||
DefaultServiceHTTPZapAddr,
|
DefaultHTTPZapAddr,
|
||||||
DefaultServiceHTTPZapPath,
|
DefaultHTTPZapPath,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,37 +0,0 @@
|
|||||||
package keel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
|
|
||||||
"github.com/foomo/keel/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DefaultServiceHTTPPrometheusName = "prometheus"
|
|
||||||
DefaultServiceHTTPPrometheusAddr = ":9200"
|
|
||||||
DefaultServiceHTTPPrometheusPath = "/metrics"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewServiceHTTPPrometheus(l *zap.Logger, name, addr, path string) *ServiceHTTP {
|
|
||||||
handler := http.NewServeMux()
|
|
||||||
handler.Handle(path, promhttp.HandlerFor(
|
|
||||||
prometheus.DefaultGatherer,
|
|
||||||
promhttp.HandlerOpts{
|
|
||||||
EnableOpenMetrics: true,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
return NewServiceHTTP(l, name, addr, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultServiceHTTPPrometheus() *ServiceHTTP {
|
|
||||||
return NewServiceHTTPPrometheus(
|
|
||||||
log.Logger(),
|
|
||||||
DefaultServiceHTTPPrometheusName,
|
|
||||||
DefaultServiceHTTPPrometheusAddr,
|
|
||||||
DefaultServiceHTTPPrometheusPath,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
162
telemetry/nonrecording/instruments.go
Normal file
162
telemetry/nonrecording/instruments.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright The OpenTelemetry Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package nonrecording
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/asyncfloat64"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/asyncint64"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/syncint64"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Metric struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Help string
|
||||||
|
}
|
||||||
|
|
||||||
|
var metrics []Metric
|
||||||
|
|
||||||
|
func Metrics() []Metric {
|
||||||
|
return metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonrecordingAsyncFloat64Instrument struct {
|
||||||
|
instrument.Asynchronous
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ asyncfloat64.InstrumentProvider = nonrecordingAsyncFloat64Instrument{}
|
||||||
|
_ asyncfloat64.Counter = nonrecordingAsyncFloat64Instrument{}
|
||||||
|
_ asyncfloat64.UpDownCounter = nonrecordingAsyncFloat64Instrument{}
|
||||||
|
_ asyncfloat64.Gauge = nonrecordingAsyncFloat64Instrument{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n nonrecordingAsyncFloat64Instrument) Counter(name string, opts ...instrument.Option) (asyncfloat64.Counter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "COUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingAsyncFloat64Instrument) UpDownCounter(name string, opts ...instrument.Option) (asyncfloat64.UpDownCounter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "UPDOWNCOUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingAsyncFloat64Instrument) Gauge(name string, opts ...instrument.Option) (asyncfloat64.Gauge, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "GAUGE", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nonrecordingAsyncFloat64Instrument) Observe(context.Context, float64, ...attribute.KeyValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonrecordingAsyncInt64Instrument struct {
|
||||||
|
instrument.Asynchronous
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ asyncint64.InstrumentProvider = nonrecordingAsyncInt64Instrument{}
|
||||||
|
_ asyncint64.Counter = nonrecordingAsyncInt64Instrument{}
|
||||||
|
_ asyncint64.UpDownCounter = nonrecordingAsyncInt64Instrument{}
|
||||||
|
_ asyncint64.Gauge = nonrecordingAsyncInt64Instrument{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n nonrecordingAsyncInt64Instrument) Counter(name string, opts ...instrument.Option) (asyncint64.Counter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "COUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingAsyncInt64Instrument) UpDownCounter(name string, opts ...instrument.Option) (asyncint64.UpDownCounter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "UPDOWNCOUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingAsyncInt64Instrument) Gauge(name string, opts ...instrument.Option) (asyncint64.Gauge, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "GAUGE", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nonrecordingAsyncInt64Instrument) Observe(context.Context, int64, ...attribute.KeyValue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonrecordingSyncFloat64Instrument struct {
|
||||||
|
instrument.Synchronous
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ syncfloat64.InstrumentProvider = nonrecordingSyncFloat64Instrument{}
|
||||||
|
_ syncfloat64.Counter = nonrecordingSyncFloat64Instrument{}
|
||||||
|
_ syncfloat64.UpDownCounter = nonrecordingSyncFloat64Instrument{}
|
||||||
|
_ syncfloat64.Histogram = nonrecordingSyncFloat64Instrument{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n nonrecordingSyncFloat64Instrument) Counter(name string, opts ...instrument.Option) (syncfloat64.Counter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "COUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingSyncFloat64Instrument) UpDownCounter(name string, opts ...instrument.Option) (syncfloat64.UpDownCounter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "UPDOWNCOUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingSyncFloat64Instrument) Histogram(name string, opts ...instrument.Option) (syncfloat64.Histogram, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "HISTOGRAM", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nonrecordingSyncFloat64Instrument) Add(context.Context, float64, ...attribute.KeyValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nonrecordingSyncFloat64Instrument) Record(context.Context, float64, ...attribute.KeyValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type nonrecordingSyncInt64Instrument struct {
|
||||||
|
instrument.Synchronous
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ syncint64.InstrumentProvider = nonrecordingSyncInt64Instrument{}
|
||||||
|
_ syncint64.Counter = nonrecordingSyncInt64Instrument{}
|
||||||
|
_ syncint64.UpDownCounter = nonrecordingSyncInt64Instrument{}
|
||||||
|
_ syncint64.Histogram = nonrecordingSyncInt64Instrument{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n nonrecordingSyncInt64Instrument) Counter(name string, opts ...instrument.Option) (syncint64.Counter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "COUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingSyncInt64Instrument) UpDownCounter(name string, opts ...instrument.Option) (syncint64.UpDownCounter, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "UPDOWNCOUNTER", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nonrecordingSyncInt64Instrument) Histogram(name string, opts ...instrument.Option) (syncint64.Histogram, error) {
|
||||||
|
metrics = append(metrics, Metric{Name: strings.ReplaceAll(name, ".", "_"), Type: "HISTOGRAM", Help: instrument.NewConfig(opts...).Description()})
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nonrecordingSyncInt64Instrument) Add(context.Context, int64, ...attribute.KeyValue) {
|
||||||
|
}
|
||||||
|
func (nonrecordingSyncInt64Instrument) Record(context.Context, int64, ...attribute.KeyValue) {
|
||||||
|
}
|
||||||
50
telemetry/nonrecording/meter.go
Normal file
50
telemetry/nonrecording/meter.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package nonrecording
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/asyncfloat64"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/asyncint64"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
|
||||||
|
"go.opentelemetry.io/otel/metric/instrument/syncint64"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewNoopMeterProvider creates a MeterProvider that does not record any metrics.
|
||||||
|
func NewNoopMeterProvider() metric.MeterProvider {
|
||||||
|
return noopMeterProvider{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopMeterProvider struct{}
|
||||||
|
|
||||||
|
var _ metric.MeterProvider = noopMeterProvider{}
|
||||||
|
|
||||||
|
func (noopMeterProvider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter {
|
||||||
|
return noopMeter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNoopMeter creates a Meter that does not record any metrics.
|
||||||
|
func NewNoopMeter() metric.Meter {
|
||||||
|
return noopMeter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noopMeter struct{}
|
||||||
|
|
||||||
|
var _ metric.Meter = noopMeter{}
|
||||||
|
|
||||||
|
func (noopMeter) AsyncInt64() asyncint64.InstrumentProvider {
|
||||||
|
return nonrecordingAsyncInt64Instrument{}
|
||||||
|
}
|
||||||
|
func (noopMeter) AsyncFloat64() asyncfloat64.InstrumentProvider {
|
||||||
|
return nonrecordingAsyncFloat64Instrument{}
|
||||||
|
}
|
||||||
|
func (noopMeter) SyncInt64() syncint64.InstrumentProvider {
|
||||||
|
return nonrecordingSyncInt64Instrument{}
|
||||||
|
}
|
||||||
|
func (noopMeter) SyncFloat64() syncfloat64.InstrumentProvider {
|
||||||
|
return nonrecordingSyncFloat64Instrument{}
|
||||||
|
}
|
||||||
|
func (noopMeter) RegisterCallback([]instrument.Asynchronous, func(context.Context)) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user