Skip to content
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

Support dynamiclly set glog.logging.verbosity #63777

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions staging/src/k8s.io/apiserver/pkg/server/config.go
Expand Up @@ -65,6 +65,7 @@ import (
openapicommon "k8s.io/kube-openapi/pkg/common"

// install apis
"github.com/golang/glog"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't make you change it again but this is in the wrong section :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the ide auto imports and put it here. I will fix it later.

_ "k8s.io/apiserver/pkg/apis/apiserver/install"
)

Expand Down Expand Up @@ -575,6 +576,16 @@ func installAPI(s *GenericAPIServer, c *Config) {
if c.EnableContentionProfiling {
goruntime.SetBlockProfileRate(1)
}
// so far, only logging related endpoints are considered valid to add for these debug flags.
routes.DebugFlags{}.Install(s.Handler.NonGoRestfulMux, "v", routes.StringFlagPutHandler(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this gated on profiling being enabled?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's @lavalamp suggested: #63777 (comment)

routes.StringFlagSetterFunc(func(val string) (string, error) {
var level glog.Level
if err := level.Set(val); err != nil {
return "", fmt.Errorf("failed set glog.logging.verbosity %s: %v", val, err)
}
return "successfully set glog.logging.verbosity to " + val, nil
}),
))
}
if c.EnableMetrics {
if c.EnableProfiling {
Expand All @@ -583,6 +594,7 @@ func installAPI(s *GenericAPIServer, c *Config) {
routes.DefaultMetrics{}.Install(s.Handler.NonGoRestfulMux)
}
}

routes.Version{Version: c.Version}.Install(s.Handler.GoRestfulContainer)

if c.EnableDiscovery {
Expand Down
Expand Up @@ -385,6 +385,7 @@ func TestNotRestRoutesHaveAuth(t *testing.T) {
{"/"},
{"/swagger-ui/"},
{"/debug/pprof/"},
{"/debug/flags/"},
{"/version"},
} {
resp := httptest.NewRecorder()
Expand Down
1 change: 1 addition & 0 deletions staging/src/k8s.io/apiserver/pkg/server/routes/BUILD
Expand Up @@ -9,6 +9,7 @@ go_library(
name = "go_default_library",
srcs = [
"doc.go",
"flags.go",
"index.go",
"metrics.go",
"openapi.go",
Expand Down
126 changes: 126 additions & 0 deletions staging/src/k8s.io/apiserver/pkg/server/routes/flags.go
@@ -0,0 +1,126 @@
/*
Copyright 2018 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 routes

import (
"fmt"
"html/template"
"io/ioutil"
"net/http"
"path"
"sync"

"github.com/golang/glog"

"k8s.io/apiserver/pkg/server/mux"
)

var (
lock = &sync.RWMutex{}
registeredFlags = map[string]debugFlag{}
)

// DebugFlags adds handlers for flags under /debug/flags.
type DebugFlags struct {
}

// Install registers the APIServer's flags handler.
func (f DebugFlags) Install(c *mux.PathRecorderMux, flag string, handler func(http.ResponseWriter, *http.Request)) {
c.UnlistedHandle("/debug/flags", http.HandlerFunc(f.Index))
c.UnlistedHandlePrefix("/debug/flags/", http.HandlerFunc(f.Index))

url := path.Join("/debug/flags", flag)
c.UnlistedHandleFunc(url, handler)

f.addFlag(flag)
}

// Index responds with the `/debug/flags` request.
// For example, "/debug/flags/v" serves the "--v" flag.
// Index responds to a request for "/debug/flags/" with an HTML page
// listing the available flags.
func (f DebugFlags) Index(w http.ResponseWriter, r *http.Request) {
lock.RLock()
defer lock.RUnlock()
if err := indexTmpl.Execute(w, registeredFlags); err != nil {
glog.Error(err)
}
}

var indexTmpl = template.Must(template.New("index").Parse(`<html>
<head>
<title>/debug/flags/</title>
</head>
<body>
/debug/flags/<br>
<br>
flags:<br>
<table>
{{range .}}
<tr>{{.Flag}}<br>
{{end}}
</table>
<br>
full flags configurable<br>
</body>
</html>
`))

type debugFlag struct {
Flag string
}

func (f DebugFlags) addFlag(flag string) {
lock.Lock()
defer lock.Unlock()
registeredFlags[flag] = debugFlag{flag}
}

// StringFlagSetterFunc is a func used for setting string type flag.
type StringFlagSetterFunc func(string) (string, error)

// StringFlagPutHandler wraps an http Handler to set string type flag.
func StringFlagPutHandler(setter StringFlagSetterFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
switch {
case req.Method == "PUT":
body, err := ioutil.ReadAll(req.Body)
if err != nil {
writePlainText(http.StatusBadRequest, "error reading request body: "+err.Error(), w)
return
}
defer req.Body.Close()
response, err := setter(string(body))
if err != nil {
writePlainText(http.StatusBadRequest, err.Error(), w)
return
}
writePlainText(http.StatusOK, response, w)
return
default:
writePlainText(http.StatusNotAcceptable, "unsupported http method", w)
return
}
})
}

// writePlainText renders a simple string response.
func writePlainText(statusCode int, text string, w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(statusCode)
fmt.Fprintln(w, text)
}