├── .gitignore ├── LICENSE ├── README.md ├── config.go ├── console_writer.go ├── examples ├── conf │ ├── log.json │ └── main.go ├── console │ └── main.go ├── file │ └── main.go ├── logger │ └── main.go ├── multi │ └── main.go └── syslog │ └── main.go ├── file_writer.go ├── log.go └── syslog_writer.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, XiaoweiWu 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | log4go 2 | ====== 3 | 4 | Simple log library for Go language. 5 | 6 | ####Install 7 | 8 | go get github.com/skoo87/log4go 9 | 10 | ####Usages 11 | Refer to examples 12 | 13 | ####Features 14 | * Output log to file, the file can be rotated by itself. 15 | * Output log to console. 16 | * Output log to remote server with syslog protocol. 17 | 18 | 19 | ####TODO 20 | 1. ~~syslog~~ 21 | 2. udp/tcp writer 22 | 3. more of rules of log rotation 23 | 4. custom the format of log 24 | 25 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package log4go 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io/ioutil" 7 | ) 8 | 9 | type ConfFileWriter struct { 10 | LogPath string `json:"LogPath"` 11 | On bool `json:"On"` 12 | } 13 | 14 | type ConfConsoleWriter struct { 15 | On bool `json:"On"` 16 | Color bool `json:"Color"` 17 | } 18 | 19 | type LogConfig struct { 20 | Level string `json:"LogLevel"` 21 | FW ConfFileWriter `json:"FileWriter"` 22 | CW ConfConsoleWriter `json:"ConsoleWriter"` 23 | } 24 | 25 | func SetupLogWithConf(file string) (err error) { 26 | var lc LogConfig 27 | 28 | cnt, err := ioutil.ReadFile(file) 29 | 30 | if err = json.Unmarshal(cnt, &lc); err != nil { 31 | return 32 | } 33 | 34 | if lc.FW.On { 35 | w := NewFileWriter() 36 | w.SetPathPattern(lc.FW.LogPath) 37 | Register(w) 38 | } 39 | 40 | if lc.CW.On { 41 | w := NewConsoleWriter() 42 | w.SetColor(lc.CW.Color) 43 | Register(w) 44 | } 45 | 46 | switch lc.Level { 47 | case "debug": 48 | SetLevel(DEBUG) 49 | 50 | case "info": 51 | SetLevel(INFO) 52 | 53 | case "warning": 54 | SetLevel(WARNING) 55 | 56 | case "error": 57 | SetLevel(ERROR) 58 | 59 | case "fatal": 60 | SetLevel(FATAL) 61 | 62 | default: 63 | err = errors.New("Invalid log level") 64 | } 65 | return 66 | } 67 | -------------------------------------------------------------------------------- /console_writer.go: -------------------------------------------------------------------------------- 1 | package log4go 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | type colorRecord Record 9 | 10 | func (r *colorRecord) String() string { 11 | switch r.level { 12 | case DEBUG: 13 | return fmt.Sprintf("\033[36m%s\033[0m [\033[34m%s\033[0m] \033[47;30m%s\033[0m %s\n", 14 | r.time, LEVEL_FLAGS[r.level], r.code, r.info) 15 | 16 | case INFO: 17 | return fmt.Sprintf("\033[36m%s\033[0m [\033[32m%s\033[0m] \033[47;30m%s\033[0m %s\n", 18 | r.time, LEVEL_FLAGS[r.level], r.code, r.info) 19 | 20 | case WARNING: 21 | return fmt.Sprintf("\033[36m%s\033[0m [\033[33m%s\033[0m] \033[47;30m%s\033[0m %s\n", 22 | r.time, LEVEL_FLAGS[r.level], r.code, r.info) 23 | 24 | case ERROR: 25 | return fmt.Sprintf("\033[36m%s\033[0m [\033[31m%s\033[0m] \033[47;30m%s\033[0m %s\n", 26 | r.time, LEVEL_FLAGS[r.level], r.code, r.info) 27 | 28 | case FATAL: 29 | return fmt.Sprintf("\033[36m%s\033[0m [\033[35m%s\033[0m] \033[47;30m%s\033[0m %s\n", 30 | r.time, LEVEL_FLAGS[r.level], r.code, r.info) 31 | } 32 | 33 | return "" 34 | } 35 | 36 | type ConsoleWriter struct { 37 | color bool 38 | } 39 | 40 | func NewConsoleWriter() *ConsoleWriter { 41 | return &ConsoleWriter{} 42 | } 43 | 44 | func (w *ConsoleWriter) Write(r *Record) error { 45 | if w.color { 46 | fmt.Fprint(os.Stdout, ((*colorRecord)(r)).String()) 47 | } else { 48 | fmt.Fprint(os.Stdout, r.String()) 49 | } 50 | return nil 51 | } 52 | 53 | func (w *ConsoleWriter) Init() error { 54 | return nil 55 | } 56 | 57 | func (w *ConsoleWriter) SetColor(c bool) { 58 | w.color = c 59 | } 60 | -------------------------------------------------------------------------------- /examples/conf/log.json: -------------------------------------------------------------------------------- 1 | { 2 | "LogLevel" : "info", 3 | 4 | "FileWriter" : { 5 | "LogPath" : "/tmp/access-%Y%M%D.log", 6 | "On": true 7 | }, 8 | 9 | "ConsoleWriter" : { 10 | "On" : true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/conf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | log "log4go" 5 | ) 6 | 7 | func main() { 8 | if err := log.SetupLogWithConf("log.json"); err != nil { 9 | panic(err) 10 | } 11 | defer log.Close() 12 | 13 | var name = "skoo" 14 | log.Debug("log4go by %s", name) 15 | log.Info("log4go by %s", name) 16 | log.Warn("log4go by %s", name) 17 | log.Error("log4go by %s", name) 18 | log.Fatal("log4go by %s", name) 19 | } 20 | -------------------------------------------------------------------------------- /examples/console/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | log "log4go" 5 | ) 6 | 7 | func SetLog() { 8 | w := log.NewConsoleWriter() 9 | w.SetColor(true) 10 | 11 | log.Register(w) 12 | log.SetLevel(log.DEBUG) 13 | log.SetLayout("2006-01-02 15:04:05") 14 | } 15 | 16 | func main() { 17 | SetLog() 18 | defer log.Close() 19 | 20 | var name = "skoo" 21 | log.Debug("log4go by %s", name) 22 | log.Info("log4go by %s", name) 23 | log.Warn("log4go by %s", name) 24 | log.Error("log4go by %s", name) 25 | log.Fatal("log4go by %s", name) 26 | } 27 | -------------------------------------------------------------------------------- /examples/file/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | log "log4go" 5 | "time" 6 | ) 7 | 8 | func SetLog() { 9 | w := log.NewFileWriter() 10 | /* 11 | %Y year (eg: 2014) 12 | %M month (eg: 07) 13 | %D day (eg: 05) 14 | %H hour (eg: 18) 15 | %m minute (eg: 29) 16 | 17 | notice: No second's variable 18 | */ 19 | w.SetPathPattern("/tmp/logs/error%Y%M%D%H%m.log") 20 | 21 | log.Register(w) 22 | log.SetLevel(log.ERROR) 23 | } 24 | 25 | func main() { 26 | SetLog() 27 | defer log.Close() 28 | 29 | var name = "skoo" 30 | 31 | for { 32 | log.Debug("log4go by %s", name) 33 | log.Info("log4go by %s", name) 34 | log.Warn("log4go by %s", name) 35 | log.Error("log4go by %s", name) 36 | log.Fatal("log4go by %s", name) 37 | 38 | time.Sleep(time.Second * 1) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/logger/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log4go" 5 | ) 6 | 7 | func SetLog() (logger *log4go.Logger) { 8 | w := log4go.NewFileWriter() 9 | w.SetPathPattern("/tmp/logs/error%Y%M%D%H.log") 10 | 11 | logger = log4go.NewLogger() 12 | logger.Register(w) 13 | logger.SetLevel(log4go.ERROR) 14 | return 15 | } 16 | 17 | func main() { 18 | logger := SetLog() 19 | defer logger.Close() 20 | 21 | var name = "skoo" 22 | logger.Debug("log4go by %s", name) 23 | logger.Info("log4go by %s", name) 24 | logger.Warn("log4go by %s", name) 25 | logger.Error("log4go by %s", name) 26 | logger.Fatal("log4go by %s", name) 27 | } 28 | -------------------------------------------------------------------------------- /examples/multi/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | log "log4go" 5 | ) 6 | 7 | func SetLog() { 8 | w1 := log.NewFileWriter() 9 | w1.SetPathPattern("/tmp/logs/error%Y%M%D%H.log") 10 | 11 | w2 := log.NewConsoleWriter() 12 | 13 | log.Register(w1) 14 | log.Register(w2) 15 | log.SetLevel(log.ERROR) 16 | } 17 | 18 | func main() { 19 | SetLog() 20 | defer log.Close() 21 | 22 | var name = "skoo" 23 | log.Debug("log4go by %s", name) 24 | log.Info("log4go by %s", name) 25 | log.Warn("log4go by %s", name) 26 | log.Error("log4go by %s", name) 27 | log.Fatal("log4go by %s", name) 28 | } 29 | -------------------------------------------------------------------------------- /examples/syslog/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | log "log4go" 5 | ) 6 | 7 | func SetLog() { 8 | w := log.NewSyslogWriter() 9 | w.SetNetwork("udp") 10 | w.SetAddr("127.0.0.1:514") 11 | w.SetTag("log4go") 12 | 13 | log.Register(w) 14 | log.SetLevel(log.DEBUG) 15 | } 16 | 17 | func main() { 18 | SetLog() 19 | defer log.Close() 20 | 21 | var name = "skoo" 22 | log.Debug("log4go by %s", name) 23 | log.Info("log4go by %s", name) 24 | log.Warn("log4go by %s", name) 25 | log.Error("log4go by %s", name) 26 | log.Fatal("log4go by %s", name) 27 | } 28 | -------------------------------------------------------------------------------- /file_writer.go: -------------------------------------------------------------------------------- 1 | package log4go 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "os" 9 | "path" 10 | "time" 11 | ) 12 | 13 | var pathVariableTable map[byte]func(*time.Time) int 14 | 15 | type FileWriter struct { 16 | pathFmt string 17 | file *os.File 18 | fileBufWriter *bufio.Writer 19 | actions []func(*time.Time) int 20 | variables []interface{} 21 | } 22 | 23 | func NewFileWriter() *FileWriter { 24 | return &FileWriter{} 25 | } 26 | 27 | func (w *FileWriter) Init() error { 28 | return w.Rotate() 29 | } 30 | 31 | func (w *FileWriter) SetPathPattern(pattern string) error { 32 | n := 0 33 | for _, c := range pattern { 34 | if c == '%' { 35 | n++ 36 | } 37 | } 38 | 39 | if n == 0 { 40 | w.pathFmt = pattern 41 | return nil 42 | } 43 | 44 | w.actions = make([]func(*time.Time) int, 0, n) 45 | w.variables = make([]interface{}, n, n) 46 | tmp := []byte(pattern) 47 | 48 | variable := 0 49 | for _, c := range tmp { 50 | if variable == 1 { 51 | act, ok := pathVariableTable[c] 52 | if !ok { 53 | return errors.New("Invalid rotate pattern (" + pattern + ")") 54 | } 55 | w.actions = append(w.actions, act) 56 | variable = 0 57 | continue 58 | } 59 | if c == '%' { 60 | variable = 1 61 | } 62 | } 63 | 64 | w.pathFmt = convertPatternToFmt(tmp) 65 | 66 | return nil 67 | } 68 | 69 | func (w *FileWriter) Write(r *Record) error { 70 | if w.fileBufWriter == nil { 71 | return errors.New("no opened file") 72 | } 73 | if _, err := w.fileBufWriter.WriteString(r.String()); err != nil { 74 | return err 75 | } 76 | return nil 77 | } 78 | 79 | func (w *FileWriter) Rotate() error { 80 | now := time.Now() 81 | v := 0 82 | rotate := false 83 | 84 | for i, act := range w.actions { 85 | v = act(&now) 86 | if v != w.variables[i] { 87 | w.variables[i] = v 88 | rotate = true 89 | } 90 | } 91 | 92 | if rotate == false { 93 | return nil 94 | } 95 | 96 | if w.fileBufWriter != nil { 97 | if err := w.fileBufWriter.Flush(); err != nil { 98 | return err 99 | } 100 | } 101 | 102 | if w.file != nil { 103 | if err := w.file.Close(); err != nil { 104 | return err 105 | } 106 | } 107 | 108 | filePath := fmt.Sprintf(w.pathFmt, w.variables...) 109 | 110 | if err := os.MkdirAll(path.Dir(filePath), 0755); err != nil { 111 | if !os.IsExist(err) { 112 | return err 113 | } 114 | } 115 | 116 | if file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644); err != nil { 117 | return err 118 | } else { 119 | w.file = file 120 | } 121 | 122 | if w.fileBufWriter = bufio.NewWriterSize(w.file, 8192); w.fileBufWriter == nil { 123 | return errors.New("new fileBufWriter failed.") 124 | } 125 | 126 | return nil 127 | } 128 | 129 | func (w *FileWriter) Flush() error { 130 | if w.fileBufWriter != nil { 131 | return w.fileBufWriter.Flush() 132 | } 133 | return nil 134 | } 135 | 136 | func getYear(now *time.Time) int { 137 | return now.Year() 138 | } 139 | 140 | func getMonth(now *time.Time) int { 141 | return int(now.Month()) 142 | } 143 | 144 | func getDay(now *time.Time) int { 145 | return now.Day() 146 | } 147 | 148 | func getHour(now *time.Time) int { 149 | return now.Hour() 150 | } 151 | 152 | func getMin(now *time.Time) int { 153 | return now.Minute() 154 | } 155 | 156 | func convertPatternToFmt(pattern []byte) string { 157 | pattern = bytes.Replace(pattern, []byte("%Y"), []byte("%d"), -1) 158 | pattern = bytes.Replace(pattern, []byte("%M"), []byte("%02d"), -1) 159 | pattern = bytes.Replace(pattern, []byte("%D"), []byte("%02d"), -1) 160 | pattern = bytes.Replace(pattern, []byte("%H"), []byte("%02d"), -1) 161 | pattern = bytes.Replace(pattern, []byte("%m"), []byte("%02d"), -1) 162 | return string(pattern) 163 | } 164 | 165 | func init() { 166 | pathVariableTable = make(map[byte]func(*time.Time) int, 5) 167 | pathVariableTable['Y'] = getYear 168 | pathVariableTable['M'] = getMonth 169 | pathVariableTable['D'] = getDay 170 | pathVariableTable['H'] = getHour 171 | pathVariableTable['m'] = getMin 172 | } 173 | -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | package log4go 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "path" 7 | "runtime" 8 | "strconv" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | var ( 14 | LEVEL_FLAGS = [...]string{"DEBUG", " INFO", " WARN", "ERROR", "FATAL"} 15 | recordPool *sync.Pool 16 | ) 17 | 18 | const ( 19 | DEBUG = iota 20 | INFO 21 | WARNING 22 | ERROR 23 | FATAL 24 | ) 25 | 26 | const tunnel_size_default = 1024 27 | 28 | type Record struct { 29 | time string 30 | code string 31 | info string 32 | level int 33 | } 34 | 35 | func (r *Record) String() string { 36 | return fmt.Sprintf("%s [%s] <%s> %s\n", r.time, LEVEL_FLAGS[r.level], r.code, r.info) 37 | } 38 | 39 | type Writer interface { 40 | Init() error 41 | Write(*Record) error 42 | } 43 | 44 | type Rotater interface { 45 | Rotate() error 46 | SetPathPattern(string) error 47 | } 48 | 49 | type Flusher interface { 50 | Flush() error 51 | } 52 | 53 | type Logger struct { 54 | writers []Writer 55 | tunnel chan *Record 56 | level int 57 | lastTime int64 58 | lastTimeStr string 59 | c chan bool 60 | layout string 61 | } 62 | 63 | func NewLogger() *Logger { 64 | if logger_default != nil && takeup == false { 65 | takeup = true 66 | return logger_default 67 | } 68 | 69 | l := new(Logger) 70 | l.writers = make([]Writer, 0, 2) 71 | l.tunnel = make(chan *Record, tunnel_size_default) 72 | l.c = make(chan bool, 1) 73 | l.level = DEBUG 74 | l.layout = "2006/01/02 15:04:05" 75 | 76 | go boostrapLogWriter(l) 77 | 78 | return l 79 | } 80 | 81 | func (l *Logger) Register(w Writer) { 82 | if err := w.Init(); err != nil { 83 | panic(err) 84 | } 85 | l.writers = append(l.writers, w) 86 | } 87 | 88 | func (l *Logger) SetLevel(lvl int) { 89 | l.level = lvl 90 | } 91 | 92 | func (l *Logger) SetLayout(layout string) { 93 | l.layout = layout 94 | } 95 | 96 | func (l *Logger) Debug(fmt string, args ...interface{}) { 97 | l.deliverRecordToWriter(DEBUG, fmt, args...) 98 | } 99 | 100 | func (l *Logger) Warn(fmt string, args ...interface{}) { 101 | l.deliverRecordToWriter(WARNING, fmt, args...) 102 | } 103 | 104 | func (l *Logger) Info(fmt string, args ...interface{}) { 105 | l.deliverRecordToWriter(INFO, fmt, args...) 106 | } 107 | 108 | func (l *Logger) Error(fmt string, args ...interface{}) { 109 | l.deliverRecordToWriter(ERROR, fmt, args...) 110 | } 111 | 112 | func (l *Logger) Fatal(fmt string, args ...interface{}) { 113 | l.deliverRecordToWriter(FATAL, fmt, args...) 114 | } 115 | 116 | func (l *Logger) Close() { 117 | close(l.tunnel) 118 | <-l.c 119 | 120 | for _, w := range l.writers { 121 | if f, ok := w.(Flusher); ok { 122 | if err := f.Flush(); err != nil { 123 | log.Println(err) 124 | } 125 | } 126 | } 127 | } 128 | 129 | func (l *Logger) deliverRecordToWriter(level int, format string, args ...interface{}) { 130 | var inf, code string 131 | 132 | if level < l.level { 133 | return 134 | } 135 | 136 | if format != "" { 137 | inf = fmt.Sprintf(format, args...) 138 | } else { 139 | inf = fmt.Sprint(args...) 140 | } 141 | 142 | // source code, file and line num 143 | _, file, line, ok := runtime.Caller(2) 144 | if ok { 145 | code = path.Base(file) + ":" + strconv.Itoa(line) 146 | } 147 | 148 | // format time 149 | now := time.Now() 150 | if now.Unix() != l.lastTime { 151 | l.lastTime = now.Unix() 152 | l.lastTimeStr = now.Format(l.layout) 153 | } 154 | 155 | r := recordPool.Get().(*Record) 156 | r.info = inf 157 | r.code = code 158 | r.time = l.lastTimeStr 159 | r.level = level 160 | 161 | l.tunnel <- r 162 | } 163 | 164 | func boostrapLogWriter(logger *Logger) { 165 | if logger == nil { 166 | panic("logger is nil") 167 | } 168 | 169 | var ( 170 | r *Record 171 | ok bool 172 | ) 173 | 174 | if r, ok = <-logger.tunnel; !ok { 175 | logger.c <- true 176 | return 177 | } 178 | 179 | for _, w := range logger.writers { 180 | if err := w.Write(r); err != nil { 181 | log.Println(err) 182 | } 183 | } 184 | 185 | flushTimer := time.NewTimer(time.Millisecond * 500) 186 | rotateTimer := time.NewTimer(time.Second * 10) 187 | 188 | for { 189 | select { 190 | case r, ok = <-logger.tunnel: 191 | if !ok { 192 | logger.c <- true 193 | return 194 | } 195 | 196 | for _, w := range logger.writers { 197 | if err := w.Write(r); err != nil { 198 | log.Println(err) 199 | } 200 | } 201 | 202 | recordPool.Put(r) 203 | 204 | case <-flushTimer.C: 205 | for _, w := range logger.writers { 206 | if f, ok := w.(Flusher); ok { 207 | if err := f.Flush(); err != nil { 208 | log.Println(err) 209 | } 210 | } 211 | } 212 | flushTimer.Reset(time.Millisecond * 1000) 213 | 214 | case <-rotateTimer.C: 215 | for _, w := range logger.writers { 216 | if r, ok := w.(Rotater); ok { 217 | if err := r.Rotate(); err != nil { 218 | log.Println(err) 219 | } 220 | } 221 | } 222 | rotateTimer.Reset(time.Second * 10) 223 | } 224 | } 225 | } 226 | 227 | // default 228 | var ( 229 | logger_default *Logger 230 | takeup = false 231 | ) 232 | 233 | func SetLevel(lvl int) { 234 | logger_default.level = lvl 235 | } 236 | 237 | func SetLayout(layout string) { 238 | logger_default.layout = layout 239 | } 240 | 241 | func Debug(fmt string, args ...interface{}) { 242 | logger_default.deliverRecordToWriter(DEBUG, fmt, args...) 243 | } 244 | 245 | func Warn(fmt string, args ...interface{}) { 246 | logger_default.deliverRecordToWriter(WARNING, fmt, args...) 247 | } 248 | 249 | func Info(fmt string, args ...interface{}) { 250 | logger_default.deliverRecordToWriter(INFO, fmt, args...) 251 | } 252 | 253 | func Error(fmt string, args ...interface{}) { 254 | logger_default.deliverRecordToWriter(ERROR, fmt, args...) 255 | } 256 | 257 | func Fatal(fmt string, args ...interface{}) { 258 | logger_default.deliverRecordToWriter(FATAL, fmt, args...) 259 | } 260 | 261 | func Register(w Writer) { 262 | logger_default.Register(w) 263 | } 264 | 265 | func Close() { 266 | logger_default.Close() 267 | } 268 | 269 | func init() { 270 | logger_default = NewLogger() 271 | recordPool = &sync.Pool{New: func() interface{} { 272 | return &Record{} 273 | }} 274 | } 275 | -------------------------------------------------------------------------------- /syslog_writer.go: -------------------------------------------------------------------------------- 1 | package log4go 2 | 3 | import ( 4 | "errors" 5 | "log/syslog" 6 | ) 7 | 8 | type ShortRecord Record 9 | 10 | func (r *ShortRecord) String() string { 11 | return "<" + r.code + "> " + r.info 12 | } 13 | 14 | type SyslogWriter struct { 15 | network string 16 | addr string 17 | tag string 18 | writer *syslog.Writer 19 | } 20 | 21 | func NewSyslogWriter() *SyslogWriter { 22 | return &SyslogWriter{} 23 | } 24 | 25 | func (w *SyslogWriter) SetNetwork(network string) { 26 | w.network = network 27 | } 28 | 29 | func (w *SyslogWriter) SetAddr(addr string) { 30 | w.addr = addr 31 | } 32 | 33 | func (w *SyslogWriter) SetTag(tag string) { 34 | w.tag = tag 35 | } 36 | 37 | func (w *SyslogWriter) Init() (err error) { 38 | w.writer, err = syslog.Dial(w.network, w.addr, syslog.LOG_SYSLOG, w.tag) 39 | return 40 | } 41 | 42 | func (w *SyslogWriter) Write(r *Record) (err error) { 43 | s := ((*ShortRecord)(r)).String() 44 | 45 | switch r.level { 46 | case DEBUG: 47 | err = w.writer.Debug(s) 48 | 49 | case INFO: 50 | err = w.writer.Info(s) 51 | 52 | case WARNING: 53 | err = w.writer.Warning(s) 54 | 55 | case ERROR: 56 | err = w.writer.Err(s) 57 | 58 | case FATAL: 59 | err = w.writer.Crit(s) 60 | 61 | default: 62 | err = errors.New("Invalid level") 63 | } 64 | return 65 | } 66 | --------------------------------------------------------------------------------