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"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -39,7 +40,7 @@ func main() {
|
||||
svs := newService()
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", ":8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -5,6 +5,5 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrServerNotRunning = errors.New("server not running")
|
||||
ErrServiceNotRunning = errors.New("service not running")
|
||||
ErrServerNotRunning = errors.New("server not running")
|
||||
)
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/foomo/keel/service"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/config"
|
||||
@ -85,7 +86,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8081", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8081", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
@ -32,7 +33,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -8,6 +8,8 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/examples/healthz/handler"
|
||||
"github.com/foomo/keel/healthz"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
// See k8s for probe documentation
|
||||
@ -46,7 +48,7 @@ func main() {
|
||||
svr.AddReadinessHealthzers(rh)
|
||||
|
||||
// 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")
|
||||
return nil
|
||||
}))
|
||||
@ -69,7 +71,7 @@ func main() {
|
||||
|
||||
// add services
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
// start serer
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/log"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
type CustomError struct {
|
||||
@ -46,7 +47,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/log"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
httputils "github.com/foomo/keel/utils/net/http"
|
||||
)
|
||||
|
||||
@ -29,7 +30,7 @@ func main() {
|
||||
log.Must(l, err, "failed to hash password")
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.BasicAuth(
|
||||
username,
|
||||
passwordHash,
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"github.com/foomo/keel"
|
||||
keelhttp "github.com/foomo/keel/net/http"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -22,7 +23,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.CORS(
|
||||
middleware.CORSWithAllowOrigins("example.com"),
|
||||
middleware.CORSWithAllowMethods(http.MethodGet, http.MethodPost),
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
jwt2 "github.com/golang-jwt/jwt"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -75,7 +76,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Skip(
|
||||
middleware.JWT(
|
||||
jwtInst,
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"crypto/rsa"
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
jwt2 "github.com/golang-jwt/jwt"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
@ -66,7 +67,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Skip(
|
||||
middleware.JWT(
|
||||
jwtInst,
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"github.com/foomo/keel"
|
||||
keelhttp "github.com/foomo/keel/net/http"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -22,7 +23,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Logger(),
|
||||
),
|
||||
)
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -23,7 +24,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Recover(
|
||||
middleware.RecoverWithDisablePrintStack(true),
|
||||
),
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"github.com/foomo/keel"
|
||||
keelhttp "github.com/foomo/keel/net/http"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -27,7 +28,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.RequestID(
|
||||
middleware.RequestIDWithSetResponseHeader(true),
|
||||
middleware.RequestIDWithGenerator(requestIDGenerator),
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -27,7 +28,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.ResponseTime(
|
||||
// automatically set cookie if not exists
|
||||
middleware.ResponseTimeWithMaxDuration(time.Millisecond*500),
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
keelhttp "github.com/foomo/keel/net/http"
|
||||
"github.com/foomo/keel/net/http/cookie"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -44,7 +45,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.SessionID(
|
||||
// automatically set cookie if not exists
|
||||
middleware.SessionIDWithSetCookie(true),
|
||||
|
||||
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
@ -28,7 +29,7 @@ func main() {
|
||||
|
||||
svr.AddServices(
|
||||
// with URI blacklist
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Skip(
|
||||
func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
||||
return http.NotFoundHandler()
|
||||
@ -38,7 +39,7 @@ func main() {
|
||||
),
|
||||
|
||||
// with URI whitelist
|
||||
keel.NewServiceHTTP(l, "demo", ":8081", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8081", svs,
|
||||
middleware.Skip(
|
||||
func(l *zap.Logger, name string, next http.Handler) http.Handler {
|
||||
return http.NotFoundHandler()
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -23,7 +24,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Telemetry(
|
||||
middleware.TelemetryWithInjectPropagationHeader(true),
|
||||
),
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -26,7 +27,7 @@ func main() {
|
||||
tokenProvider := middleware.CookieTokenProvider("keel-token")
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.TokenAuth(
|
||||
token,
|
||||
middleware.TokenAuthWithTokenProvider(tokenProvider),
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -29,7 +30,7 @@ func main() {
|
||||
)
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.TokenAuth(
|
||||
token,
|
||||
middleware.TokenAuthWithTokenProvider(tokenProvider),
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/config"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -42,7 +43,7 @@ func main() {
|
||||
|
||||
// curl localhost:8080
|
||||
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) {
|
||||
fmt.Println("current foo:", fooFn()) //nolint:forbidigo
|
||||
}),
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func server() {
|
||||
@ -26,7 +27,7 @@ func server() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
keelhttp "github.com/foomo/keel/net/http"
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
"github.com/foomo/keel/net/http/roundtripware"
|
||||
"github.com/foomo/keel/service"
|
||||
httputils "github.com/foomo/keel/utils/net/http"
|
||||
)
|
||||
|
||||
@ -52,7 +53,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
// add middleware
|
||||
middleware.RequestID(),
|
||||
// add middleware
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func server() {
|
||||
@ -27,7 +28,7 @@ func server() {
|
||||
})
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/config"
|
||||
"github.com/foomo/keel/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -23,7 +24,7 @@ func main() {
|
||||
})
|
||||
|
||||
svr.AddServices(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080",
|
||||
service.NewHTTP(l, "demo", "localhost:8080",
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c.Set("service.enabled", !enabled())
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@ -32,7 +33,7 @@ func main() {
|
||||
),
|
||||
keel.NewServiceEnabler(l, "service-enabler",
|
||||
func() keel.Service {
|
||||
return keel.NewServiceHTTP(l, "service", "localhost:8081", svs)
|
||||
return service.NewHTTP(l, "service", "localhost:8081", svs)
|
||||
},
|
||||
enabled,
|
||||
),
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
@ -29,24 +28,11 @@ func main() {
|
||||
keel.WithHTTPPProfService(false),
|
||||
)
|
||||
|
||||
l := svr.Logger()
|
||||
|
||||
// alternatively you can add them manually
|
||||
// svr.AddServices(keel.NewDefaultServiceHTTPZap())
|
||||
// svr.AddServices(keel.NewDefaultServiceHTTPViper())
|
||||
// svr.AddServices(keel.NewDefaultServiceHTTPPProf())
|
||||
// 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()
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
@ -89,7 +90,7 @@ func main() {
|
||||
svr.AddClosers(subscription, stream)
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
@ -73,7 +74,7 @@ func main() {
|
||||
svr.AddClosers(subscription, stream.Conn())
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs),
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs),
|
||||
)
|
||||
|
||||
svr.Run()
|
||||
|
||||
@ -4,6 +4,9 @@ import (
|
||||
"math/rand"
|
||||
"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/metric/instrument"
|
||||
|
||||
@ -58,6 +61,14 @@ func main() {
|
||||
})
|
||||
}
|
||||
|
||||
promauto.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "foo",
|
||||
Subsystem: "",
|
||||
Name: "bar",
|
||||
Help: "blubb",
|
||||
ConstLabels: nil,
|
||||
})
|
||||
|
||||
{ // up down
|
||||
upDown, err := meter.SyncInt64().UpDownCounter(
|
||||
"a.updown",
|
||||
@ -92,7 +103,7 @@ func main() {
|
||||
}
|
||||
|
||||
svr.AddService(
|
||||
keel.NewServiceHTTP(l, "demo", "localhost:8080", svs,
|
||||
service.NewHTTP(l, "demo", "localhost:8080", svs,
|
||||
middleware.Telemetry(),
|
||||
middleware.Recover(),
|
||||
),
|
||||
|
||||
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.20
|
||||
require (
|
||||
github.com/avast/retry-go v3.0.0+incompatible
|
||||
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/go-logr/logr v1.2.4
|
||||
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.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
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/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
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"
|
||||
|
||||
@ -16,6 +16,10 @@ func (h healther) Healthz(ctx context.Context) error {
|
||||
return h.handle(ctx)
|
||||
}
|
||||
|
||||
func (h healther) Close(ctx context.Context) error {
|
||||
return h.handle(ctx)
|
||||
}
|
||||
|
||||
// BoolHealthzer interface
|
||||
type BoolHealthzer interface {
|
||||
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/
|
||||
type HealthzType string
|
||||
type Type string
|
||||
|
||||
const (
|
||||
// HealthzTypeAlways will run on any checks
|
||||
HealthzTypeAlways HealthzType = "always"
|
||||
// HealthzTypeStartup will run on /healthz/startup checks
|
||||
// TypeAlways will run on any checks
|
||||
TypeAlways Type = "always"
|
||||
// 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,
|
||||
// > 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
|
||||
// > killed by the kubelet before they are up and running.
|
||||
HealthzTypeStartup HealthzType = "startup"
|
||||
// HealthzTypeReadiness will run on /healthz/readiness checks
|
||||
TypeStartup Type = "startup"
|
||||
// TypeReadiness will run on /healthz/readiness checks
|
||||
// > 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
|
||||
// > which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.
|
||||
HealthzTypeReadiness HealthzType = "readiness"
|
||||
// HealthzTypeLiveness will run on /healthz/liveness checks
|
||||
TypeReadiness Type = "readiness"
|
||||
// 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
|
||||
// > 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.
|
||||
HealthzTypeLiveness HealthzType = "liveness"
|
||||
TypeLiveness Type = "liveness"
|
||||
)
|
||||
|
||||
// String interface
|
||||
func (t HealthzType) String() string {
|
||||
func (t Type) String() string {
|
||||
return string(t)
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
package keel
|
||||
package interfaces
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type closer struct {
|
||||
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
|
||||
type Closer interface {
|
||||
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"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package keel
|
||||
package interfaces
|
||||
|
||||
import "context"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package keel
|
||||
package interfaces
|
||||
|
||||
import "context"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package keel
|
||||
package interfaces
|
||||
|
||||
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 (
|
||||
ServiceTypeKey = "service_type"
|
||||
|
||||
// ServiceNameKey represents the NameKey of the service.
|
||||
ServiceNameKey = "service_name"
|
||||
|
||||
@ -35,6 +37,10 @@ const (
|
||||
ServiceVersionKey = "service_version"
|
||||
)
|
||||
|
||||
func FServiceType(name string) zap.Field {
|
||||
return zap.String(ServiceTypeKey, name)
|
||||
}
|
||||
|
||||
func FServiceName(name string) zap.Field {
|
||||
return zap.String(ServiceNameKey, name)
|
||||
}
|
||||
|
||||
12
log/with.go
12
log/with.go
@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -20,6 +21,17 @@ func With(l *zap.Logger, fields ...zap.Field) *zap.Logger {
|
||||
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 {
|
||||
return With(l, FErrorType(err), FError(err))
|
||||
}
|
||||
|
||||
31
option.go
31
option.go
@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@ -72,9 +73,9 @@ func WithShutdownTimeout(shutdownTimeout time.Duration) Option {
|
||||
func WithHTTPZapService(enabled bool) Option {
|
||||
return func(inst *Server) {
|
||||
if config.GetBool(inst.Config(), "service.zap.enabled", enabled)() {
|
||||
service := NewDefaultServiceHTTPZap()
|
||||
inst.initServices = append(inst.initServices, service)
|
||||
inst.AddAlwaysHealthzers(service)
|
||||
svs := service.NewDefaultHTTPZap()
|
||||
inst.initServices = append(inst.initServices, svs)
|
||||
inst.AddAlwaysHealthzers(svs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,9 +84,9 @@ func WithHTTPZapService(enabled bool) Option {
|
||||
func WithHTTPViperService(enabled bool) Option {
|
||||
return func(inst *Server) {
|
||||
if config.GetBool(inst.Config(), "service.viper.enabled", enabled)() {
|
||||
service := NewDefaultServiceHTTPViper()
|
||||
inst.initServices = append(inst.initServices, service)
|
||||
inst.AddAlwaysHealthzers(service)
|
||||
svs := service.NewDefaultHTTPViper()
|
||||
inst.initServices = append(inst.initServices, svs)
|
||||
inst.AddAlwaysHealthzers(svs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,9 +150,9 @@ func WithPrometheusMeter(enabled bool) Option {
|
||||
func WithHTTPPrometheusService(enabled bool) Option {
|
||||
return func(inst *Server) {
|
||||
if config.GetBool(inst.Config(), "service.prometheus.enabled", enabled)() {
|
||||
service := NewDefaultServiceHTTPPrometheus()
|
||||
inst.initServices = append(inst.initServices, service)
|
||||
inst.AddAlwaysHealthzers(service)
|
||||
svs := service.NewDefaultHTTPPrometheus()
|
||||
inst.initServices = append(inst.initServices, svs)
|
||||
inst.AddAlwaysHealthzers(svs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,9 +161,9 @@ func WithHTTPPrometheusService(enabled bool) Option {
|
||||
func WithHTTPPProfService(enabled bool) Option {
|
||||
return func(inst *Server) {
|
||||
if config.GetBool(inst.Config(), "service.pprof.enabled", enabled)() {
|
||||
service := NewDefaultServiceHTTPPProf()
|
||||
inst.initServices = append(inst.initServices, service)
|
||||
inst.AddAlwaysHealthzers(service)
|
||||
svs := service.NewDefaultHTTPPProf()
|
||||
inst.initServices = append(inst.initServices, svs)
|
||||
inst.AddAlwaysHealthzers(svs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -171,9 +172,9 @@ func WithHTTPPProfService(enabled bool) Option {
|
||||
func WithHTTPHealthzService(enabled bool) Option {
|
||||
return func(inst *Server) {
|
||||
if config.GetBool(inst.Config(), "service.healthz.enabled", enabled)() {
|
||||
service := NewDefaultServiceHTTPProbes(inst.probes)
|
||||
inst.initServices = append(inst.initServices, service)
|
||||
inst.AddAlwaysHealthzers(service)
|
||||
svs := service.NewDefaultHTTPProbes(inst.probes)
|
||||
inst.initServices = append(inst.initServices, svs)
|
||||
inst.AddAlwaysHealthzers(svs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
97
server.go
97
server.go
@ -1,3 +1,6 @@
|
||||
//go:build !docs
|
||||
// +build !docs
|
||||
|
||||
package keel
|
||||
|
||||
import (
|
||||
@ -10,6 +13,8 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/healthz"
|
||||
"github.com/foomo/keel/interfaces"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
@ -40,7 +45,7 @@ type Server struct {
|
||||
shutdownTimeout time.Duration
|
||||
running atomic.Bool
|
||||
closers []interface{}
|
||||
probes map[HealthzType][]interface{}
|
||||
probes map[healthz.Type][]interface{}
|
||||
ctx context.Context
|
||||
ctxCancel context.Context
|
||||
ctxCancelFn context.CancelFunc
|
||||
@ -54,7 +59,7 @@ func NewServer(opts ...Option) *Server {
|
||||
inst := &Server{
|
||||
shutdownTimeout: 30 * time.Second,
|
||||
shutdownSignals: []os.Signal{os.Interrupt, syscall.SIGTERM},
|
||||
probes: map[HealthzType][]interface{}{},
|
||||
probes: map[healthz.Type][]interface{}{},
|
||||
ctx: context.Background(),
|
||||
c: config.Config(),
|
||||
l: log.Logger(),
|
||||
@ -83,51 +88,51 @@ func NewServer(opts ...Option) *Server {
|
||||
for _, closer := range closers {
|
||||
l := inst.l.With(log.FName(fmt.Sprintf("%T", closer)))
|
||||
switch c := closer.(type) {
|
||||
case Closer:
|
||||
case interfaces.Closer:
|
||||
c.Close()
|
||||
case ErrorCloser:
|
||||
case interfaces.ErrorCloser:
|
||||
if err := c.Close(); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorCloser")
|
||||
}
|
||||
case CloserWithContext:
|
||||
case interfaces.CloserWithContext:
|
||||
c.Close(timeoutCtx)
|
||||
case ErrorCloserWithContext:
|
||||
case interfaces.ErrorCloserWithContext:
|
||||
if err := c.Close(timeoutCtx); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorCloserWithContext")
|
||||
}
|
||||
case Shutdowner:
|
||||
case interfaces.Shutdowner:
|
||||
c.Shutdown()
|
||||
case ErrorShutdowner:
|
||||
case interfaces.ErrorShutdowner:
|
||||
if err := c.Shutdown(); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorShutdowner")
|
||||
}
|
||||
case ShutdownerWithContext:
|
||||
case interfaces.ShutdownerWithContext:
|
||||
c.Shutdown(timeoutCtx)
|
||||
case ErrorShutdownerWithContext:
|
||||
case interfaces.ErrorShutdownerWithContext:
|
||||
if err := c.Shutdown(timeoutCtx); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorShutdownerWithContext")
|
||||
}
|
||||
case Stopper:
|
||||
case interfaces.Stopper:
|
||||
c.Stop()
|
||||
case ErrorStopper:
|
||||
case interfaces.ErrorStopper:
|
||||
if err := c.Stop(); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorStopper")
|
||||
}
|
||||
case StopperWithContext:
|
||||
case interfaces.StopperWithContext:
|
||||
c.Stop(timeoutCtx)
|
||||
case ErrorStopperWithContext:
|
||||
case interfaces.ErrorStopperWithContext:
|
||||
if err := c.Stop(timeoutCtx); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorStopperWithContext")
|
||||
}
|
||||
case Unsubscriber:
|
||||
case interfaces.Unsubscriber:
|
||||
c.Unsubscribe()
|
||||
case ErrorUnsubscriber:
|
||||
case interfaces.ErrorUnsubscriber:
|
||||
if err := c.Unsubscribe(); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriber")
|
||||
}
|
||||
case UnsubscriberWithContext:
|
||||
case interfaces.UnsubscriberWithContext:
|
||||
c.Unsubscribe(timeoutCtx)
|
||||
case ErrorUnsubscriberWithContext:
|
||||
case interfaces.ErrorUnsubscriberWithContext:
|
||||
if err := c.Unsubscribe(timeoutCtx); err != nil {
|
||||
log.WithError(l, err).Error("failed to gracefully stop ErrorUnsubscriberWithContext")
|
||||
}
|
||||
@ -229,22 +234,22 @@ func (s *Server) AddCloser(closer interface{}) {
|
||||
}
|
||||
}
|
||||
switch closer.(type) {
|
||||
case Closer,
|
||||
ErrorCloser,
|
||||
CloserWithContext,
|
||||
ErrorCloserWithContext,
|
||||
Shutdowner,
|
||||
ErrorShutdowner,
|
||||
ShutdownerWithContext,
|
||||
ErrorShutdownerWithContext,
|
||||
Stopper,
|
||||
ErrorStopper,
|
||||
StopperWithContext,
|
||||
ErrorStopperWithContext,
|
||||
Unsubscriber,
|
||||
ErrorUnsubscriber,
|
||||
UnsubscriberWithContext,
|
||||
ErrorUnsubscriberWithContext:
|
||||
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)))
|
||||
@ -259,14 +264,14 @@ func (s *Server) AddClosers(closers ...interface{}) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
case BoolHealthzer,
|
||||
BoolHealthzerWithContext,
|
||||
ErrorHealthzer,
|
||||
ErrorHealthzWithContext,
|
||||
ErrorPinger,
|
||||
ErrorPingerWithContext:
|
||||
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)))
|
||||
@ -274,7 +279,7 @@ func (s *Server) AddHealthzer(typ HealthzType, probe interface{}) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/zap"
|
||||
@ -74,7 +75,7 @@ func (s *KeelTestSuite) TearDownSuite() {}
|
||||
|
||||
func (s *KeelTestSuite) TestServiceHTTP() {
|
||||
s.svr.AddServices(
|
||||
keel.NewServiceHTTP(s.l, "test", ":55000", s.mux),
|
||||
service.NewHTTP(s.l, "test", ":55000", s.mux),
|
||||
)
|
||||
|
||||
s.runServer()
|
||||
@ -86,8 +87,8 @@ func (s *KeelTestSuite) TestServiceHTTP() {
|
||||
|
||||
func (s *KeelTestSuite) TestServiceHTTPZap() {
|
||||
s.svr.AddServices(
|
||||
keel.NewServiceHTTPZap(s.l, "zap", ":9100", "/log"),
|
||||
keel.NewServiceHTTP(s.l, "test", ":55000", s.mux),
|
||||
service.NewHTTPZap(s.l, "zap", ":9100", "/log"),
|
||||
service.NewHTTP(s.l, "test", ":55000", s.mux),
|
||||
)
|
||||
|
||||
s.runServer()
|
||||
@ -141,7 +142,7 @@ func (s *KeelTestSuite) TestServiceHTTPZap() {
|
||||
|
||||
func (s *KeelTestSuite) TestGraceful() {
|
||||
s.svr.AddServices(
|
||||
keel.NewServiceHTTP(s.l, "test", ":55000", s.mux),
|
||||
service.NewHTTP(s.l, "test", ":55000", s.mux),
|
||||
)
|
||||
|
||||
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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -14,22 +15,25 @@ import (
|
||||
"github.com/foomo/keel/net/http/middleware"
|
||||
)
|
||||
|
||||
// ServiceHTTP struct
|
||||
type ServiceHTTP struct {
|
||||
// HTTP struct
|
||||
type HTTP struct {
|
||||
running atomic.Bool
|
||||
server *http.Server
|
||||
name string
|
||||
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 {
|
||||
l = log.Logger()
|
||||
}
|
||||
// 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{
|
||||
Addr: addr,
|
||||
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
|
||||
}
|
||||
|
||||
func (s *ServiceHTTP) Healthz() error {
|
||||
func (s *HTTP) Healthz() error {
|
||||
if !s.running.Load() {
|
||||
return ErrServiceNotRunning
|
||||
}
|
||||
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
|
||||
if value := strings.Split(s.server.Addr, ":"); len(value) == 2 {
|
||||
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))
|
||||
}
|
||||
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.RegisterOnShutdown(func() {
|
||||
s.running.Store(false)
|
||||
})
|
||||
s.running.Store(true)
|
||||
if err := s.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
||||
log.WithError(s.l, err).Error("service error")
|
||||
return err
|
||||
if err := s.server.ListenAndServe(); errors.Is(err, http.ErrServerClosed) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return errors.Wrap(err, "failed to start service")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceHTTP) Close(ctx context.Context) error {
|
||||
s.l.Info("stopping http service")
|
||||
return s.server.Shutdown(ctx)
|
||||
func (s *HTTP) Close(ctx context.Context) error {
|
||||
s.l.Info("stopping keel service")
|
||||
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 (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/keel/healthz"
|
||||
"github.com/foomo/keel/interfaces"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/foomo/keel/log"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServiceHTTPHealthzName = "healthz"
|
||||
DefaultServiceHTTPHealthzAddr = ":9400"
|
||||
DefaultServiceHTTPHealthzPath = "/healthz"
|
||||
DefaultHTTPHealthzName = "healthz"
|
||||
DefaultHTTPHealthzAddr = ":9400"
|
||||
DefaultHTTPHealthzPath = "/healthz"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -24,7 +26,7 @@ var (
|
||||
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()
|
||||
|
||||
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) {
|
||||
switch h := probe.(type) {
|
||||
case BoolHealthzer:
|
||||
case healthz.BoolHealthzer:
|
||||
return h.Healthz(), nil
|
||||
case BoolHealthzerWithContext:
|
||||
case healthz.BoolHealthzerWithContext:
|
||||
return h.Healthz(ctx), nil
|
||||
case ErrorHealthzer:
|
||||
case healthz.ErrorHealthzer:
|
||||
return true, h.Healthz()
|
||||
case ErrorHealthzWithContext:
|
||||
case healthz.ErrorHealthzWithContext:
|
||||
return true, h.Healthz(ctx)
|
||||
case ErrorPinger:
|
||||
case interfaces.ErrorPinger:
|
||||
return true, h.Ping()
|
||||
case ErrorPingerWithContext:
|
||||
case interfaces.ErrorPingerWithContext:
|
||||
return true, h.Ping(ctx)
|
||||
default:
|
||||
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) {
|
||||
for typ, values := range probes {
|
||||
if typ == HealthzTypeStartup {
|
||||
if typ == healthz.TypeStartup {
|
||||
continue
|
||||
}
|
||||
for _, p := range values {
|
||||
@ -72,12 +74,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
_, _ = 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{}
|
||||
if p, ok := probes[HealthzTypeAlways]; ok {
|
||||
if p, ok := probes[healthz.TypeAlways]; ok {
|
||||
ps = append(ps, p...)
|
||||
}
|
||||
if p, ok := probes[HealthzTypeLiveness]; ok {
|
||||
if p, ok := probes[healthz.TypeLiveness]; ok {
|
||||
ps = append(ps, p...)
|
||||
}
|
||||
for _, p := range ps {
|
||||
@ -93,12 +95,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
_, _ = 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{}
|
||||
if p, ok := probes[HealthzTypeAlways]; ok {
|
||||
if p, ok := probes[healthz.TypeAlways]; ok {
|
||||
ps = append(ps, p...)
|
||||
}
|
||||
if p, ok := probes[HealthzTypeReadiness]; ok {
|
||||
if p, ok := probes[healthz.TypeReadiness]; ok {
|
||||
ps = append(ps, p...)
|
||||
}
|
||||
for _, p := range ps {
|
||||
@ -114,12 +116,12 @@ func NewServiceHTTPHealthz(l *zap.Logger, name, addr, path string, probes map[He
|
||||
_, _ = 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{}
|
||||
if p, ok := probes[HealthzTypeAlways]; ok {
|
||||
if p, ok := probes[healthz.TypeAlways]; ok {
|
||||
ps = append(ps, p...)
|
||||
}
|
||||
if p, ok := probes[HealthzTypeStartup]; ok {
|
||||
if p, ok := probes[healthz.TypeStartup]; ok {
|
||||
ps = append(ps, p...)
|
||||
}
|
||||
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.Write([]byte("OK"))
|
||||
})
|
||||
return NewServiceHTTP(l, name, addr, handler)
|
||||
return NewHTTP(l, name, addr, handler)
|
||||
}
|
||||
|
||||
func NewDefaultServiceHTTPProbes(probes map[HealthzType][]interface{}) *ServiceHTTP {
|
||||
return NewServiceHTTPHealthz(
|
||||
func NewDefaultHTTPProbes(probes map[healthz.Type][]interface{}) *HTTP {
|
||||
return NewHealthz(
|
||||
log.Logger(),
|
||||
DefaultServiceHTTPHealthzName,
|
||||
DefaultServiceHTTPHealthzAddr,
|
||||
DefaultServiceHTTPHealthzPath,
|
||||
DefaultHTTPHealthzName,
|
||||
DefaultHTTPHealthzAddr,
|
||||
DefaultHTTPHealthzPath,
|
||||
probes,
|
||||
)
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
//go:build !pprof
|
||||
|
||||
package keel
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@ -10,12 +10,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServiceHTTPPProfName = "pprof"
|
||||
DefaultServiceHTTPPProfAddr = "localhost:6060"
|
||||
DefaultServiceHTTPPProfPath = "/debug/pprof"
|
||||
DefaultHTTPPProfName = "pprof"
|
||||
DefaultHTTPPProfAddr = "localhost:6060"
|
||||
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) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
_, _ = 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+"/symbol", route)
|
||||
handler.HandleFunc(path+"/trace", route)
|
||||
return NewServiceHTTP(l, name, addr, handler)
|
||||
return NewHTTP(l, name, addr, handler)
|
||||
}
|
||||
|
||||
func NewDefaultServiceHTTPPProf() *ServiceHTTP {
|
||||
return NewServiceHTTPPProf(
|
||||
func NewDefaultHTTPPProf() *HTTP {
|
||||
return NewHTTPPProf(
|
||||
log.Logger(),
|
||||
DefaultServiceHTTPPProfName,
|
||||
DefaultServiceHTTPPProfAddr,
|
||||
DefaultServiceHTTPPProfPath,
|
||||
DefaultHTTPPProfName,
|
||||
DefaultHTTPPProfAddr,
|
||||
DefaultHTTPPProfPath,
|
||||
)
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
//go:build pprof
|
||||
// +build pprof
|
||||
|
||||
package keel
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@ -12,12 +12,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServiceHTTPPProfName = "pprof"
|
||||
DefaultServiceHTTPPProfAddr = "localhost:6060"
|
||||
DefaultServiceHTTPPProfPath = "/debug/pprof"
|
||||
DefaultHTTPPProfName = "pprof"
|
||||
DefaultHTTPPProfAddr = "localhost:6060"
|
||||
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.HandleFunc(path+"/", pprof.Index)
|
||||
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)
|
||||
}
|
||||
|
||||
func NewDefaultServiceHTTPPProf() *ServiceHTTP {
|
||||
return NewServiceHTTPPProf(
|
||||
func NewDefaultHTTPPProf() *ServiceHTTP {
|
||||
return NewHTTPPProf(
|
||||
log.Logger(),
|
||||
DefaultServiceHTTPPProfName,
|
||||
DefaultServiceHTTPPProfAddr,
|
||||
DefaultServiceHTTPPProfPath,
|
||||
DefaultHTTPPProfName,
|
||||
DefaultHTTPPProfAddr,
|
||||
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 (
|
||||
"encoding/json"
|
||||
@ -12,12 +12,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServiceHTTPViperName = "viper"
|
||||
DefaultServiceHTTPViperAddr = "localhost:9300"
|
||||
DefaultServiceHTTPViperPath = "/config"
|
||||
DefaultHTTPViperName = "viper"
|
||||
DefaultHTTPViperAddr = "localhost:9300"
|
||||
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.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
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)
|
||||
}
|
||||
})
|
||||
return NewServiceHTTP(l, name, addr, handler)
|
||||
return NewHTTP(l, name, addr, handler)
|
||||
}
|
||||
|
||||
func NewDefaultServiceHTTPViper() *ServiceHTTP {
|
||||
return NewServiceHTTPViper(
|
||||
func NewDefaultHTTPViper() *HTTP {
|
||||
return NewHTTPViper(
|
||||
log.Logger(),
|
||||
config.Config(),
|
||||
DefaultServiceHTTPViperName,
|
||||
DefaultServiceHTTPViperAddr,
|
||||
DefaultServiceHTTPViperPath,
|
||||
DefaultHTTPViperName,
|
||||
DefaultHTTPViperAddr,
|
||||
DefaultHTTPViperPath,
|
||||
)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package keel
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -12,12 +12,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultServiceHTTPZapName = "zap"
|
||||
DefaultServiceHTTPZapAddr = "localhost:9100"
|
||||
DefaultServiceHTTPZapPath = "/log"
|
||||
DefaultHTTPZapName = "zap"
|
||||
DefaultHTTPZapAddr = "localhost:9100"
|
||||
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.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
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 {
|
||||
return NewServiceHTTPZap(
|
||||
func NewDefaultHTTPZap() *HTTP {
|
||||
return NewHTTPZap(
|
||||
log.Logger(),
|
||||
DefaultServiceHTTPZapName,
|
||||
DefaultServiceHTTPZapAddr,
|
||||
DefaultServiceHTTPZapPath,
|
||||
DefaultHTTPZapName,
|
||||
DefaultHTTPZapAddr,
|
||||
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