Skip to content

✨ Add httpserver.Server and pkg/debug for pprof support #743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions pkg/debug/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2020 The Kubernetes 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 debug

import (
"net/http/pprof"

"sigs.k8s.io/controller-runtime/pkg/httpserver"
)

// Options use to provide configuration option
type Options struct {
CmdLine bool
Profile bool
Symbol bool
Trace bool
}

// DefaultOptions returns default options configuration
func DefaultOptions() *Options {
return &Options{
CmdLine: true,
Profile: true,
Symbol: true,
Trace: true,
}
}

// Register use to register the different debug endpoint
func Register(mux httpserver.Server, options *Options) {
mux.HandleFunc("/debug/pprof/", pprof.Index)
if options == nil {
options = DefaultOptions()
}
if options.CmdLine {
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
}
if options.Profile {
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
}
if options.Symbol {
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
}
if options.Trace {
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
}
}
31 changes: 31 additions & 0 deletions pkg/httpserver/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2020 The Kubernetes 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 httpserver

import (
"net/http"

"sigs.k8s.io/controller-runtime/pkg/manager"
)

// Server inferface for the http server
// Allows to register http.Hander and http.HandlerFunc
type Server interface {
manager.Runnable
Handle(path string, handler http.Handler)
HandleFunc(path string, handlerFunc http.HandlerFunc)
}
103 changes: 103 additions & 0 deletions pkg/httpserver/runner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
Copyright 2020 The Kubernetes 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 httpserver

import (
"context"
"fmt"
"net"
"net/http"

logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
)

var log = logf.RuntimeLog.WithName("httpserver")

// DefaultBindAddress sets the default bind address for the HTTP server listener
var DefaultBindAddress = ":8080"

// Options use to provides Runner creation options
type Options struct {
BindAddress string
}

// server HTTP debug server
type server struct {
bindAddress string

mux *http.ServeMux
}

// New returns new Runner instance
func New(options Options) Server {
return &server{
bindAddress: options.BindAddress,
mux: http.NewServeMux(),
}
}

// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (s *server) Handle(path string, handler http.Handler) {
s.mux.Handle(path, handler)
}

// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func (s *server) HandleFunc(path string, handlerFunc http.HandlerFunc) {
s.mux.HandleFunc(path, handlerFunc)
}

// Start use to start the HTTP server
func (s *server) Start(stop <-chan struct{}) error {
listener, err := newListener(s.bindAddress)
if err != nil {
return err
}
server := http.Server{
Handler: s.mux,
}
// Run the server
go func() {
log.Info("starting http server")
if err := server.Serve(listener); err != nil && err != http.ErrServerClosed {
log.Error(err, "http server error")
}
}()

// Shutdown the server when stop is close
<-stop
return server.Shutdown(context.Background())
}

// newListener creates a new TCP listener bound to the given address.
func newListener(addr string) (net.Listener, error) {
if addr == "" {
// If the http server bind address is empty, default to ":8080"
addr = DefaultBindAddress
}

log.Info("debug server is starting to listen", "addr", addr)
ln, err := net.Listen("tcp", addr)
if err != nil {
er := fmt.Errorf("error listening on %s: %v", addr, err)
log.Error(er, "debug server failed to listen. You may want to disable the debug server or use another port if it is due to conflicts")
return nil, er
}
return ln, nil
}
32 changes: 32 additions & 0 deletions pkg/metrics/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright 2020 The Kubernetes 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 metrics

import (
"github.com/prometheus/client_golang/prometheus/promhttp"

"sigs.k8s.io/controller-runtime/pkg/httpserver"
)

// Register used to register Metrics handler in the http server
func Register(mux httpserver.Server) {
var metricsPath = "/metrics"
handler := promhttp.HandlerFor(Registry, promhttp.HandlerOpts{
ErrorHandling: promhttp.HTTPErrorOnError,
})
mux.Handle(metricsPath, handler)
}