| // Copyright 2015 CoreOS, Inc. |
| // |
| // 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 capnslog |
| |
| import ( |
| "bufio" |
| "fmt" |
| "io" |
| "log" |
| "runtime" |
| "strings" |
| "time" |
| ) |
| |
| type Formatter interface { |
| Format(pkg string, level LogLevel, depth int, entries ...interface{}) |
| Flush() |
| } |
| |
| func NewStringFormatter(w io.Writer) Formatter { |
| return &StringFormatter{ |
| w: bufio.NewWriter(w), |
| } |
| } |
| |
| type StringFormatter struct { |
| w *bufio.Writer |
| } |
| |
| func (s *StringFormatter) Format(pkg string, l LogLevel, i int, entries ...interface{}) { |
| now := time.Now().UTC() |
| s.w.WriteString(now.Format(time.RFC3339)) |
| s.w.WriteByte(' ') |
| writeEntries(s.w, pkg, l, i, entries...) |
| s.Flush() |
| } |
| |
| func writeEntries(w *bufio.Writer, pkg string, _ LogLevel, _ int, entries ...interface{}) { |
| if pkg != "" { |
| w.WriteString(pkg + ": ") |
| } |
| str := fmt.Sprint(entries...) |
| endsInNL := strings.HasSuffix(str, "\n") |
| w.WriteString(str) |
| if !endsInNL { |
| w.WriteString("\n") |
| } |
| } |
| |
| func (s *StringFormatter) Flush() { |
| s.w.Flush() |
| } |
| |
| func NewPrettyFormatter(w io.Writer, debug bool) Formatter { |
| return &PrettyFormatter{ |
| w: bufio.NewWriter(w), |
| debug: debug, |
| } |
| } |
| |
| type PrettyFormatter struct { |
| w *bufio.Writer |
| debug bool |
| } |
| |
| func (c *PrettyFormatter) Format(pkg string, l LogLevel, depth int, entries ...interface{}) { |
| now := time.Now() |
| ts := now.Format("2006-01-02 15:04:05") |
| c.w.WriteString(ts) |
| ms := now.Nanosecond() / 1000 |
| c.w.WriteString(fmt.Sprintf(".%06d", ms)) |
| if c.debug { |
| _, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call. |
| if !ok { |
| file = "???" |
| line = 1 |
| } else { |
| slash := strings.LastIndex(file, "/") |
| if slash >= 0 { |
| file = file[slash+1:] |
| } |
| } |
| if line < 0 { |
| line = 0 // not a real line number |
| } |
| c.w.WriteString(fmt.Sprintf(" [%s:%d]", file, line)) |
| } |
| c.w.WriteString(fmt.Sprint(" ", l.Char(), " | ")) |
| writeEntries(c.w, pkg, l, depth, entries...) |
| c.Flush() |
| } |
| |
| func (c *PrettyFormatter) Flush() { |
| c.w.Flush() |
| } |
| |
| // LogFormatter emulates the form of the traditional built-in logger. |
| type LogFormatter struct { |
| logger *log.Logger |
| prefix string |
| } |
| |
| // NewLogFormatter is a helper to produce a new LogFormatter struct. It uses the |
| // golang log package to actually do the logging work so that logs look similar. |
| func NewLogFormatter(w io.Writer, prefix string, flag int) Formatter { |
| return &LogFormatter{ |
| logger: log.New(w, "", flag), // don't use prefix here |
| prefix: prefix, // save it instead |
| } |
| } |
| |
| // Format builds a log message for the LogFormatter. The LogLevel is ignored. |
| func (lf *LogFormatter) Format(pkg string, _ LogLevel, _ int, entries ...interface{}) { |
| str := fmt.Sprint(entries...) |
| prefix := lf.prefix |
| if pkg != "" { |
| prefix = fmt.Sprintf("%s%s: ", prefix, pkg) |
| } |
| lf.logger.Output(5, fmt.Sprintf("%s%v", prefix, str)) // call depth is 5 |
| } |
| |
| // Flush is included so that the interface is complete, but is a no-op. |
| func (lf *LogFormatter) Flush() { |
| // noop |
| } |
| |
| // NilFormatter is a no-op log formatter that does nothing. |
| type NilFormatter struct { |
| } |
| |
| // NewNilFormatter is a helper to produce a new LogFormatter struct. It logs no |
| // messages so that you can cause part of your logging to be silent. |
| func NewNilFormatter() Formatter { |
| return &NilFormatter{} |
| } |
| |
| // Format does nothing. |
| func (_ *NilFormatter) Format(_ string, _ LogLevel, _ int, _ ...interface{}) { |
| // noop |
| } |
| |
| // Flush is included so that the interface is complete, but is a no-op. |
| func (_ *NilFormatter) Flush() { |
| // noop |
| } |