1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package textlogger 18 19 import ( 20 "flag" 21 "io" 22 "os" 23 "strconv" 24 "time" 25 26 "k8s.io/klog/v2/internal/verbosity" 27 ) 28 29 // Config influences logging in a text logger. To make this configurable via 30 // command line flags, instantiate this once per program and use AddFlags to 31 // bind command line flags to the instance before passing it to NewTestContext. 32 // 33 // Must be constructed with NewConfig. 34 type Config struct { 35 vstate *verbosity.VState 36 co configOptions 37 } 38 39 // Verbosity returns a value instance that can be used to query (via String) or 40 // modify (via Set) the verbosity threshold. This is thread-safe and can be 41 // done at runtime. 42 func (c *Config) Verbosity() flag.Value { 43 return c.vstate.V() 44 } 45 46 // VModule returns a value instance that can be used to query (via String) or 47 // modify (via Set) the vmodule settings. This is thread-safe and can be done 48 // at runtime. 49 func (c *Config) VModule() flag.Value { 50 return c.vstate.VModule() 51 } 52 53 // ConfigOption implements functional parameters for NewConfig. 54 type ConfigOption func(co *configOptions) 55 56 type configOptions struct { 57 verbosityFlagName string 58 vmoduleFlagName string 59 verbosityDefault int 60 fixedTime *time.Time 61 unwind func(int) (string, int) 62 output io.Writer 63 } 64 65 // VerbosityFlagName overrides the default -v for the verbosity level. 66 func VerbosityFlagName(name string) ConfigOption { 67 return func(co *configOptions) { 68 69 co.verbosityFlagName = name 70 } 71 } 72 73 // VModulFlagName overrides the default -vmodule for the per-module 74 // verbosity levels. 75 func VModuleFlagName(name string) ConfigOption { 76 return func(co *configOptions) { 77 co.vmoduleFlagName = name 78 } 79 } 80 81 // Verbosity overrides the default verbosity level of 0. 82 // See https://github.com/kubernetes/community/blob/9406b4352fe2d5810cb21cc3cb059ce5886de157/contributors/devel/sig-instrumentation/logging.md#logging-conventions 83 // for log level conventions in Kubernetes. 84 func Verbosity(level int) ConfigOption { 85 return func(co *configOptions) { 86 co.verbosityDefault = level 87 } 88 } 89 90 // Output overrides stderr as the output stream. 91 func Output(output io.Writer) ConfigOption { 92 return func(co *configOptions) { 93 co.output = output 94 } 95 } 96 97 // FixedTime overrides the actual time with a fixed time. Useful only for testing. 98 // 99 // # Experimental 100 // 101 // Notice: This function is EXPERIMENTAL and may be changed or removed in a 102 // later release. 103 func FixedTime(ts time.Time) ConfigOption { 104 return func(co *configOptions) { 105 co.fixedTime = &ts 106 } 107 } 108 109 // Backtrace overrides the default mechanism for determining the call site. 110 // The callback is invoked with the number of function calls between itself 111 // and the call site. It must return the file name and line number. An empty 112 // file name indicates that the information is unknown. 113 // 114 // # Experimental 115 // 116 // Notice: This function is EXPERIMENTAL and may be changed or removed in a 117 // later release. 118 func Backtrace(unwind func(skip int) (filename string, line int)) ConfigOption { 119 return func(co *configOptions) { 120 co.unwind = unwind 121 } 122 } 123 124 // NewConfig returns a configuration with recommended defaults and optional 125 // modifications. Command line flags are not bound to any FlagSet yet. 126 func NewConfig(opts ...ConfigOption) *Config { 127 c := &Config{ 128 vstate: verbosity.New(), 129 co: configOptions{ 130 verbosityFlagName: "v", 131 vmoduleFlagName: "vmodule", 132 verbosityDefault: 0, 133 unwind: runtimeBacktrace, 134 output: os.Stderr, 135 }, 136 } 137 for _, opt := range opts { 138 opt(&c.co) 139 } 140 141 // Cannot fail for this input. 142 _ = c.Verbosity().Set(strconv.FormatInt(int64(c.co.verbosityDefault), 10)) 143 return c 144 } 145 146 // AddFlags registers the command line flags that control the configuration. 147 // 148 // The default flag names are the same as in klog, so unless those defaults 149 // are changed, either klog.InitFlags or Config.AddFlags can be used for the 150 // same flag set, but not both. 151 func (c *Config) AddFlags(fs *flag.FlagSet) { 152 fs.Var(c.Verbosity(), c.co.verbosityFlagName, "number for the log level verbosity of the testing logger") 153 fs.Var(c.VModule(), c.co.vmoduleFlagName, "comma-separated list of pattern=N log level settings for files matching the patterns") 154 } 155