1 // Copyright 2015 CoreOS, Inc.
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 // LogLevel is the set of all log levels.
27 // CRITICAL is the lowest log level; only errors which will end the program will be propagated.
28 CRITICAL LogLevel = iota - 1
29 // ERROR is for errors that are not fatal but lead to troubling behavior.
31 // WARNING is for errors which are not fatal and not errors, but are unusual. Often sourced from misconfigurations.
33 // NOTICE is for normal but significant conditions.
35 // INFO is a log level for common, everyday log updates.
37 // DEBUG is the default hidden level for more verbose updates about internal processes.
39 // TRACE is for (potentially) call by call tracing of programs.
43 // Char returns a single-character representation of the log level.
44 func (l LogLevel) Char() string {
61 panic("Unhandled loglevel")
65 // String returns a multi-character representation of the log level.
66 func (l LogLevel) String() string {
83 panic("Unhandled loglevel")
87 // Update using the given string value. Fulfills the flag.Value interface.
88 func (l *LogLevel) Set(s string) error {
89 value, err := ParseLevel(s)
98 // ParseLevel translates some potential loglevel strings into their corresponding levels.
99 func ParseLevel(s string) (LogLevel, error) {
101 case "CRITICAL", "C":
103 case "ERROR", "0", "E":
105 case "WARNING", "1", "W":
107 case "NOTICE", "2", "N":
109 case "INFO", "3", "I":
111 case "DEBUG", "4", "D":
113 case "TRACE", "5", "T":
116 return CRITICAL, errors.New("couldn't parse log level " + s)
119 type RepoLogger map[string]*PackageLogger
121 type loggerStruct struct {
123 repoMap map[string]RepoLogger
127 // logger is the global logger
128 var logger = new(loggerStruct)
130 // SetGlobalLogLevel sets the log level for all packages in all repositories
131 // registered with capnslog.
132 func SetGlobalLogLevel(l LogLevel) {
134 defer logger.Unlock()
135 for _, r := range logger.repoMap {
136 r.setRepoLogLevelInternal(l)
140 // GetRepoLogger may return the handle to the repository's set of packages' loggers.
141 func GetRepoLogger(repo string) (RepoLogger, error) {
143 defer logger.Unlock()
144 r, ok := logger.repoMap[repo]
146 return nil, errors.New("no packages registered for repo " + repo)
151 // MustRepoLogger returns the handle to the repository's packages' loggers.
152 func MustRepoLogger(repo string) RepoLogger {
153 r, err := GetRepoLogger(repo)
160 // SetRepoLogLevel sets the log level for all packages in the repository.
161 func (r RepoLogger) SetRepoLogLevel(l LogLevel) {
163 defer logger.Unlock()
164 r.setRepoLogLevelInternal(l)
167 func (r RepoLogger) setRepoLogLevelInternal(l LogLevel) {
168 for _, v := range r {
173 // ParseLogLevelConfig parses a comma-separated string of "package=loglevel", in
174 // order, and returns a map of the results, for use in SetLogLevel.
175 func (r RepoLogger) ParseLogLevelConfig(conf string) (map[string]LogLevel, error) {
176 setlist := strings.Split(conf, ",")
177 out := make(map[string]LogLevel)
178 for _, setstring := range setlist {
179 setting := strings.Split(setstring, "=")
180 if len(setting) != 2 {
181 return nil, errors.New("oddly structured `pkg=level` option: " + setstring)
183 l, err := ParseLevel(setting[1])
192 // SetLogLevel takes a map of package names within a repository to their desired
193 // loglevel, and sets the levels appropriately. Unknown packages are ignored.
194 // "*" is a special package name that corresponds to all packages, and will be
196 func (r RepoLogger) SetLogLevel(m map[string]LogLevel) {
198 defer logger.Unlock()
199 if l, ok := m["*"]; ok {
200 r.setRepoLogLevelInternal(l)
202 for k, v := range m {
211 // SetFormatter sets the formatting function for all logs.
212 func SetFormatter(f Formatter) {
214 defer logger.Unlock()
218 // NewPackageLogger creates a package logger object.
219 // This should be defined as a global var in your package, referencing your repo.
220 func NewPackageLogger(repo string, pkg string) (p *PackageLogger) {
222 defer logger.Unlock()
223 if logger.repoMap == nil {
224 logger.repoMap = make(map[string]RepoLogger)
226 r, rok := logger.repoMap[repo]
228 logger.repoMap[repo] = make(RepoLogger)
229 r = logger.repoMap[repo]
233 r[pkg] = &PackageLogger{