├── example.conf ├── .travis.yml ├── .gitignore ├── vendor ├── github.com │ ├── kardianos │ │ └── osext │ │ │ ├── osext_plan9.go │ │ │ ├── README.md │ │ │ ├── osext_windows.go │ │ │ ├── osext.go │ │ │ ├── osext_procfs.go │ │ │ ├── LICENSE │ │ │ └── osext_sysctl.go │ └── ccding │ │ └── go-config-reader │ │ ├── config │ │ └── config.go │ │ └── LICENSE └── vendor.json ├── logging ├── request.go ├── fields_test.go ├── logging_test.go ├── level.go ├── formater.go ├── commands.go ├── writer.go ├── fields.go └── logging.go ├── example.go ├── README.md └── LICENSE /example.conf: -------------------------------------------------------------------------------- 1 | name = logger3 2 | sync = 0 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 1.6 3 | script: go test -v ./logging 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Temporary files for running example 2 | go-logging 3 | logging.log 4 | 5 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 6 | *.o 7 | *.a 8 | *.so 9 | 10 | # Folders 11 | _obj 12 | _test 13 | 14 | # Architecture specific extensions/prefixes 15 | *.[568vq] 16 | [568vq].out 17 | 18 | *.cgo1.go 19 | *.cgo2.c 20 | _cgo_defun.c 21 | _cgo_gotypes.go 22 | _cgo_export.* 23 | 24 | _testmain.go 25 | 26 | *.exe 27 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_plan9.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package osext 6 | 7 | import ( 8 | "os" 9 | "strconv" 10 | "syscall" 11 | ) 12 | 13 | func executable() (string, error) { 14 | f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") 15 | if err != nil { 16 | return "", err 17 | } 18 | defer f.Close() 19 | return syscall.Fd2path(int(f.Fd())) 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/README.md: -------------------------------------------------------------------------------- 1 | ### Extensions to the "os" package. 2 | 3 | ## Find the current Executable and ExecutableFolder. 4 | 5 | There is sometimes utility in finding the current executable file 6 | that is running. This can be used for upgrading the current executable 7 | or finding resources located relative to the executable file. Both 8 | working directory and the os.Args[0] value are arbitrary and cannot 9 | be relied on; os.Args[0] can be "faked". 10 | 11 | Multi-platform and supports: 12 | * Linux 13 | * OS X 14 | * Windows 15 | * Plan 9 16 | * BSDs. 17 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "ignore": "test", 4 | "package": [ 5 | { 6 | "checksumSHA1": "V5fI1L0jZRkPPx0NRSLe3Eqefd0=", 7 | "path": "github.com/ccding/go-config-reader/config", 8 | "revision": "8b6c2b50197f20da3b1c5944c274c173634dc056", 9 | "revisionTime": "2013-08-17T22:59:50Z" 10 | }, 11 | { 12 | "checksumSHA1": "6nmAJBw2phU9MUmkUnqFvbO5urg=", 13 | "path": "github.com/kardianos/osext", 14 | "revision": "29ae4ffbc9a6fe9fb2bc5029050ce6996ea1d3bc", 15 | "revisionTime": "2015-12-22T15:32:29Z" 16 | } 17 | ], 18 | "rootPath": "github.com/ccding/go-logging" 19 | } 20 | -------------------------------------------------------------------------------- /logging/request.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | // request struct stores the logger request 20 | type request struct { 21 | level Level 22 | format string 23 | v []interface{} 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package osext 6 | 7 | import ( 8 | "syscall" 9 | "unicode/utf16" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | kernel = syscall.MustLoadDLL("kernel32.dll") 15 | getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") 16 | ) 17 | 18 | // GetModuleFileName() with hModule = NULL 19 | func executable() (exePath string, err error) { 20 | return getModuleFileName() 21 | } 22 | 23 | func getModuleFileName() (string, error) { 24 | var n uint32 25 | b := make([]uint16, syscall.MAX_PATH) 26 | size := uint32(len(b)) 27 | 28 | r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) 29 | n = uint32(r0) 30 | if n == 0 { 31 | return "", e1 32 | } 33 | return string(utf16.Decode(b[0:n])), nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Extensions to the standard "os" package. 6 | package osext // import "github.com/kardianos/osext" 7 | 8 | import "path/filepath" 9 | 10 | var cx, ce = executableClean() 11 | 12 | func executableClean() (string, error) { 13 | p, err := executable() 14 | return filepath.Clean(p), err 15 | } 16 | 17 | // Executable returns an absolute path that can be used to 18 | // re-invoke the current program. 19 | // It may not be valid after the current program exits. 20 | func Executable() (string, error) { 21 | return cx, ce 22 | } 23 | 24 | // Returns same path as Executable, returns just the folder 25 | // path. Excludes the executable name and any trailing slash. 26 | func ExecutableFolder() (string, error) { 27 | p, err := Executable() 28 | if err != nil { 29 | return "", err 30 | } 31 | 32 | return filepath.Dir(p), nil 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_procfs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build linux netbsd solaris dragonfly 6 | 7 | package osext 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "os" 13 | "runtime" 14 | "strings" 15 | ) 16 | 17 | func executable() (string, error) { 18 | switch runtime.GOOS { 19 | case "linux": 20 | const deletedTag = " (deleted)" 21 | execpath, err := os.Readlink("/proc/self/exe") 22 | if err != nil { 23 | return execpath, err 24 | } 25 | execpath = strings.TrimSuffix(execpath, deletedTag) 26 | execpath = strings.TrimPrefix(execpath, deletedTag) 27 | return execpath, nil 28 | case "netbsd": 29 | return os.Readlink("/proc/curproc/exe") 30 | case "dragonfly": 31 | return os.Readlink("/proc/curproc/file") 32 | case "solaris": 33 | return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) 34 | } 35 | return "", errors.New("ExecPath not implemented for " + runtime.GOOS) 36 | } 37 | -------------------------------------------------------------------------------- /logging/fields_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | "testing" 23 | ) 24 | 25 | func TestSeqid(t *testing.T) { 26 | logger, _ := BasicLogger("test") 27 | for i := 0; i < 1000; i++ { 28 | r := new(record) 29 | r.genNonRuntime(logger) 30 | name := strconv.Itoa(i + 1) 31 | seq := logger.nextSeqid(r) 32 | if fmt.Sprintf("%d", seq) != name { 33 | t.Errorf("%v, %v\n", seq, name) 34 | } 35 | } 36 | logger.Destroy() 37 | } 38 | 39 | func TestName(t *testing.T) { 40 | name := "test" 41 | logger, _ := BasicLogger(name) 42 | r := new(record) 43 | if logger.lname(r) != name { 44 | t.Errorf("%v, %v\n", logger.lname(r), name) 45 | } 46 | logger.Destroy() 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /example.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/ccding/go-logging/logging" 21 | "time" 22 | ) 23 | 24 | func main() { 25 | logger1, _ := logging.SimpleLogger("logger1") 26 | logger1.SetLevel(logging.NOTSET) 27 | logger1.Error("this is a test from error") 28 | logger1.Debug("this is a test from debug") 29 | logger1.Notset("orz", time.Now().UnixNano()) 30 | logger1.Destroy() 31 | 32 | logger2, _ := logging.RichLogger("logger2") 33 | logger2.SetLevel(logging.DEBUG) 34 | logger2.Error("this is a test from error") 35 | logger2.Debug("this is a test from debug") 36 | logger2.Notset("orz", time.Now().UnixNano()) 37 | logger2.Destroy() 38 | 39 | logger3, _ := logging.ConfigLogger("example.conf") 40 | logger3.SetLevel(logging.DEBUG) 41 | logger3.Error("this is a test from error") 42 | logger3.Debug("this is a test from debug") 43 | logger3.Notset("orz", time.Now().UnixNano()) 44 | logger3.Destroy() 45 | } 46 | -------------------------------------------------------------------------------- /logging/logging_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | "testing" 23 | ) 24 | 25 | func BenchmarkSync(b *testing.B) { 26 | logger, _ := RichLogger("main") 27 | logger.SetLevel(NOTSET) 28 | for i := 0; i < b.N; i++ { 29 | logger.Error("this is a test from error") 30 | } 31 | logger.Flush() 32 | logger.Destroy() 33 | } 34 | 35 | func BenchmarkAsync(b *testing.B) { 36 | logger, _ := RichLogger("main") 37 | logger.SetLevel(NOTSET) 38 | for i := 0; i < b.N; i++ { 39 | logger.Error("this is a test from error") 40 | } 41 | logger.Flush() 42 | logger.Destroy() 43 | } 44 | 45 | func BenchmarkBasicSync(b *testing.B) { 46 | logger, _ := BasicLogger("main") 47 | logger.SetLevel(NOTSET) 48 | for i := 0; i < b.N; i++ { 49 | logger.Error("this is a test from error") 50 | } 51 | logger.Flush() 52 | logger.Destroy() 53 | } 54 | 55 | func BenchmarkBasicAsync(b *testing.B) { 56 | logger, _ := BasicLogger("main") 57 | logger.SetLevel(NOTSET) 58 | for i := 0; i < b.N; i++ { 59 | logger.Error("this is a test from error") 60 | } 61 | logger.Flush() 62 | logger.Destroy() 63 | } 64 | 65 | func BenchmarkPrintln(b *testing.B) { 66 | out, _ := os.Create("logging.log") 67 | for i := 0; i < b.N; i++ { 68 | fmt.Fprintln(out, "this is a test from error") 69 | } 70 | out.Close() 71 | } 72 | -------------------------------------------------------------------------------- /logging/level.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | // Level is the type of level. 20 | type Level int32 21 | 22 | // Values of level 23 | const ( 24 | CRITICAL Level = 50 25 | FATAL Level = CRITICAL 26 | ERROR Level = 40 27 | WARNING Level = 30 28 | WARN Level = WARNING 29 | INFO Level = 20 30 | DEBUG Level = 10 31 | NOTSET Level = 0 32 | ) 33 | 34 | // The mapping from level to level name 35 | var levelNames = map[Level]string{ 36 | CRITICAL: "CRITICAL", 37 | ERROR: "ERROR", 38 | WARNING: "WARNING", 39 | INFO: "INFO", 40 | DEBUG: "DEBUG", 41 | NOTSET: "NOTSET", 42 | } 43 | 44 | // The mapping from level name to level 45 | var levelValues = map[string]Level{ 46 | "CRITICAL": CRITICAL, 47 | "ERROR": ERROR, 48 | "WARN": WARNING, 49 | "WARNING": WARNING, 50 | "INFO": INFO, 51 | "DEBUG": DEBUG, 52 | "NOTSET": NOTSET, 53 | } 54 | 55 | // String function casts level value to string 56 | func (level *Level) String() string { 57 | return levelNames[*level] 58 | } 59 | 60 | // GetLevelName lets users be able to get level name from level value. 61 | func GetLevelName(levelValue Level) string { 62 | return levelNames[levelValue] 63 | } 64 | 65 | // GetLevelValue lets users be able to get level value from level name. 66 | func GetLevelValue(levelName string) Level { 67 | return levelValues[levelName] 68 | } 69 | -------------------------------------------------------------------------------- /logging/formater.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "strings" 23 | ) 24 | 25 | // pre-defined formats 26 | const ( 27 | BasicFormat = "%s [%6s] %30s - %s\n name,levelname,time,message" 28 | RichFormat = "%s [%6s] %d %30s - %s:%s:%d - %s\n name, levelname, seqid, time, filename, funcname, lineno, message" 29 | ) 30 | 31 | // genLog generates log string from the format setting. 32 | func (logger *Logger) genLog(level Level, message string) string { 33 | fs := make([]interface{}, len(logger.recordArgs)) 34 | r := new(record) 35 | r.message = message 36 | r.level = level 37 | r.genNonRuntime(logger) 38 | if logger.runtime { 39 | r.genRuntime() 40 | } 41 | for k, v := range logger.recordArgs { 42 | fs[k] = fields[v](logger, r) 43 | } 44 | return fmt.Sprintf(logger.recordFormat, fs...) 45 | } 46 | 47 | // parseFormat checks the legality of format and parses it to recordFormat and recordArgs 48 | func (logger *Logger) parseFormat(format string) error { 49 | logger.runtime = false 50 | fts := strings.Split(format, "\n") 51 | if len(fts) != 2 { 52 | return errors.New("logging format error") 53 | } 54 | logger.recordFormat = fts[0] 55 | logger.recordArgs = strings.Split(fts[1], ",") 56 | for k, v := range logger.recordArgs { 57 | tv := strings.TrimSpace(v) 58 | _, ok := fields[tv] 59 | if ok == false { 60 | return errors.New("logging format error") 61 | } 62 | logger.recordArgs[k] = tv 63 | logger.runtime = logger.runtime || runtimeFields[tv] 64 | } 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /logging/commands.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | // Log receives log request from the client. The request includes a set of 20 | // variables. 21 | func (logger *Logger) Log(level Level, v ...interface{}) { 22 | // Don't delete this calling. The calling is used to keep the same 23 | // calldepth for all the logging functions. The calldepth is used to 24 | // get runtime information such as line number, function name, etc. 25 | logger.log(level, v...) 26 | } 27 | 28 | // Logf receives log request from the client. The request has a string 29 | // parameter to describe the format of output. 30 | func (logger *Logger) Logf(level Level, format string, v ...interface{}) { 31 | logger.logf(level, format, v...) 32 | } 33 | 34 | // Other quick commands for different level 35 | 36 | func (logger *Logger) Critical(v ...interface{}) { 37 | logger.log(CRITICAL, v...) 38 | } 39 | 40 | func (logger *Logger) Fatal(v ...interface{}) { 41 | logger.log(CRITICAL, v...) 42 | } 43 | 44 | func (logger *Logger) Error(v ...interface{}) { 45 | logger.log(ERROR, v...) 46 | } 47 | 48 | func (logger *Logger) Warn(v ...interface{}) { 49 | logger.log(WARNING, v...) 50 | } 51 | 52 | func (logger *Logger) Warning(v ...interface{}) { 53 | logger.log(WARNING, v...) 54 | } 55 | 56 | func (logger *Logger) Info(v ...interface{}) { 57 | logger.log(INFO, v...) 58 | } 59 | 60 | func (logger *Logger) Debug(v ...interface{}) { 61 | logger.log(DEBUG, v...) 62 | } 63 | 64 | func (logger *Logger) Notset(v ...interface{}) { 65 | logger.log(NOTSET, v...) 66 | } 67 | 68 | func (logger *Logger) Criticalf(format string, v ...interface{}) { 69 | logger.logf(CRITICAL, format, v...) 70 | } 71 | 72 | func (logger *Logger) Fatalf(format string, v ...interface{}) { 73 | logger.logf(CRITICAL, format, v...) 74 | } 75 | 76 | func (logger *Logger) Errorf(format string, v ...interface{}) { 77 | logger.logf(ERROR, format, v...) 78 | } 79 | 80 | func (logger *Logger) Warnf(format string, v ...interface{}) { 81 | logger.logf(WARNING, format, v...) 82 | } 83 | 84 | func (logger *Logger) Warningf(format string, v ...interface{}) { 85 | logger.logf(WARNING, format, v...) 86 | } 87 | 88 | func (logger *Logger) Infof(format string, v ...interface{}) { 89 | logger.logf(INFO, format, v...) 90 | } 91 | 92 | func (logger *Logger) Debugf(format string, v ...interface{}) { 93 | logger.logf(DEBUG, format, v...) 94 | } 95 | 96 | func (logger *Logger) Notsetf(format string, v ...interface{}) { 97 | logger.logf(NOTSET, format, v...) 98 | } 99 | -------------------------------------------------------------------------------- /vendor/github.com/kardianos/osext/osext_sysctl.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin freebsd openbsd 6 | 7 | package osext 8 | 9 | import ( 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "runtime" 14 | "syscall" 15 | "unsafe" 16 | ) 17 | 18 | var initCwd, initCwdErr = os.Getwd() 19 | 20 | func executable() (string, error) { 21 | var mib [4]int32 22 | switch runtime.GOOS { 23 | case "freebsd": 24 | mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} 25 | case "darwin": 26 | mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} 27 | case "openbsd": 28 | mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */} 29 | } 30 | 31 | n := uintptr(0) 32 | // Get length. 33 | _, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 34 | if errNum != 0 { 35 | return "", errNum 36 | } 37 | if n == 0 { // This shouldn't happen. 38 | return "", nil 39 | } 40 | buf := make([]byte, n) 41 | _, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) 42 | if errNum != 0 { 43 | return "", errNum 44 | } 45 | if n == 0 { // This shouldn't happen. 46 | return "", nil 47 | } 48 | 49 | var execPath string 50 | switch runtime.GOOS { 51 | case "openbsd": 52 | // buf now contains **argv, with pointers to each of the C-style 53 | // NULL terminated arguments. 54 | var args []string 55 | argv := uintptr(unsafe.Pointer(&buf[0])) 56 | Loop: 57 | for { 58 | argp := *(**[1 << 20]byte)(unsafe.Pointer(argv)) 59 | if argp == nil { 60 | break 61 | } 62 | for i := 0; uintptr(i) < n; i++ { 63 | // we don't want the full arguments list 64 | if string(argp[i]) == " " { 65 | break Loop 66 | } 67 | if argp[i] != 0 { 68 | continue 69 | } 70 | args = append(args, string(argp[:i])) 71 | n -= uintptr(i) 72 | break 73 | } 74 | if n < unsafe.Sizeof(argv) { 75 | break 76 | } 77 | argv += unsafe.Sizeof(argv) 78 | n -= unsafe.Sizeof(argv) 79 | } 80 | execPath = args[0] 81 | // There is no canonical way to get an executable path on 82 | // OpenBSD, so check PATH in case we are called directly 83 | if execPath[0] != '/' && execPath[0] != '.' { 84 | execIsInPath, err := exec.LookPath(execPath) 85 | if err == nil { 86 | execPath = execIsInPath 87 | } 88 | } 89 | default: 90 | for i, v := range buf { 91 | if v == 0 { 92 | buf = buf[:i] 93 | break 94 | } 95 | } 96 | execPath = string(buf) 97 | } 98 | 99 | var err error 100 | // execPath will not be empty due to above checks. 101 | // Try to get the absolute path if the execPath is not rooted. 102 | if execPath[0] != '/' { 103 | execPath, err = getAbs(execPath) 104 | if err != nil { 105 | return execPath, err 106 | } 107 | } 108 | // For darwin KERN_PROCARGS may return the path to a symlink rather than the 109 | // actual executable. 110 | if runtime.GOOS == "darwin" { 111 | if execPath, err = filepath.EvalSymlinks(execPath); err != nil { 112 | return execPath, err 113 | } 114 | } 115 | return execPath, nil 116 | } 117 | 118 | func getAbs(execPath string) (string, error) { 119 | if initCwdErr != nil { 120 | return execPath, initCwdErr 121 | } 122 | // The execPath may begin with a "../" or a "./" so clean it first. 123 | // Join the two paths, trailing and starting slashes undetermined, so use 124 | // the generic Join function. 125 | return filepath.Join(initCwd, filepath.Clean(execPath)), nil 126 | } 127 | -------------------------------------------------------------------------------- /logging/writer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "sync/atomic" 23 | "time" 24 | ) 25 | 26 | // watcher watches the logger.queue channel, and writes the logs to output 27 | func (logger *Logger) watcher() { 28 | var buf bytes.Buffer 29 | for { 30 | timeout := time.After(time.Millisecond * logger.timeInterval) 31 | 32 | for i := 0; i < logger.bufferSize; i++ { 33 | select { 34 | case msg := <-logger.queue: 35 | fmt.Fprintln(&buf, msg) 36 | case req := <-logger.request: 37 | logger.flushReq(&buf, &req) 38 | case <-timeout: 39 | i = logger.bufferSize 40 | case <-logger.flush: 41 | logger.flushBuf(&buf) 42 | logger.finish <- true 43 | i = logger.bufferSize 44 | case <-logger.quit: 45 | // If quit signal received, cleans the channel 46 | // and writes all of them to io.Writer. 47 | for { 48 | select { 49 | case msg := <-logger.queue: 50 | fmt.Fprintln(&buf, msg) 51 | case req := <-logger.request: 52 | logger.flushReq(&buf, &req) 53 | case <-logger.flush: 54 | // do nothing 55 | default: 56 | logger.flushBuf(&buf) 57 | logger.quit <- true 58 | return 59 | } 60 | } 61 | } 62 | } 63 | logger.flushBuf(&buf) 64 | } 65 | } 66 | 67 | // flushBuf flushes the content of buffer to out and reset the buffer 68 | func (logger *Logger) flushBuf(b *bytes.Buffer) { 69 | if len(b.Bytes()) > 0 { 70 | logger.out.Write(b.Bytes()) 71 | b.Reset() 72 | } 73 | } 74 | 75 | // flushReq handles the request and writes the result to writer 76 | func (logger *Logger) flushReq(b *bytes.Buffer, req *request) { 77 | if req.format == "" { 78 | msg := fmt.Sprint(req.v...) 79 | msg = logger.genLog(req.level, msg) 80 | fmt.Fprintln(b, msg) 81 | } else { 82 | msg := fmt.Sprintf(req.format, req.v...) 83 | msg = logger.genLog(req.level, msg) 84 | fmt.Fprintln(b, msg) 85 | } 86 | } 87 | 88 | // flushMsg is to print log to file, stdout, or others. 89 | func (logger *Logger) flushMsg(message string) { 90 | if logger.sync { 91 | logger.wlock.Lock() 92 | defer logger.wlock.Unlock() 93 | fmt.Fprintln(logger.out, message) 94 | } else { 95 | logger.queue <- message 96 | } 97 | } 98 | 99 | // log records log v... with level `level'. 100 | func (logger *Logger) log(level Level, v ...interface{}) { 101 | if int32(level) >= atomic.LoadInt32((*int32)(&logger.level)) { 102 | if logger.runtime || logger.sync { 103 | message := fmt.Sprint(v...) 104 | message = logger.genLog(level, message) 105 | logger.flushMsg(message) 106 | } else { 107 | r := new(request) 108 | r.level = level 109 | r.v = v 110 | logger.request <- *r 111 | } 112 | } 113 | } 114 | 115 | // logf records log v... with level `level'. 116 | func (logger *Logger) logf(level Level, format string, v ...interface{}) { 117 | if int32(level) >= atomic.LoadInt32((*int32)(&logger.level)) { 118 | if logger.runtime || logger.sync { 119 | message := fmt.Sprintf(format, v...) 120 | message = logger.genLog(level, message) 121 | logger.flushMsg(message) 122 | } else { 123 | r := new(request) 124 | r.level = level 125 | r.format = format 126 | r.v = v 127 | logger.request <- *r 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /vendor/github.com/ccding/go-config-reader/config/config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package config 18 | 19 | import ( 20 | "bufio" 21 | "errors" 22 | "fmt" 23 | "io/ioutil" 24 | "os" 25 | "strings" 26 | ) 27 | 28 | var commentPrefix = []string{"//", "#", ";"} 29 | 30 | // Config struct constructs a new configuration handler. 31 | type Config struct { 32 | filename string 33 | config map[string]map[string]string 34 | } 35 | 36 | // NewConfig function cnstructs a new Config struct with filename. You have to 37 | // call Read() function to let it read from the file. Otherwise you will get 38 | // empty string (i.e., "") when you are calling Get() function. Another usage 39 | // is that you call NewConfig() function and then call Add()/Set() function to 40 | // add new key-values to the configuration. Finally you can call Write() 41 | // function to write the new configuration to the file. 42 | func NewConfig(filename string) *Config { 43 | c := new(Config) 44 | c.filename = filename 45 | c.config = make(map[string]map[string]string) 46 | return c 47 | } 48 | 49 | // Filename function returns the filename of the configuration. 50 | func (c *Config) Filename() string { 51 | return c.filename 52 | } 53 | 54 | // SetFilename function sets the filename of the configuration. 55 | func (c *Config) SetFilename(filename string) { 56 | c.filename = filename 57 | } 58 | 59 | // Reset function reset the map in the configuration. 60 | func (c *Config) Reset() { 61 | c.config = make(map[string]map[string]string) 62 | } 63 | 64 | // Read function reads configurations from the file defined in 65 | // Config.filename. 66 | func (c *Config) Read() error { 67 | in, err := os.Open(c.filename) 68 | if err != nil { 69 | return err 70 | } 71 | defer in.Close() 72 | scanner := bufio.NewScanner(in) 73 | line := "" 74 | section := "" 75 | for scanner.Scan() { 76 | if scanner.Text() == "" { 77 | continue 78 | } 79 | if line == "" { 80 | sec, ok := checkSection(scanner.Text()) 81 | if ok { 82 | section = sec 83 | continue 84 | } 85 | } 86 | if checkComment(scanner.Text()) { 87 | continue 88 | } 89 | line += scanner.Text() 90 | if strings.HasSuffix(line, "\\") { 91 | line = line[:len(line)-1] 92 | continue 93 | } 94 | key, value, ok := checkLine(line) 95 | if !ok { 96 | return errors.New("WRONG: " + line) 97 | } 98 | c.Set(section, key, value) 99 | line = "" 100 | } 101 | return nil 102 | } 103 | 104 | // Get function returns the value of a key in the configuration. If the key 105 | // does not exist, it returns empty string (i.e., ""). 106 | func (c *Config) Get(section string, key string) string { 107 | value, ok := c.config[section][key] 108 | if !ok { 109 | return "" 110 | } 111 | return value 112 | } 113 | 114 | // Set function updates the value of a key in the configuration. Function 115 | // Set() is exactly the same as function Add(). 116 | func (c *Config) Set(section string, key string, value string) { 117 | _, ok := c.config[section] 118 | if !ok { 119 | c.config[section] = make(map[string]string) 120 | } 121 | c.config[section][key] = value 122 | } 123 | 124 | // Add function adds a new key to the configuration. Function Add() is exactly 125 | // the same as function Set(). 126 | func (c *Config) Add(section string, key string, value string) { 127 | c.Set(section, key, value) 128 | } 129 | 130 | // Del function deletes a key from the configuration. 131 | func (c *Config) Del(section string, key string) { 132 | _, ok := c.config[section] 133 | if ok { 134 | delete(c.config[section], key) 135 | if len(c.config[section]) == 0 { 136 | delete(c.config, section) 137 | } 138 | } 139 | } 140 | 141 | // Write function writes the updated configuration back. 142 | func (c *Config) Write() error { 143 | return nil 144 | } 145 | 146 | // WriteTo function writes the configuration to a new file. This function 147 | // re-organizes the configuration and deletes all the comments. 148 | func (c *Config) WriteTo(filename string) error { 149 | content := "" 150 | for k, v := range c.config { 151 | format := "%v = %v\n" 152 | if k != "" { 153 | content += fmt.Sprintf("[%v]\n", k) 154 | format = "\t" + format 155 | } 156 | for key, value := range v { 157 | content += fmt.Sprintf(format, key, value) 158 | } 159 | } 160 | return ioutil.WriteFile(filename, []byte(content), 0644) 161 | } 162 | 163 | // To check this line is a section or not. If it is not a section, it returns 164 | // "". 165 | func checkSection(line string) (string, bool) { 166 | line = strings.TrimSpace(line) 167 | lineLen := len(line) 168 | if lineLen < 2 { 169 | return "", false 170 | } 171 | if line[0] == '[' && line[lineLen-1] == ']' { 172 | return line[1 : lineLen-1], true 173 | } 174 | return "", false 175 | } 176 | 177 | // To check this line is a valid key-value pair or not. 178 | func checkLine(line string) (string, string, bool) { 179 | key := "" 180 | value := "" 181 | sp := strings.SplitN(line, "=", 2) 182 | if len(sp) != 2 { 183 | return key, value, false 184 | } 185 | key = strings.TrimSpace(sp[0]) 186 | value = strings.TrimSpace(sp[1]) 187 | return key, value, true 188 | } 189 | 190 | // To check this line is a whole line comment or not. 191 | func checkComment(line string) bool { 192 | line = strings.TrimSpace(line) 193 | for p := range commentPrefix { 194 | if strings.HasPrefix(line, commentPrefix[p]) { 195 | return true 196 | } 197 | } 198 | return false 199 | } 200 | -------------------------------------------------------------------------------- /logging/fields.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | package logging 18 | 19 | import ( 20 | "github.com/kardianos/osext" 21 | "os" 22 | "path" 23 | "runtime" 24 | "strings" 25 | "sync/atomic" 26 | "time" 27 | ) 28 | 29 | // The struct for each log record 30 | type record struct { 31 | level Level 32 | seqid uint64 33 | pathname string 34 | filename string 35 | module string 36 | lineno int 37 | funcname string 38 | thread int 39 | process int 40 | message string 41 | time time.Time 42 | } 43 | 44 | // This variable maps fields in recordArgs to relavent function signatures 45 | var fields = map[string]func(*Logger, *record) interface{}{ 46 | "name": (*Logger).lname, // name of the logger 47 | "seqid": (*Logger).nextSeqid, // sequence number 48 | "levelno": (*Logger).levelno, // level number 49 | "levelname": (*Logger).levelname, // level name 50 | "created": (*Logger).created, // starting time of the logger 51 | "nsecs": (*Logger).nsecs, // nanosecond of the starting time 52 | "time": (*Logger).time, // record created time 53 | "timestamp": (*Logger).timestamp, // timestamp of record 54 | "rtime": (*Logger).rtime, // relative time since started 55 | "filename": (*Logger).filename, // source filename of the caller 56 | "pathname": (*Logger).pathname, // filename with path 57 | "module": (*Logger).module, // executable filename 58 | "lineno": (*Logger).lineno, // line number in source code 59 | "funcname": (*Logger).funcname, // function name of the caller 60 | "process": (*Logger).process, // process id 61 | "message": (*Logger).message, // logger message 62 | } 63 | 64 | var runtimeFields = map[string]bool{ 65 | "name": false, 66 | "seqid": false, 67 | "levelno": false, 68 | "levelname": false, 69 | "created": false, 70 | "nsecs": false, 71 | "time": false, 72 | "timestamp": false, 73 | "rtime": false, 74 | "filename": true, 75 | "pathname": true, 76 | "module": false, 77 | "lineno": true, 78 | "funcname": true, 79 | "thread": true, 80 | "process": false, 81 | "message": false, 82 | } 83 | 84 | // If it fails to get some fields with string type, these fields are set to 85 | // errString value. 86 | const errString = "???" 87 | 88 | // getShortFuncName generates short function name. 89 | func getShortFuncName(fname string) string { 90 | fns := strings.Split(fname, ".") 91 | return fns[len(fns)-1] 92 | } 93 | 94 | // genRuntime generates the runtime information, including pathname, function 95 | // name, filename, line number. 96 | func (r *record) genRuntime() { 97 | calldepth := 4 98 | pc, file, line, ok := runtime.Caller(calldepth) 99 | if ok { 100 | fname := runtime.FuncForPC(pc).Name() 101 | r.pathname = file 102 | r.funcname = getShortFuncName(fname) 103 | r.filename = path.Base(file) 104 | r.lineno = line 105 | } else { 106 | r.pathname = errString 107 | r.funcname = errString 108 | r.filename = errString 109 | // Here we uses -1 rather than 0, because the default value in 110 | // golang is 0 and we should know the value is uninitialized 111 | // or failed to get 112 | r.lineno = -1 113 | } 114 | } 115 | 116 | // genNonRuntime generates the non-runtime information, including sequential 117 | // id and time. 118 | func (r *record) genNonRuntime(logger *Logger) { 119 | r.seqid = atomic.AddUint64(&(logger.seqid), 1) 120 | r.time = time.Now() 121 | } 122 | 123 | // Logger name 124 | func (logger *Logger) lname(r *record) interface{} { 125 | return logger.name 126 | } 127 | 128 | // Next sequence number 129 | func (logger *Logger) nextSeqid(r *record) interface{} { 130 | return r.seqid 131 | } 132 | 133 | // Log level number 134 | func (logger *Logger) levelno(r *record) interface{} { 135 | return int32(r.level) 136 | } 137 | 138 | // Log level name 139 | func (logger *Logger) levelname(r *record) interface{} { 140 | return levelNames[r.level] 141 | } 142 | 143 | // File name of calling logger, with whole path 144 | func (logger *Logger) pathname(r *record) interface{} { 145 | return r.pathname 146 | } 147 | 148 | // File name of calling logger 149 | func (logger *Logger) filename(r *record) interface{} { 150 | return r.filename 151 | } 152 | 153 | // module name 154 | func (logger *Logger) module(r *record) interface{} { 155 | module, _ := osext.Executable() 156 | return path.Base(module) 157 | } 158 | 159 | // Line number 160 | func (logger *Logger) lineno(r *record) interface{} { 161 | return r.lineno 162 | } 163 | 164 | // Function name 165 | func (logger *Logger) funcname(r *record) interface{} { 166 | return r.funcname 167 | } 168 | 169 | // Timestamp of starting time 170 | func (logger *Logger) created(r *record) interface{} { 171 | return logger.startTime.UnixNano() 172 | } 173 | 174 | // RFC3339Nano time 175 | func (logger *Logger) time(r *record) interface{} { 176 | return r.time.Format(logger.timeFormat) 177 | } 178 | 179 | // Nanosecond of starting time 180 | func (logger *Logger) nsecs(r *record) interface{} { 181 | return logger.startTime.Nanosecond() 182 | } 183 | 184 | // Nanosecond timestamp 185 | func (logger *Logger) timestamp(r *record) interface{} { 186 | return r.time.UnixNano() 187 | } 188 | 189 | // Nanoseconds since logger created 190 | func (logger *Logger) rtime(r *record) interface{} { 191 | return r.time.Sub(logger.startTime).Nanoseconds() 192 | } 193 | 194 | // Process ID 195 | func (logger *Logger) process(r *record) interface{} { 196 | r.process = os.Getpid() 197 | return r.process 198 | } 199 | 200 | // The log message 201 | func (logger *Logger) message(r *record) interface{} { 202 | return r.message 203 | } 204 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-logging 2 | 3 | [![Build Status](https://travis-ci.org/ccding/go-logging.svg?branch=master)](https://travis-ci.org/ccding/go-logging) 4 | [![License](https://img.shields.io/badge/License-Apache%202.0-red.svg)](https://opensource.org/licenses/Apache-2.0) 5 | [![GoDoc](https://godoc.org/github.com/ccding/go-logging?status.svg)](http://godoc.org/github.com/ccding/go-logging/logging) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/ccding/go-logging)](https://goreportcard.com/report/github.com/ccding/go-logging) 7 | 8 | go-logging is a high-performance logging library for golang. 9 | * Simple: It supports only necessary operations and easy to get started. 10 | * Fast: Asynchronous logging without runtime-related fields has an extremely 11 | low delay of about 800 nano-seconds. 12 | * Performance in my laptop as follow. 13 | ```bash 14 | BenchmarkSync 300000 4018 ns/op 15 | BenchmarkAsync 300000 4229 ns/op 16 | BenchmarkBasicSync 500000 2504 ns/op 17 | BenchmarkBasicAsync 1000000 2495 ns/op 18 | BenchmarkPrintln 1000000 1550 ns/op 19 | ``` 20 | 21 | ## Getting Started 22 | ### Installation 23 | The step below will download the library source code to 24 | `${GOPATH}/src/github.com/ccding/go-logging`. 25 | ```bash 26 | go get github.com/ccding/go-logging/logging 27 | ``` 28 | 29 | Given the source code downloaded, it makes you be able to run the examples, 30 | tests, and benchmarks. 31 | ```bash 32 | cd ${GOPATH}/src/github.com/ccding/go-logging/logging 33 | go get 34 | go run ../example.go 35 | go test -v -bench . 36 | ``` 37 | 38 | ### Example 39 | go-logging is used like any other Go libraries. You can simply use the library 40 | in this way. 41 | ```go 42 | import "github.com/ccding/go-logging/logging" 43 | ``` 44 | 45 | Here is a simple example. 46 | ```go 47 | package main 48 | 49 | import ( 50 | "github.com/ccding/go-logging/logging" 51 | ) 52 | 53 | func main() { 54 | logger, _ := logging.SimpleLogger("main") 55 | logger.Error("this is a test from error") 56 | logger.Destroy() 57 | } 58 | ``` 59 | 60 | ### Configuration 61 | #### Construction Functions 62 | It has the following functions to create a logger. 63 | ```go 64 | // with BasicFormat and writing to stdout 65 | SimpleLogger(name string) (*Logger, error) 66 | // with BasicFormat and writing to DefaultFileName 67 | BasicLogger(name string) (*Logger, error) 68 | // with RichFormatand writing to DefaultFileName 69 | RichLogger(name string) (*Logger, error) 70 | // with detailed configuration and writing to file 71 | FileLogger(name string, level Level, format string, timeFormat string, file string, sync bool) (*Logger, error) 72 | // with detailed configuration and writing to a writer 73 | WriterLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) 74 | // read configurations from a config file 75 | ConfigLogger(filename string) (*Logger, error) 76 | ``` 77 | The meanings of these fields are 78 | ```go 79 | name string // logger name 80 | level Level // record level higher than this will be printed 81 | format string // format configuration 82 | timeFormat string // format for time 83 | file string // file name for logging 84 | out io.Writer // writer for logging 85 | sync bool // use sync or async way to record logs 86 | ``` 87 | The detailed description of these fields will be presented later. 88 | 89 | #### Logging Functions 90 | It supports the following functions for logging. All of these functions are 91 | thread-safe. 92 | ```go 93 | (*Logger) Logf(level Level, format string, v ...interface{}) 94 | (*Logger) Log(level Level, v ...interface{}) 95 | (*Logger) Criticalf(format string, v ...interface{}) 96 | (*Logger) Critical(v ...interface{}) 97 | (*Logger) Fatalf(format string, v ...interface{}) 98 | (*Logger) Fatal(v ...interface{}) 99 | (*Logger) Errorf(format string, v ...interface{}) 100 | (*Logger) Error(v ...interface{}) 101 | (*Logger) Warningf(format string, v ...interface{}) 102 | (*Logger) Warning(v ...interface{}) 103 | (*Logger) Warnf(format string, v ...interface{}) 104 | (*Logger) Warn(v ...interface{}) 105 | (*Logger) Infof(format string, v ...interface{}) 106 | (*Logger) Info(v ...interface{}) 107 | (*Logger) Debugf(format string, v ...interface{}) 108 | (*Logger) Debug(v ...interface{}) 109 | (*Logger) Notsetf(format string, v ...interface{}) 110 | (*Logger) Notset(v ...interface{}) 111 | ``` 112 | 113 | #### Logger Operations 114 | The logger supports the following operations. In these functions, `SetWriter` 115 | and `Destroy` are not thread-safe, while others are. All these functions are 116 | running in a synchronous way. 117 | ```go 118 | // Getter functions 119 | (*Logger) Name() string // get name 120 | (*Logger) TimeFormat() string // get time format 121 | (*Logger) Level() Level // get level [this function is thread safe] 122 | (*Logger) RecordFormat() string // get the first part of the format 123 | (*Logger) RecordArgs() []string // get the second part of the format 124 | (*Logger) Writer() io.Writer // get writer 125 | (*Logger) Sync() bool // get sync or async 126 | 127 | // Setter functions 128 | (*Logger) SetLevel(level Level) // set level [this function is thread safe] 129 | (*Logger) SetWriter(out ...io.Writer) // set multiple writers 130 | 131 | // Other functions 132 | (*Logger) Flush() // flush the writer 133 | (*Logger) Destroy() // destroy the logger 134 | ``` 135 | 136 | #### Fields Description 137 | 138 | ##### Name 139 | Name field is a string, which can be written to the logging and used to 140 | separate multiple loggers. It allows two logger having the same name. There 141 | is not any default value for name. 142 | 143 | ##### Logging Levels 144 | There are these levels in logging. 145 | ```go 146 | CRITICAL 50 147 | FATAL CRITICAL 148 | ERROR 40 149 | WARNING 30 150 | WARN WARNING 151 | INFO 20 152 | DEBUG 10 153 | NOTSET 0 154 | ``` 155 | 156 | ##### Record Format 157 | The record format is described by a string, which has two parts separated by 158 | `\n`. The first part describes the format of the log, and the second part 159 | lists all the fields to be shown in the log. In other word, the first part is 160 | the first parameter `format` of `fmt.Printf(format string, v ...interface{})`, 161 | and the second part describes the second parameter `v` of it. It is not 162 | allowed to have `\n` in the first part. The fields in the second part are 163 | separated by comma `,`, while extra blank spaces are allowed. An example of 164 | the format string is 165 | ```go 166 | const BasicFormat = "%s [%6s] %30s - %s\n name,levelname,time,message" 167 | ``` 168 | which is the pre-defined `BasicFormat` used by `BasicLogger()` and 169 | `SimpleLogger()`. 170 | 171 | It supports the following fields for the second part of the format. 172 | ```go 173 | "name" string %s // name of the logger 174 | "seqid" uint64 %d // sequence number 175 | "levelno" int32 %d // level number 176 | "levelname" string %s // level name 177 | "created" int64 %d // starting time of the logger 178 | "nsecs" int64 %d // nanosecond of the starting time 179 | "time" string %s // record created time 180 | "timestamp" int64 %d // timestamp of record 181 | "rtime" int64 %d // relative time since started 182 | "filename" string %s // source filename of the caller 183 | "pathname" string %s // filename with path 184 | "module" string %s // executable filename 185 | "lineno" int %d // line number in source code 186 | "funcname" string %s // function name of the caller 187 | "process" int %d // process id 188 | "message" string %s // logger message 189 | ``` 190 | The following runtime-related fields is extremely expensive and slow, please 191 | be careful when using them. 192 | ```go 193 | "filename" string %s // source filename of the caller 194 | "pathname" string %s // filename with path 195 | "lineno" int %d // line number in source code 196 | "funcname" string %s // function name of the caller 197 | ``` 198 | 199 | There are a few pre-defined values for record format. 200 | ```go 201 | BasicFormat = "%s [%6s] %30s - %s\n name,levelname,time,message" 202 | RichFormat = "%s [%6s] %d %30s - %d - %s:%s:%d - %s\n name, levelname, seqid, time, filename, funcname, lineno, message" 203 | ``` 204 | 205 | ##### Time Format 206 | We use the same time format as golang. The default time format is 207 | ```go 208 | DefaultTimeFormat = "2006-01-02 15:04:05.999999999" // default time format 209 | ``` 210 | 211 | ##### File Name, Writer, and Sync 212 | The meaning of these fields are obvious. Filename is used to create writer. 213 | We also allow the user create a writer by herself and pass it to the logger. 214 | Sync describes whether the user would like to use synchronous or asynchronous 215 | method to write logs. `true` value means synchronous method, and `false` value 216 | means asynchronous way. We suggest you use asynchronous way because it causes 217 | extremely low extra delay by the logging functions. 218 | 219 | ## Contributors 220 | In alphabetical order 221 | * Cong Ding ([ccding][ccding]) 222 | * Xiang Li ([xiang90][xiang90]) 223 | * Zifei Tong ([5kg][5kg]) 224 | 225 | [ccding]: //github.com/ccding 226 | [xiang90]: //github.com/xiang90 227 | [5kg]: //github.com/5kg 228 | -------------------------------------------------------------------------------- /logging/logging.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Cong Ding. All rights reserved. 2 | // 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 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 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. 14 | // 15 | // author: Cong Ding 16 | 17 | // Package logging implements log library for other applications. It provides 18 | // functions Debug, Info, Warning, Error, Critical, and formatting version 19 | // Logf. 20 | // 21 | // Example: 22 | // 23 | // logger := logging.SimpleLogger("main") 24 | // logger.SetLevel(logging.WARNING) 25 | // logger.Error("test for error") 26 | // logger.Warning("test for warning", "second parameter") 27 | // logger.Debug("test for debug") 28 | // 29 | package logging 30 | 31 | import ( 32 | "github.com/ccding/go-config-reader/config" 33 | "io" 34 | "os" 35 | "strconv" 36 | "sync" 37 | "sync/atomic" 38 | "time" 39 | ) 40 | 41 | // Pre-defined formats 42 | const ( 43 | DefaultFileName = "logging.log" // default logging filename 44 | DefaultTimeFormat = "2006-01-02 15:04:05.999999999" // defaulttime format 45 | DefaultBufferSize = 1000 // default buffer size for writer 46 | DefaultQueueSize = 10000 // default chan queue size in async logging 47 | DefaultRequestSize = 10000 // default chan queue size in async logging 48 | DefaultTimeInterval = 100 // default time interval in milliseconds in async logging 49 | ) 50 | 51 | // Logger is the logging struct. 52 | type Logger struct { 53 | 54 | // Be careful of the alignment issue of the variable seqid because it 55 | // uses the sync/atomic.AddUint64() operation. If the alignment is 56 | // wrong, it will cause a panic. To solve the alignment issue in an 57 | // easy way, we put seqid to the beginning of the structure. 58 | // seqid is only visiable internally. 59 | seqid uint64 // last used sequence number in record 60 | 61 | // These variables can be configured by users. 62 | name string // logger name 63 | level Level // record level higher than this will be printed 64 | recordFormat string // format of the record 65 | recordArgs []string // arguments to be used in the recordFormat 66 | out io.Writer // writer 67 | sync bool // use sync or async way to record logs 68 | timeFormat string // format for time 69 | 70 | // These variables are visible to users. 71 | startTime time.Time // start time of the logger 72 | 73 | // Internally used variables, which don't have get and set functions. 74 | wlock sync.Mutex // writer lock 75 | queue chan string // queue used in async logging 76 | request chan request // queue used in non-runtime logging 77 | flush chan bool // flush signal for the watcher to write 78 | finish chan bool // finish flush signal for the flush function to return 79 | quit chan bool // quit signal for the watcher to quit 80 | fd *os.File // file handler, used to close the file on destroy 81 | runtime bool // with runtime operation or not 82 | 83 | // The customized configurations. 84 | bufferSize int 85 | timeInterval time.Duration 86 | } 87 | 88 | // SimpleLogger creates a new logger with simple configuration. 89 | func SimpleLogger(name string) (*Logger, error) { 90 | return createLogger(name, WARNING, BasicFormat, DefaultTimeFormat, os.Stdout, false) 91 | } 92 | 93 | // BasicLogger creates a new logger with basic configuration. 94 | func BasicLogger(name string) (*Logger, error) { 95 | return FileLogger(name, WARNING, BasicFormat, DefaultTimeFormat, DefaultFileName, false) 96 | } 97 | 98 | // RichLogger creates a new logger with simple configuration. 99 | func RichLogger(name string) (*Logger, error) { 100 | return FileLogger(name, NOTSET, RichFormat, DefaultTimeFormat, DefaultFileName, false) 101 | } 102 | 103 | // FileLogger creates a new logger with file output. 104 | func FileLogger(name string, level Level, format string, timeFormat string, file string, sync bool) (*Logger, error) { 105 | out, err := os.OpenFile(file, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0644) 106 | if err != nil { 107 | return nil, err 108 | } 109 | logger, err := createLogger(name, level, format, timeFormat, out, sync) 110 | if err == nil { 111 | logger.fd = out 112 | return logger, nil 113 | } else { 114 | return nil, err 115 | } 116 | } 117 | 118 | // WriterLogger creates a new logger with a writer 119 | func WriterLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) { 120 | return createLogger(name, level, format, timeFormat, out, sync) 121 | } 122 | 123 | // CustomizedLogger creates a new logger with all configurations customized 124 | // (in addition to WriterLogger). 125 | func CustomizedLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool, queueSize int, requestSize int, bufferSize int, timeInterval time.Duration) (*Logger, error) { 126 | return createCustomizedLogger(name, level, format, timeFormat, out, sync, queueSize, requestSize, bufferSize, timeInterval) 127 | } 128 | 129 | // ConfigLogger creates a new logger from a configuration file 130 | func ConfigLogger(filename string) (*Logger, error) { 131 | conf := config.NewConfig(filename) 132 | err := conf.Read() 133 | if err != nil { 134 | return nil, err 135 | } 136 | name := conf.Get("", "name") 137 | slevel := conf.Get("", "level") 138 | if slevel == "" { 139 | slevel = "0" 140 | } 141 | l, err := strconv.Atoi(slevel) 142 | if err != nil { 143 | return nil, err 144 | } 145 | level := Level(l) 146 | format := conf.Get("", "format") 147 | if format == "" { 148 | format = BasicFormat 149 | } 150 | timeFormat := conf.Get("", "timeFormat") 151 | if timeFormat == "" { 152 | timeFormat = DefaultTimeFormat 153 | } 154 | ssync := conf.Get("", "sync") 155 | if ssync == "" { 156 | ssync = "0" 157 | } 158 | file := conf.Get("", "file") 159 | if file == "" { 160 | file = DefaultFileName 161 | } 162 | sync := true 163 | if ssync == "0" { 164 | sync = false 165 | } else if ssync == "1" { 166 | sync = true 167 | } else { 168 | return nil, err 169 | } 170 | return FileLogger(name, level, format, timeFormat, file, sync) 171 | } 172 | 173 | // createLogger create a new logger 174 | func createLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool) (*Logger, error) { 175 | return createCustomizedLogger(name, level, format, timeFormat, out, sync, DefaultQueueSize, DefaultRequestSize, DefaultBufferSize, DefaultTimeInterval) 176 | } 177 | 178 | // createCustomizedLogger create a new logger with customizing queue size and request size 179 | func createCustomizedLogger(name string, level Level, format string, timeFormat string, out io.Writer, sync bool, queueSize int, requestSize int, bufferSize int, timeInterval time.Duration) (*Logger, error) { 180 | logger := new(Logger) 181 | 182 | err := logger.parseFormat(format) 183 | if err != nil { 184 | return nil, err 185 | } 186 | 187 | // assign values to logger 188 | logger.name = name 189 | logger.level = level 190 | logger.out = out 191 | logger.seqid = 0 192 | logger.sync = sync 193 | logger.queue = make(chan string, queueSize) 194 | logger.request = make(chan request, requestSize) 195 | logger.flush = make(chan bool) 196 | logger.finish = make(chan bool) 197 | logger.quit = make(chan bool) 198 | logger.startTime = time.Now() 199 | logger.fd = nil 200 | logger.timeFormat = timeFormat 201 | logger.bufferSize = bufferSize 202 | logger.timeInterval = timeInterval 203 | 204 | // start watcher to write logs if it is async or no runtime field 205 | if !logger.sync { 206 | go logger.watcher() 207 | } 208 | 209 | return logger, nil 210 | } 211 | 212 | // Destroy sends quit signal to watcher and releases all the resources. 213 | func (logger *Logger) Destroy() { 214 | if !logger.sync { 215 | // quit watcher 216 | logger.quit <- true 217 | // wait for watcher quit 218 | <-logger.quit 219 | } 220 | // clean up 221 | if logger.fd != nil { 222 | logger.fd.Close() 223 | } 224 | } 225 | 226 | // Flush the writer 227 | func (logger *Logger) Flush() { 228 | if !logger.sync { 229 | // send flush signal 230 | logger.flush <- true 231 | // wait for the flush finish 232 | <-logger.finish 233 | } 234 | } 235 | 236 | // Getter functions 237 | 238 | func (logger *Logger) Name() string { 239 | return logger.name 240 | } 241 | 242 | func (logger *Logger) StartTime() int64 { 243 | return logger.startTime.UnixNano() 244 | } 245 | 246 | func (logger *Logger) TimeFormat() string { 247 | return logger.timeFormat 248 | } 249 | 250 | func (logger *Logger) Level() Level { 251 | return Level(atomic.LoadInt32((*int32)(&logger.level))) 252 | } 253 | 254 | func (logger *Logger) RecordFormat() string { 255 | return logger.recordFormat 256 | } 257 | 258 | func (logger *Logger) RecordArgs() []string { 259 | return logger.recordArgs 260 | } 261 | 262 | func (logger *Logger) Writer() io.Writer { 263 | return logger.out 264 | } 265 | 266 | func (logger *Logger) Sync() bool { 267 | return logger.sync 268 | } 269 | 270 | // Setter functions 271 | 272 | func (logger *Logger) SetLevel(level Level) { 273 | atomic.StoreInt32((*int32)(&logger.level), int32(level)) 274 | } 275 | 276 | func (logger *Logger) SetWriter(out ...io.Writer) { 277 | logger.out = io.MultiWriter(out...) 278 | } 279 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /vendor/github.com/ccding/go-config-reader/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | --------------------------------------------------------------------------------