1
// Copyright Istio Authors
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
23
"github.com/gorilla/mux"
25
"istio.io/istio/pkg/ctrlz/fw"
26
"istio.io/istio/pkg/ctrlz/topics/assets"
27
"istio.io/istio/pkg/log"
30
type scopeTopic struct{}
32
type scopeInfo struct {
33
Name string `json:"name"`
34
Description string `json:"description"`
35
OutputLevel string `json:"output_level"`
36
StackTraceLevel string `json:"stack_trace_level"`
37
LogCallers bool `json:"log_callers"`
40
var levelToString = map[log.Level]string{
41
log.DebugLevel: "debug",
42
log.InfoLevel: "info",
43
log.WarnLevel: "warn",
44
log.ErrorLevel: "error",
45
log.NoneLevel: "none",
48
var stringToLevel = map[string]log.Level{
49
"debug": log.DebugLevel,
50
"info": log.InfoLevel,
51
"warn": log.WarnLevel,
52
"error": log.ErrorLevel,
53
"none": log.NoneLevel,
56
// ScopeTopic returns a ControlZ topic that allows visualization of process logging scopes.
57
func ScopeTopic() fw.Topic {
61
func (scopeTopic) Title() string {
62
return "Logging Scopes"
65
func (scopeTopic) Prefix() string {
69
func getScopeInfo(s *log.Scope) *scopeInfo {
72
Description: s.Description(),
73
OutputLevel: levelToString[s.GetOutputLevel()],
74
StackTraceLevel: levelToString[s.GetStackTraceLevel()],
75
LogCallers: s.GetLogCallers(),
79
func (scopeTopic) Activate(context fw.TopicContext) {
80
tmpl := assets.ParseTemplate(context.Layout(), "templates/scopes.html")
82
_ = context.HTMLRouter().NewRoute().HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
83
allScopes := log.Scopes()
84
s := make([]scopeInfo, 0, len(allScopes))
85
for _, scope := range allScopes {
86
s = append(s, *getScopeInfo(scope))
88
sort.Slice(s, func(i, j int) bool {
89
return s[i].Name < s[j].Name
92
fw.RenderHTML(w, tmpl, s)
95
_ = context.JSONRouter().StrictSlash(true).NewRoute().Methods("GET").Path("/").HandlerFunc(getAllScopes)
96
_ = context.JSONRouter().NewRoute().Methods("GET").Path("/{scope}").HandlerFunc(getScope)
97
_ = context.JSONRouter().NewRoute().Methods("PUT").Path("/{scope}").HandlerFunc(putScope)
100
func getAllScopes(w http.ResponseWriter, _ *http.Request) {
101
allScopes := log.Scopes()
103
scopeInfos := make([]scopeInfo, 0, len(allScopes))
104
for _, s := range allScopes {
105
scopeInfos = append(scopeInfos, *getScopeInfo(s))
107
sort.Slice(scopeInfos, func(i, j int) bool {
108
return scopeInfos[i].Name < scopeInfos[j].Name
111
fw.RenderJSON(w, http.StatusOK, scopeInfos)
114
func getScope(w http.ResponseWriter, req *http.Request) {
115
vars := mux.Vars(req)
116
name := vars["scope"]
118
if s := log.FindScope(name); s != nil {
119
fw.RenderJSON(w, http.StatusOK, getScopeInfo(s))
123
fw.RenderError(w, http.StatusBadRequest, fmt.Errorf("unknown scope name: %s", name))
126
func putScope(w http.ResponseWriter, req *http.Request) {
127
vars := mux.Vars(req)
128
name := vars["scope"]
131
if err := json.NewDecoder(req.Body).Decode(&info); err != nil {
132
fw.RenderError(w, http.StatusBadRequest, fmt.Errorf("unable to decode request: %v", err))
136
if s := log.FindScope(name); s != nil {
137
level, ok := stringToLevel[info.OutputLevel]
139
s.SetOutputLevel(level)
142
level, ok = stringToLevel[info.StackTraceLevel]
144
s.SetStackTraceLevel(level)
147
s.SetLogCallers(info.LogCallers)
148
w.WriteHeader(http.StatusAccepted)
152
fw.RenderError(w, http.StatusBadRequest, fmt.Errorf("unknown scope name: %s", name))