github.com/ethersphere/bee/v2@v2.2.0/pkg/api/logger.go (about) 1 // Copyright 2022 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package api 6 7 import ( 8 "encoding/base64" 9 "fmt" 10 "net/http" 11 "regexp" 12 "strings" 13 14 "github.com/ethersphere/bee/v2/pkg/jsonhttp" 15 "github.com/ethersphere/bee/v2/pkg/log" 16 "github.com/gorilla/mux" 17 ) 18 19 // The following variables exist only to be mocked in tests. 20 var ( 21 logRegistryIterate = log.RegistryIterate 22 logSetVerbosityByExp = log.SetVerbosityByExp 23 ) 24 25 type ( 26 data struct { 27 Next node `json:"/,omitempty"` 28 Names []string `json:"+,omitempty"` 29 } 30 31 node map[string]*data 32 33 loggerInfo struct { 34 Logger string `json:"logger"` 35 Verbosity string `json:"verbosity"` 36 Subsystem string `json:"subsystem"` 37 ID string `json:"id"` 38 } 39 40 loggerResult struct { 41 Tree node `json:"tree"` 42 Loggers []loggerInfo `json:"loggers"` 43 } 44 ) 45 46 // loggerGetHandler returns all available loggers that match the specified expression. 47 func (s *Service) loggerGetHandler(w http.ResponseWriter, r *http.Request) { 48 logger := s.logger.WithName("get_loggers").Build() 49 50 paths := struct { 51 Exp string `map:"exp,decBase64url"` 52 }{} 53 if response := s.mapStructure(mux.Vars(r), &paths); response != nil { 54 response("invalid path params", logger, w) 55 return 56 } 57 58 rex, err := regexp.Compile(paths.Exp) 59 60 result := loggerResult{Tree: make(node)} 61 logRegistryIterate(func(id, name string, verbosity log.Level, v uint) bool { 62 if paths.Exp == id || (rex != nil && rex.MatchString(id)) { 63 if int(verbosity) == int(v) { 64 verbosity = log.VerbosityAll 65 } 66 67 // Tree structure. 68 curr := result.Tree 69 path := strings.Split(name, "/") 70 last := len(path) - 1 71 for i, n := range path { 72 if curr[n] == nil { 73 curr[n] = &data{Next: make(node)} 74 } 75 if i == last { 76 name := fmt.Sprintf("%s|%s", verbosity, id) 77 curr[n].Names = append(curr[n].Names, name) 78 } 79 curr = curr[n].Next 80 } 81 82 // Flat structure. 83 result.Loggers = append(result.Loggers, loggerInfo{ 84 Logger: name, 85 Verbosity: verbosity.String(), 86 Subsystem: id, 87 ID: base64.URLEncoding.EncodeToString([]byte(id)), 88 }) 89 } 90 return true 91 }) 92 93 if len(result.Loggers) == 0 && err != nil { 94 logger.Debug("invalid path params", "error", err) 95 logger.Error(nil, "invalid path params") 96 jsonhttp.BadRequest(w, jsonhttp.StatusResponse{ 97 Message: "invalid path params", 98 Code: http.StatusBadRequest, 99 Reasons: []jsonhttp.Reason{{ 100 Field: "exp", 101 Error: err.Error(), 102 }}, 103 }) 104 } else { 105 jsonhttp.OK(w, result) 106 } 107 } 108 109 // loggerSetVerbosityHandler sets logger(s) verbosity level based on 110 // the specified expression or subsystem that matches the logger(s). 111 func (s *Service) loggerSetVerbosityHandler(w http.ResponseWriter, r *http.Request) { 112 logger := s.logger.WithName("put_loggers").Build() 113 114 paths := struct { 115 Exp string `map:"exp,decBase64url" validate:"required"` 116 Verbosity string `map:"verbosity" validate:"required,oneof=none error warning info debug all"` 117 }{} 118 if response := s.mapStructure(mux.Vars(r), &paths); response != nil { 119 response("invalid path params", logger, w) 120 return 121 } 122 123 if err := logSetVerbosityByExp(paths.Exp, log.MustParseVerbosityLevel(paths.Verbosity)); err != nil { 124 logger.Debug("invalid path params", "error", err) 125 logger.Error(nil, "invalid path params") 126 jsonhttp.BadRequest(w, jsonhttp.StatusResponse{ 127 Message: "invalid path params", 128 Code: http.StatusBadRequest, 129 Reasons: []jsonhttp.Reason{{ 130 Field: "exp", 131 Error: err.Error(), 132 }}, 133 }) 134 } else { 135 jsonhttp.OK(w, nil) 136 } 137 }