-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add pprof and create admin endpoint (#1315)
Signed-off-by: Konrad Galuszka <konrad.galuszka.ctr@sabre.com>
- Loading branch information
Konrad Galuszka
committed
Feb 28, 2019
1 parent
adec968
commit 0bbd2a2
Showing
10 changed files
with
237 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Copyright (c) 2019 The Jaeger Authors. | ||
// Copyright (c) 2017 Uber Technologies, Inc. | ||
// | ||
// 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 adminendpoint | ||
|
||
import ( | ||
"context" | ||
"net" | ||
"net/http" | ||
"net/http/pprof" | ||
"strconv" | ||
|
||
"go.uber.org/zap" | ||
|
||
hc "github.com/jaegertracing/jaeger/pkg/adminendpoint/healthcheck" | ||
"github.com/jaegertracing/jaeger/pkg/version" | ||
) | ||
|
||
// AdminEndpoint provides an endpoint that returns the healthcheck or profiling tool | ||
type AdminEndpoint struct { | ||
logger *zap.Logger | ||
server *http.Server | ||
healthcheck *hc.HealthCheck | ||
} | ||
|
||
// Option is a functional option for passing parameters to New() | ||
type Option func(endpoint *AdminEndpoint) | ||
|
||
// Logger creates an option to set the logger. If not specified, Nop logger is used. | ||
func Logger(logger *zap.Logger) Option { | ||
return func(ae *AdminEndpoint) { | ||
ae.logger = logger | ||
} | ||
} | ||
|
||
// HealthCheck creates an option to set the healthcheck. Required | ||
func HealthCheck(healthcheck *hc.HealthCheck) Option { | ||
return func(ae *AdminEndpoint) { | ||
ae.healthcheck = healthcheck | ||
} | ||
} | ||
|
||
// New creates a AdminEndpoint | ||
func New(options ...Option) *AdminEndpoint { | ||
ae := &AdminEndpoint{} | ||
for _, option := range options { | ||
option(ae) | ||
} | ||
if ae.logger == nil { | ||
ae.logger = zap.NewNop() | ||
} | ||
return ae | ||
} | ||
|
||
// Serve starts HTTP server on the specified port. | ||
func (ae *AdminEndpoint) Serve(port int) error { | ||
portStr := ":" + strconv.Itoa(port) | ||
l, err := net.Listen("tcp", portStr) | ||
if err != nil { | ||
ae.logger.Error("Admin endpoint server failed to listen", zap.Error(err)) | ||
return err | ||
} | ||
ae.serveWithListener(l) | ||
ae.logger.Info("Admin endpoint server started", zap.Int("http-port", port), zap.Stringer("status", ae.healthcheck.Get())) | ||
return nil | ||
} | ||
|
||
// ServeWithListener starts server using given listener | ||
func (ae *AdminEndpoint) serveWithListener(l net.Listener) { | ||
ae.server = &http.Server{Handler: ae.httpHandler()} | ||
go func() { | ||
if err := ae.server.Serve(l); err != nil { | ||
ae.logger.Error("failed to serve", zap.Error(err)) | ||
ae.healthcheck.Set(hc.Broken) | ||
} | ||
}() | ||
} | ||
|
||
// Close stops the HTTP server | ||
func (ae *AdminEndpoint) Close() error { | ||
return ae.server.Shutdown(context.Background()) | ||
} | ||
|
||
// httpHandler creates a new HTTP handler. | ||
func (ae *AdminEndpoint) httpHandler() http.Handler { | ||
mux := http.NewServeMux() | ||
ae.registerHealthCheckHandler(mux) | ||
ae.registerProfilingHandler(mux) | ||
version.RegisterHandler(mux, ae.logger) | ||
return mux | ||
} | ||
|
||
// registerHealthCheckHandler registers | ||
func (ae *AdminEndpoint) registerHealthCheckHandler(mux *http.ServeMux) { | ||
mux.HandleFunc("/", ae.healthcheck.GetHandlerFunc()) | ||
} | ||
|
||
// registerProfilingHandler adds pprof endpoints | ||
func (ae *AdminEndpoint) registerProfilingHandler(mux *http.ServeMux) { | ||
mux.HandleFunc("/debug/pprof/", pprof.Index) | ||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) | ||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile) | ||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) | ||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace) | ||
mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine")) | ||
mux.Handle("/debug/pprof/heap", pprof.Handler("heap")) | ||
mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate")) | ||
mux.Handle("/debug/pprof/block", pprof.Handler("block")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright (c) 2019 The Jaeger Authors. | ||
// Copyright (c) 2017 Uber Technologies, Inc. | ||
// | ||
// 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 adminendpoint_test | ||
|
||
import ( | ||
"net" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/jaegertracing/jaeger/pkg/adminendpoint" | ||
"github.com/jaegertracing/jaeger/pkg/adminendpoint/healthcheck" | ||
"github.com/jaegertracing/jaeger/pkg/testutils" | ||
) | ||
|
||
func TestPortBusy(t *testing.T) { | ||
l, err := net.Listen("tcp", ":0") | ||
require.NoError(t, err) | ||
defer l.Close() | ||
port := l.Addr().(*net.TCPAddr).Port | ||
|
||
logger, logBuf := testutils.NewLogger() | ||
err = adminendpoint.New(adminendpoint.Logger(logger)).Serve(port) | ||
assert.Error(t, err) | ||
assert.Equal(t, "Admin endpoint server failed to listen", logBuf.JSONLine(0)["msg"]) | ||
} | ||
|
||
func TestServeHandler(t *testing.T) { | ||
hc := healthcheck.New(healthcheck.Ready) | ||
ae := adminendpoint.New(adminendpoint.HealthCheck(hc)) | ||
err := ae.Serve(0) | ||
require.NoError(t, err) | ||
defer ae.Close() | ||
} |
Oops, something went wrong.