├── example └── example.go ├── logger └── logger.go └── readme.markdown /example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "github.com/jander/golog/logger" 6 | "log" 7 | "os" 8 | ) 9 | 10 | // This will run untill press enter key 11 | 12 | func main() { 13 | rotatingHandler := logger.NewRotatingHandler(".", "test.log", 4, 4*1024*1024) 14 | 15 | logger.SetHandlers(logger.Console, rotatingHandler) 16 | 17 | defer logger.Close() 18 | 19 | logger.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 20 | 21 | //logger.DEBUG is default, nosense here. 22 | logger.SetLevel(logger.DEBUG) 23 | 24 | for i := 0; i < 10; i++ { 25 | go func(num int) { 26 | count := 0 27 | for { 28 | logger.Debug("log", num, "-", count) 29 | count++ 30 | } 31 | }(i) 32 | } 33 | 34 | reader := bufio.NewReader(os.Stdin) 35 | reader.ReadString('\n') 36 | } 37 | -------------------------------------------------------------------------------- /logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "os" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | type Level int32 13 | 14 | const ( 15 | DEBUG Level = iota 16 | INFO 17 | WARN 18 | ERROR 19 | ) 20 | 21 | /* 22 | =================== 23 | utils functions 24 | =================== 25 | */ 26 | func fileSize(file string) int64 { 27 | fmt.Println("fileSize", file) 28 | f, e := os.Stat(file) 29 | if e != nil { 30 | fmt.Println(e.Error()) 31 | return 0 32 | } 33 | return f.Size() 34 | } 35 | 36 | func isExist(path string) bool { 37 | _, err := os.Stat(path) 38 | return err == nil || os.IsExist(err) 39 | } 40 | 41 | /* 42 | =================== 43 | log handlers 44 | =================== 45 | */ 46 | type Handler interface { 47 | SetOutput(w io.Writer) 48 | Output(calldepth int, s string) error 49 | Printf(format string, v ...interface{}) 50 | Print(v ...interface{}) 51 | Println(v ...interface{}) 52 | Fatal(v ...interface{}) 53 | Fatalf(format string, v ...interface{}) 54 | Fatalln(v ...interface{}) 55 | 56 | Debug(v ...interface{}) 57 | Info(v ...interface{}) 58 | Warn(v ...interface{}) 59 | Error(v ...interface{}) 60 | 61 | Flags() int 62 | SetFlags(flag int) 63 | Prefix() string 64 | SetPrefix(prefix string) 65 | close() 66 | } 67 | 68 | type LogHandler struct { 69 | lg *log.Logger 70 | } 71 | 72 | type ConsoleHander struct { 73 | LogHandler 74 | } 75 | 76 | type FileHandler struct { 77 | LogHandler 78 | logfile *os.File 79 | } 80 | 81 | type RotatingHandler struct { 82 | LogHandler 83 | dir string 84 | filename string 85 | maxNum int 86 | maxSize int64 87 | suffix int 88 | logfile *os.File 89 | mu sync.Mutex 90 | } 91 | 92 | var Console = NewConsoleHandler() 93 | 94 | func NewConsoleHandler() *ConsoleHander { 95 | l := log.New(os.Stderr, "", log.LstdFlags) 96 | return &ConsoleHander{LogHandler: LogHandler{l}} 97 | } 98 | 99 | func NewFileHandler(filepath string) *FileHandler { 100 | logfile, _ := os.OpenFile(filepath, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) 101 | l := log.New(logfile, "", log.LstdFlags) 102 | return &FileHandler{ 103 | LogHandler: LogHandler{l}, 104 | logfile: logfile, 105 | } 106 | } 107 | 108 | func NewRotatingHandler(dir string, filename string, maxNum int, maxSize int64) *RotatingHandler { 109 | logfile, _ := os.OpenFile(dir+"/"+filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666) 110 | l := log.New(logfile, "", log.LstdFlags) 111 | 112 | h := &RotatingHandler{ 113 | LogHandler: LogHandler{l}, 114 | dir: dir, 115 | filename: filename, 116 | maxNum: maxNum, 117 | maxSize: maxSize, 118 | suffix: 0, 119 | } 120 | 121 | if h.isMustRename() { 122 | h.rename() 123 | } else { 124 | h.mu.Lock() 125 | defer h.mu.Unlock() 126 | h.lg.SetOutput(logfile) 127 | } 128 | 129 | // monitor filesize per second 130 | go func() { 131 | timer := time.NewTicker(1 * time.Second) 132 | for { 133 | select { 134 | case <-timer.C: 135 | h.fileCheck() 136 | } 137 | } 138 | }() 139 | 140 | return h 141 | } 142 | 143 | func (l *LogHandler) SetOutput(w io.Writer) { 144 | l.lg.SetOutput(w) 145 | } 146 | 147 | func (l *LogHandler) Output(calldepth int, s string) error { 148 | return l.lg.Output(calldepth, s) 149 | } 150 | 151 | func (l *LogHandler) Printf(format string, v ...interface{}) { 152 | l.lg.Printf(format, v...) 153 | } 154 | 155 | func (l *LogHandler) Print(v ...interface{}) { l.lg.Print(v...) } 156 | 157 | func (l *LogHandler) Println(v ...interface{}) { l.lg.Println(v...) } 158 | 159 | func (l *LogHandler) Fatal(v ...interface{}) { 160 | l.lg.Output(2, fmt.Sprint(v...)) 161 | } 162 | 163 | func (l *LogHandler) Fatalf(format string, v ...interface{}) { 164 | l.lg.Output(2, fmt.Sprintf(format, v...)) 165 | } 166 | 167 | func (l *LogHandler) Fatalln(v ...interface{}) { 168 | l.lg.Output(2, fmt.Sprintln(v...)) 169 | } 170 | 171 | func (l *LogHandler) Flags() int { 172 | return l.lg.Flags() 173 | } 174 | 175 | func (l *LogHandler) SetFlags(flag int) { 176 | l.lg.SetFlags(flag) 177 | } 178 | 179 | func (l *LogHandler) Prefix() string { 180 | return l.lg.Prefix() 181 | } 182 | 183 | func (l *LogHandler) SetPrefix(prefix string) { 184 | l.lg.SetPrefix(prefix) 185 | } 186 | 187 | func (l *LogHandler) Debug(v ...interface{}) { 188 | l.lg.Output(2, fmt.Sprintln("debug", v)) 189 | } 190 | 191 | func (l *LogHandler) Info(v ...interface{}) { 192 | l.lg.Output(2, fmt.Sprintln("info", v)) 193 | } 194 | 195 | func (l *LogHandler) Warn(v ...interface{}) { 196 | l.lg.Output(2, fmt.Sprintln("warn", v)) 197 | } 198 | 199 | func (l *LogHandler) Error(v ...interface{}) { 200 | l.lg.Output(2, fmt.Sprintln("error", v)) 201 | } 202 | 203 | func (l *LogHandler) close() { 204 | 205 | } 206 | 207 | func (h *FileHandler) close() { 208 | if h.logfile != nil { 209 | h.logfile.Close() 210 | } 211 | } 212 | 213 | func (h *RotatingHandler) close() { 214 | if h.logfile != nil { 215 | h.logfile.Close() 216 | } 217 | } 218 | 219 | func (h *RotatingHandler) isMustRename() bool { 220 | if h.maxNum > 1 { 221 | if fileSize(h.dir+"/"+h.filename) >= h.maxSize { 222 | return true 223 | } 224 | } 225 | return false 226 | } 227 | 228 | func (h *RotatingHandler) rename() { 229 | h.suffix = h.suffix%h.maxNum + 1 230 | 231 | if h.logfile != nil { 232 | h.logfile.Close() 233 | } 234 | 235 | newpath := fmt.Sprintf("%s/%s.%d.log", h.dir, h.filename, h.suffix) 236 | if isExist(newpath) { 237 | os.Remove(newpath) 238 | } 239 | 240 | h.mu.Lock() 241 | defer h.mu.Unlock() 242 | 243 | filepath := h.dir + "/" + h.filename 244 | os.Rename(filepath, newpath) 245 | h.logfile, _ = os.Create(filepath) 246 | h.lg.SetOutput(h.logfile) 247 | } 248 | 249 | func (h *RotatingHandler) fileCheck() { 250 | defer func() { 251 | if err := recover(); err != nil { 252 | log.Println(err) 253 | } 254 | }() 255 | if h.isMustRename() { 256 | h.rename() 257 | } 258 | } 259 | 260 | /* 261 | =================== 262 | logger 263 | =================== 264 | */ 265 | type _Logger struct { 266 | handlers []Handler 267 | level Level 268 | mu sync.Mutex 269 | } 270 | 271 | var logger = &_Logger{ 272 | handlers: []Handler{ 273 | Console, 274 | }, 275 | level: DEBUG, 276 | } 277 | 278 | func SetHandlers(handlers ...Handler) { 279 | logger.handlers = handlers 280 | } 281 | 282 | func SetFlags(flag int) { 283 | for i := range logger.handlers { 284 | logger.handlers[i].SetFlags(flag) 285 | } 286 | } 287 | 288 | func SetLevel(level Level) { 289 | logger.level = level 290 | } 291 | 292 | func Print(v ...interface{}) { 293 | for i := range logger.handlers { 294 | logger.handlers[i].Print(v...) 295 | } 296 | } 297 | 298 | func Printf(format string, v ...interface{}) { 299 | for i := range logger.handlers { 300 | logger.handlers[i].Printf(format, v...) 301 | } 302 | } 303 | 304 | func Println(v ...interface{}) { 305 | for i := range logger.handlers { 306 | logger.handlers[i].Println(v...) 307 | } 308 | } 309 | 310 | func Fatal(v ...interface{}) { 311 | for i := range logger.handlers { 312 | logger.handlers[i].Fatal(v...) 313 | } 314 | os.Exit(1) 315 | } 316 | 317 | func Fatalf(format string, v ...interface{}) { 318 | for i := range logger.handlers { 319 | logger.handlers[i].Fatalf(format, v...) 320 | } 321 | os.Exit(1) 322 | } 323 | 324 | func Fatalln(v ...interface{}) { 325 | for i := range logger.handlers { 326 | logger.handlers[i].Fatalln(v...) 327 | } 328 | os.Exit(1) 329 | } 330 | 331 | func Panic(v ...interface{}) { 332 | s := fmt.Sprint(v...) 333 | for i := range logger.handlers { 334 | logger.handlers[i].Output(2, s) 335 | } 336 | panic(s) 337 | } 338 | 339 | func Panicf(format string, v ...interface{}) { 340 | s := fmt.Sprintf(format, v...) 341 | for i := range logger.handlers { 342 | logger.handlers[i].Output(2, s) 343 | } 344 | panic(s) 345 | } 346 | 347 | func Panicln(v ...interface{}) { 348 | s := fmt.Sprintln(v...) 349 | for i := range logger.handlers { 350 | logger.handlers[i].Output(2, s) 351 | } 352 | panic(s) 353 | } 354 | 355 | func Debug(v ...interface{}) { 356 | if logger.level <= DEBUG { 357 | for i := range logger.handlers { 358 | logger.handlers[i].Debug(v...) 359 | } 360 | } 361 | } 362 | 363 | func Info(v ...interface{}) { 364 | if logger.level <= INFO { 365 | for i := range logger.handlers { 366 | logger.handlers[i].Info(v...) 367 | } 368 | } 369 | } 370 | 371 | func Warn(v ...interface{}) { 372 | if logger.level <= WARN { 373 | for i := range logger.handlers { 374 | logger.handlers[i].Warn(v...) 375 | } 376 | } 377 | } 378 | 379 | func Error(v ...interface{}) { 380 | if logger.level <= ERROR { 381 | for i := range logger.handlers { 382 | logger.handlers[i].Error(v...) 383 | } 384 | } 385 | } 386 | 387 | func Close() { 388 | for i := range logger.handlers { 389 | logger.handlers[i].close() 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # Golog 2 | 3 | Golog is a simple log for golang. 4 | 5 | ## Features 6 | 7 | - log levels: DEBUG, INFO, WARN, ERROR 8 | - deferent log handlers: ConsoleHander, FileHandler, RotatingHandler 9 | - basic on golang inner pkg - log 10 | 11 | ## Installation 12 | 13 | go get github.com/jander/golog/logger 14 | 15 | ## Example 16 | 17 | // rotating hander, max log files is 4, max file size is 4M 18 | rotatingHandler := logger.NewRotatingHandler("./", "test.log", 4, 4*1024*1024) 19 | 20 | // logger set handlers: console, rotating 21 | logger.SetHandlers(logger.Console, rotatingHandler) 22 | 23 | defer logger.Close() 24 | 25 | // logger set flags 26 | logger.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 27 | 28 | // logger set log level 29 | logger.SetLevel(logger.INFO) 30 | 31 | logger.Debug("something", "debug") 32 | logger.Info("something") 33 | logger.Warn("something") 34 | logger.Error("something") 35 | 36 | ## License 37 | 38 | Golog is available under the MIT License. 39 | 40 | --------------------------------------------------------------------------------