├── .circleci └── config.yml ├── .gitignore ├── .whitesource ├── LICENSE ├── Makefile ├── README.md ├── example └── main.go ├── glg.go ├── glg_bench_test.go ├── glg_test.go ├── go.mod ├── go.sum ├── images ├── bench.png ├── logo.png └── sample.png ├── levelmap.go ├── loggers.go └── renovate.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | alias: 2 | default: &default 3 | docker: 4 | - image: cimg/go:1.20.2 5 | environment: 6 | GO111MODULE: "on" 7 | REPO_NAME: "kpango" 8 | IMAGE_NAME: "glg" 9 | GITHUB_API: "https://api.github.com/" 10 | DOCKER_USER: "kpango" 11 | setup_remote_docker: &setup_remote_docker 12 | version: 20.10.18 13 | docker_layer_caching: true 14 | 15 | version: 2 16 | jobs: 17 | test: 18 | <<: *default 19 | steps: 20 | - checkout 21 | - restore_cache: 22 | key: gosum-{{ .Branch }}-{{ checksum "go.sum" }} 23 | - run: 24 | name: preparation 25 | command: | 26 | go mod vendor 27 | - run: 28 | name: run tests 29 | command: | 30 | go test -v -race -covermode=atomic -coverprofile=coverage.out ./... 31 | go tool cover -html=coverage.out -o coverage.html 32 | bash <(curl -s https://codecov.io/bash) 33 | - store_artifacts: 34 | path: ./coverage.html 35 | - save_cache: 36 | key: gosum-{{ .Branch }}-{{ checksum "go.sum" }} 37 | paths: 38 | - ./vendor 39 | versioning: 40 | <<: *default 41 | steps: 42 | - checkout 43 | - run: 44 | name: check 45 | command: | 46 | mkdir -p $HOME/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config 47 | LAST_COMMIT=`git log -1 --pretty=%B` 48 | VERSION=`git describe --abbrev=0 --tags` 49 | touch ./.tag 50 | if [ ! -z "`git diff $VERSION`" -o -z "$VERSION" ]; then 51 | VERSION=${VERSION:-'0.0.0'} 52 | MAJOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" 53 | MINOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" 54 | PATCH="${VERSION%%.*}"; VERSION="${VERSION#*.}" 55 | if echo $LAST_COMMIT | grep "\[\(major\|MAJOR\)\]" > /dev/null; then 56 | MAJOR=$((MAJOR+1)) 57 | echo "$MAJOR.0.0" > ./.tag 58 | elif echo $LAST_COMMIT | grep "\[\(minor\|MINOR\)\]" > /dev/null; then 59 | MINOR=$((MINOR+1)) 60 | echo "$MAJOR.$MINOR.0" > ./.tag 61 | elif echo $LAST_COMMIT | grep "\[\(patch\|PATCH\)\]" > /dev/null; then 62 | PATCH=$((PATCH+1)) 63 | echo "$MAJOR.$MINOR.$PATCH" > ./.tag 64 | fi 65 | fi 66 | - persist_to_workspace: 67 | root: . 68 | paths: 69 | - . 70 | push: 71 | <<: *default 72 | steps: 73 | - attach_workspace: 74 | at: . 75 | - run: 76 | name: push tag and check PR body 77 | command: | 78 | mkdir -p $HOME/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config 79 | TAG=`cat ./.tag` 80 | if [ ! -z "$TAG" ]; then 81 | echo $TAG 82 | git tag $TAG 83 | git push https://${GITHUB_ACCESS_TOKEN}:x-oauth-basic@github.com/${REPO_NAME}/${IMAGE_NAME} --tags 84 | fi 85 | - persist_to_workspace: 86 | root: . 87 | paths: 88 | - . 89 | gh_release: 90 | <<: *default 91 | steps: 92 | - attach_workspace: 93 | at: . 94 | - run: 95 | name: release 96 | command: | 97 | mkdir -p $HOME/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config 98 | TAG=`cat ./.tag` 99 | if [ ! -z "$TAG" ]; then 100 | echo "Create release: ${TAG}" 101 | curl -H "Authorization: token ${GITHUB_ACCESS_TOKEN}" \ 102 | -X POST \ 103 | -d "{\"tag_name\": \"${TAG}\"}" \ 104 | ${GITHUB_API}repos/${REPO_NAME}/${IMAGE_NAME}/releases 105 | fi 106 | 107 | workflows: 108 | version: 2 109 | build: 110 | jobs: 111 | - test 112 | - versioning: 113 | filters: 114 | branches: 115 | only: 116 | - master 117 | - push: 118 | requires: 119 | - versioning 120 | - gh_release: 121 | requires: 122 | - push 123 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # sandbox files 7 | *.svg 8 | *.log 9 | *.out 10 | 11 | # Folders 12 | _obj 13 | _test 14 | 15 | # Architecture specific extensions/prefixes 16 | *.[568vq] 17 | [568vq].out 18 | 19 | *.cgo1.go 20 | *.cgo2.c 21 | _cgo_defun.c 22 | _cgo_gotypes.go 23 | _cgo_export.* 24 | 25 | _testmain.go 26 | 27 | *.exe 28 | *.test 29 | *.prof 30 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "generalSettings": { 3 | "shouldScanRepo": true 4 | }, 5 | "checkRunSettings": { 6 | "vulnerableCheckRunConclusionLevel": "failure" 7 | } 8 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 kpango (Yusuke Kato) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GO_VERSION:=$(shell go version) 2 | 3 | .PHONY: all clean bench bench-all profile lint test contributors update install 4 | 5 | all: clean install lint test bench 6 | 7 | clean: 8 | go clean ./... 9 | rm -rf ./*.log 10 | rm -rf ./*.svg 11 | rm -rf ./go.mod 12 | rm -rf ./go.sum 13 | rm -rf bench 14 | rm -rf pprof 15 | rm -rf vendor 16 | 17 | 18 | bench: clean init 19 | go test -count=5 -run=NONE -bench . -benchmem 20 | 21 | init: 22 | go mod init 23 | go mod tidy 24 | sleep 3 25 | 26 | profile: clean init 27 | rm -rf bench 28 | mkdir bench 29 | mkdir pprof 30 | \ 31 | go test -count=10 -run=NONE -bench=BenchmarkGlg -benchmem -o pprof/glg-test.bin -cpuprofile pprof/cpu-glg.out -memprofile pprof/mem-glg.out 32 | go tool pprof --svg pprof/glg-test.bin pprof/cpu-glg.out > cpu-glg.svg 33 | go tool pprof --svg pprof/glg-test.bin pprof/mem-glg.out > mem-glg.svg 34 | \ 35 | go test -count=10 -run=NONE -bench=BenchmarkDefaultLog -benchmem -o pprof/default-test.bin -cpuprofile pprof/cpu-default.out -memprofile pprof/mem-default.out 36 | go tool pprof --svg pprof/default-test.bin pprof/mem-default.out > mem-default.svg 37 | go tool pprof --svg pprof/default-test.bin pprof/cpu-default.out > cpu-default.svg 38 | \ 39 | mv ./*.svg bench/ 40 | 41 | profile-web: 42 | go tool pprof -http=":6061" \ 43 | pprof/glg-test.bin \ 44 | pprof/cpu-glg.out & 45 | go tool pprof -http=":6062" \ 46 | pprof/glg-test.bin \ 47 | pprof/mem-glg.out 48 | 49 | cpu: 50 | go tool pprof pprof/glg-test.bin pprof/cpu-glg.out 51 | 52 | mem: 53 | go tool pprof --alloc_space pprof/glg-test.bin pprof/mem-glg.out 54 | 55 | format: 56 | find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs golines -w -m 200 57 | find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs gofumpt -w 58 | find ./ -type d -name .git -prune -o -type f -regex '.*\.go' -print | xargs strictgoimports -w 59 | find ./ -type d -name .git -prune -o -type f -regex '.*\.go' -print | xargs goimports -w 60 | 61 | lint: 62 | gometalinter --enable-all . | rg -v comment 63 | 64 | test: clean init 65 | GO111MODULE=on go test --race -timeout 1h -v $(go list ./... | rg -v vendor) 66 | 67 | contributors: 68 | git log --format='%aN <%aE>' | sort -fu > CONTRIBUTORS 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT) 6 | [![release](https://img.shields.io/github/release/kpango/glg.svg?style=flat-square)](https://github.com/kpango/glg/releases/latest) 7 | [![CircleCI](https://circleci.com/gh/kpango/glg.svg)](https://circleci.com/gh/kpango/glg) 8 | [![codecov](https://codecov.io/gh/kpango/glg/branch/main/graph/badge.svg?token=2CzooNJtUu&style=flat-square)](https://codecov.io/gh/kpango/glg) 9 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a6e544eee7bc49e08a000bb10ba3deed)](https://www.codacy.com/app/i.can.feel.gravity/glg?utm_source=github.com&utm_medium=referral&utm_content=kpango/glg&utm_campaign=Badge_Grade) 10 | [![Go Report Card](https://goreportcard.com/badge/github.com/kpango/glg)](https://goreportcard.com/report/github.com/kpango/glg) 11 | [![GolangCI](https://golangci.com/badges/github.com/kpango/glg.svg?style=flat-square)](https://golangci.com/r/github.com/kpango/glg) 12 | [![Go Walker](http://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/kpango/glg) 13 | [![GoDoc](http://godoc.org/github.com/kpango/glg?status.svg)](http://godoc.org/github.com/kpango/glg) 14 | [![DepShield Badge](https://depshield.sonatype.org/badges/kpango/glg/depshield.svg)](https://depshield.github.io) 15 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fkpango%2Fglg.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkpango%2Fglg?ref=badge_shield) 16 | 17 | 18 | glg is simple golang logging library 19 | 20 | ## Requirement 21 | Go 1.16 22 | 23 | ## Installation 24 | ```shell 25 | go get github.com/kpango/glg 26 | ``` 27 | 28 | ## Example 29 | ```go 30 | package main 31 | 32 | import ( 33 | "net/http" 34 | "time" 35 | 36 | "github.com/kpango/glg" 37 | ) 38 | 39 | // NetWorkLogger sample network logger 40 | type NetWorkLogger struct{} 41 | 42 | func (n NetWorkLogger) Write(b []byte) (int, error) { 43 | // http.Post("localhost:8080/log", "", bytes.NewReader(b)) 44 | http.Get("http://127.0.0.1:8080/log") 45 | glg.Success("Requested") 46 | glg.Infof("RawString is %s", glg.RawString(b)) 47 | return 1, nil 48 | } 49 | 50 | func main() { 51 | 52 | // var errWriter io.Writer 53 | // var customWriter io.Writer 54 | infolog := glg.FileWriter("/tmp/info.log", 0666) 55 | 56 | customTag := "FINE" 57 | customErrTag := "CRIT" 58 | 59 | errlog := glg.FileWriter("/tmp/error.log", 0666) 60 | defer infolog.Close() 61 | defer errlog.Close() 62 | 63 | glg.Get(). 64 | SetMode(glg.BOTH). // default is STD 65 | // DisableColor(). 66 | // SetMode(glg.NONE). 67 | // SetMode(glg.WRITER). 68 | // SetMode(glg.BOTH). 69 | // InitWriter(). 70 | // AddWriter(customWriter). 71 | // SetWriter(customWriter). 72 | // AddLevelWriter(glg.LOG, customWriter). 73 | // AddLevelWriter(glg.INFO, customWriter). 74 | // AddLevelWriter(glg.WARN, customWriter). 75 | // AddLevelWriter(glg.ERR, customWriter). 76 | // SetLevelWriter(glg.LOG, customWriter). 77 | // SetLevelWriter(glg.INFO, customWriter). 78 | // SetLevelWriter(glg.WARN, customWriter). 79 | // SetLevelWriter(glg.ERR, customWriter). 80 | // EnableJSON(). 81 | SetLineTraceMode(glg.TraceLineNone). 82 | AddLevelWriter(glg.INFO, infolog). // add info log file destination 83 | AddLevelWriter(glg.ERR, errlog). // add error log file destination 84 | AddLevelWriter(glg.WARN, rotate) // add error log file destination 85 | 86 | glg.Info("info") 87 | glg.Infof("%s : %s", "info", "formatted") 88 | glg.Log("log") 89 | glg.Logf("%s : %s", "info", "formatted") 90 | glg.Debug("debug") 91 | glg.Debugf("%s : %s", "info", "formatted") 92 | glg.Trace("Trace") 93 | glg.Tracef("%s : %s", "tracef", "formatted") 94 | glg.Warn("warn") 95 | glg.Warnf("%s : %s", "info", "formatted") 96 | glg.Error("error") 97 | glg.Errorf("%s : %s", "info", "formatted") 98 | glg.Success("ok") 99 | glg.Successf("%s : %s", "info", "formatted") 100 | glg.Fail("fail") 101 | glg.Failf("%s : %s", "info", "formatted") 102 | glg.Print("Print") 103 | glg.Println("Println") 104 | glg.Printf("%s : %s", "printf", "formatted") 105 | 106 | // set global log level to ERR level 107 | glg.Info("before setting level to ERR this message will show") 108 | glg.Get().SetLevel(glg.ERR) 109 | glg.Info("after setting level to ERR this message will not show") 110 | glg.Error("this log is ERR level this will show") 111 | glg.Get().SetLevel(glg.DEBG) 112 | glg.Info("log level is now DEBG, this INFO level log will show") 113 | 114 | glg.Get(). 115 | AddStdLevel(customTag, glg.STD, false). // user custom log level 116 | AddErrLevel(customErrTag, glg.STD, true). // user custom error log level 117 | SetLevelColor(glg.TagStringToLevel(customTag), glg.Cyan). // set color output to user custom level 118 | SetLevelColor(glg.TagStringToLevel(customErrTag), glg.Red) // set color output to user custom level 119 | glg.CustomLog(customTag, "custom logging") 120 | glg.CustomLog(customErrTag, "custom error logging") 121 | 122 | // glg.Info("kpango's glg supports disable timestamp for logging") 123 | glg.Get().DisableTimestamp() 124 | glg.Info("timestamp disabled") 125 | glg.Warn("timestamp disabled") 126 | glg.Log("timestamp disabled") 127 | glg.Get().EnableTimestamp() 128 | glg.Info("timestamp enabled") 129 | glg.Warn("timestamp enabled") 130 | glg.Log("timestamp enabled") 131 | 132 | glg.Info("kpango's glg support line trace logging") 133 | glg.Error("error log shows short line trace by default") 134 | glg.Info("error log shows none trace by default") 135 | glg.Get().SetLineTraceMode(glg.TraceLineShort) 136 | glg.Error("after configure TraceLineShort, error log shows short line trace") 137 | glg.Info("after configure TraceLineShort, info log shows short line trace") 138 | glg.Get().DisableTimestamp() 139 | glg.Error("after configure TraceLineShort and DisableTimestamp, error log shows short line trace without timestamp") 140 | glg.Info("after configure TraceLineShort and DisableTimestamp, info log shows short line trace without timestamp") 141 | glg.Get().EnableTimestamp() 142 | glg.Get().SetLineTraceMode(glg.TraceLineLong) 143 | glg.Error("after configure TraceLineLong, error log shows long line trace") 144 | glg.Info("after configure TraceLineLong, info log shows long line trace") 145 | glg.Get().DisableTimestamp() 146 | glg.Error("after configure TraceLineLong and DisableTimestamp, error log shows long line trace without timestamp") 147 | glg.Info("after configure TraceLineLong and DisableTimestamp, info log shows long line trace without timestamp") 148 | glg.Get().EnableTimestamp() 149 | glg.Get().SetLineTraceMode(glg.TraceLineNone) 150 | glg.Error("after configure TraceLineNone, error log without line trace") 151 | glg.Info("after configure TraceLineNone, info log without line trace") 152 | glg.Get().SetLevelLineTraceMode(glg.INFO, glg.TraceLineLong) 153 | glg.Info("after configure Level trace INFO=TraceLineLong, only info log shows long line trace") 154 | glg.Error("after configure Level trace INFO=TraceLineLong, error log without long line trace") 155 | glg.Get().SetLevelLineTraceMode(glg.ERR, glg.TraceLineShort) 156 | glg.Info("after configure Level trace ERR=TraceLineShort, info log still shows long line trace") 157 | glg.Error("after configure Level trace ERR=TraceLineShort, error log now shows short line trace") 158 | glg.Get().SetLineTraceMode(glg.TraceLineNone) 159 | 160 | glg.Info("kpango's glg support json logging") 161 | glg.Get().EnableJSON() 162 | err := glg.Warn("kpango's glg", "support", "json", "logging") 163 | if err != nil { 164 | glg.Get().DisableJSON() 165 | glg.Error(err) 166 | glg.Get().EnableJSON() 167 | } 168 | err = glg.Info("hello", struct { 169 | Name string 170 | Age int 171 | Gender string 172 | }{ 173 | Name: "kpango", 174 | Age: 28, 175 | Gender: "male", 176 | }, 2020) 177 | if err != nil { 178 | glg.Get().DisableJSON() 179 | glg.Error(err) 180 | glg.Get().EnableJSON() 181 | } glg.CustomLog(customTag, "custom logging") 182 | 183 | glg.CustomLog(customErrTag, "custom error logging") 184 | 185 | glg.Get().AddLevelWriter(glg.DEBG, NetWorkLogger{}) // add info log file destination 186 | 187 | http.Handle("/glg", glg.HTTPLoggerFunc("glg sample", func(w http.ResponseWriter, r *http.Request) { 188 | glg.New(). 189 | AddLevelWriter(glg.Info, NetWorkLogger{}). 190 | AddLevelWriter(glg.Info, w). 191 | Info("glg HTTP server logger sample") 192 | })) 193 | 194 | http.ListenAndServe("port", nil) 195 | 196 | // fatal logging 197 | glg.Fatalln("fatal") 198 | } 199 | ``` 200 | 201 |
202 | 203 |
204 | 205 | ## Benchmarks 206 | 207 |
208 | 209 |
210 | 211 | ## Contribution 212 | 1. Fork it ( https://github.com/kpango/glg/fork ) 213 | 2. Create your feature branch (git checkout -b my-new-feature) 214 | 3. Commit your changes (git commit -am 'Add some feature') 215 | 4. Push to the branch (git push origin my-new-feature) 216 | 5. Create new Pull Request 217 | 218 | ## Author 219 | [kpango](https://github.com/kpango) 220 | 221 | ## LICENSE 222 | glg released under MIT license, refer [LICENSE](https://github.com/kpango/glg/blob/main/LICENSE) file. 223 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fkpango%2Fglg.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkpango%2Fglg?ref=badge_large) 224 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "errors" 7 | "io" 8 | "net/http" 9 | "os" 10 | "sync" 11 | "time" 12 | 13 | "github.com/kpango/glg" 14 | ) 15 | 16 | var dummyObject = struct { 17 | Age int `json:"age,omitempty"` 18 | Name string `json:"name,omitempty"` 19 | IsProgrammer bool `json:"is_programmer,omitempty"` 20 | }{ 21 | Age: 29, 22 | Name: "Yusuke Kato", 23 | IsProgrammer: true, 24 | } 25 | 26 | // NetWorkLogger sample network logger 27 | type NetWorkLogger struct{} 28 | 29 | func (n NetWorkLogger) Write(b []byte) (int, error) { 30 | // http.Post("localhost:8080/log", "", bytes.NewReader(b)) 31 | http.Get("http://127.0.0.1:8080/log") 32 | glg.Success("Requested") 33 | glg.Infof("RawString is %s", glg.RawString(b)) 34 | return 1, nil 35 | } 36 | 37 | type RotateWriter struct { 38 | writer io.Writer 39 | dur time.Duration 40 | once sync.Once 41 | cancel context.CancelFunc 42 | mu sync.Mutex 43 | buf *bytes.Buffer 44 | } 45 | 46 | func NewRotateWriter(w io.Writer, dur time.Duration, buf *bytes.Buffer) io.WriteCloser { 47 | return &RotateWriter{ 48 | writer: w, 49 | dur: dur, 50 | buf: buf, 51 | } 52 | } 53 | 54 | func (r *RotateWriter) Write(b []byte) (int, error) { 55 | if r.buf == nil || r.writer == nil { 56 | return 0, errors.New("error invalid rotate config") 57 | } 58 | r.once.Do(func() { 59 | var ctx context.Context 60 | ctx, r.cancel = context.WithCancel(context.Background()) 61 | go func() { 62 | tick := time.NewTicker(r.dur) 63 | for { 64 | select { 65 | case <-ctx.Done(): 66 | tick.Stop() 67 | return 68 | case <-tick.C: 69 | r.mu.Lock() 70 | r.writer.Write(r.buf.Bytes()) 71 | r.buf.Reset() 72 | r.mu.Unlock() 73 | } 74 | } 75 | }() 76 | }) 77 | r.mu.Lock() 78 | r.buf.Write(b) 79 | r.mu.Unlock() 80 | return len(b), nil 81 | } 82 | 83 | func (r *RotateWriter) Close() error { 84 | if r.cancel != nil { 85 | r.cancel() 86 | } 87 | return nil 88 | } 89 | 90 | func main() { 91 | // var errWriter io.Writer 92 | // var customWriter io.Writer 93 | infolog := glg.FileWriter("/tmp/info.log", 0o666) 94 | 95 | customTag := "FINE" 96 | customErrTag := "CRIT" 97 | 98 | errlog := glg.FileWriter("/tmp/error.log", 0o666) 99 | rotate := NewRotateWriter(os.Stdout, time.Second*10, bytes.NewBuffer(make([]byte, 0, 4096))) 100 | 101 | defer infolog.Close() 102 | defer errlog.Close() 103 | defer rotate.Close() 104 | 105 | glg.Get(). 106 | SetMode(glg.BOTH). // default is STD 107 | // DisableColor(). 108 | // SetMode(glg.NONE). 109 | // SetMode(glg.WRITER). 110 | // SetMode(glg.BOTH). 111 | // InitWriter(). 112 | // AddWriter(customWriter). 113 | // SetWriter(customWriter). 114 | // AddLevelWriter(glg.LOG, customWriter). 115 | // AddLevelWriter(glg.INFO, customWriter). 116 | // AddLevelWriter(glg.WARN, customWriter). 117 | // AddLevelWriter(glg.ERR, customWriter). 118 | // SetLevelWriter(glg.LOG, customWriter). 119 | // SetLevelWriter(glg.INFO, customWriter). 120 | // SetLevelWriter(glg.WARN, customWriter). 121 | // SetLevelWriter(glg.ERR, customWriter). 122 | // EnableJSON(). 123 | SetLineTraceMode(glg.TraceLineNone). 124 | AddLevelWriter(glg.INFO, infolog). // add info log file destination 125 | AddLevelWriter(glg.ERR, errlog). // add error log file destination 126 | AddLevelWriter(glg.WARN, rotate) // add error log file destination 127 | 128 | glg.Info("info") 129 | glg.Infof("%s : %s", "info", "formatted") 130 | glg.Log("log") 131 | glg.Logf("%s : %s", "info", "formatted") 132 | glg.Debug("debug") 133 | glg.Debugf("%s : %s", "info", "formatted") 134 | glg.Trace("Trace") 135 | glg.Tracef("%s : %s", "tracef", "formatted") 136 | glg.Warn("warn") 137 | glg.Warnf("%s : %s", "info", "formatted") 138 | glg.Error("error") 139 | glg.Errorf("%s : %s", "info", "formatted") 140 | glg.Success("ok") 141 | glg.Successf("%s : %s", "info", "formatted") 142 | glg.Fail("fail") 143 | glg.Failf("%s : %s", "info", "formatted") 144 | glg.Print("Print") 145 | glg.Println("Println") 146 | glg.Printf("%s : %s", "printf", "formatted") 147 | 148 | // set global log level to ERR level 149 | glg.Info("before setting level to ERR this message will show") 150 | glg.Get().SetLevel(glg.ERR) 151 | glg.Info("after setting level to ERR this message will not show") 152 | glg.Error("this log is ERR level this will show") 153 | glg.Get().SetLevel(glg.DEBG) 154 | glg.Info("log level is now DEBG, this INFO level log will show") 155 | 156 | glg.Get(). 157 | AddStdLevel(customTag, glg.STD, false). // user custom log level 158 | AddErrLevel(customErrTag, glg.STD, true). // user custom error log level 159 | SetLevelColor(glg.TagStringToLevel(customTag), glg.Cyan). // set color output to user custom level 160 | SetLevelColor(glg.TagStringToLevel(customErrTag), glg.Red) // set color output to user custom level 161 | glg.CustomLog(customTag, "custom logging") 162 | glg.CustomLog(customErrTag, "custom error logging") 163 | 164 | // glg.Info("kpango's glg supports disable timestamp for logging") 165 | glg.Get().DisableTimestamp() 166 | glg.Info("timestamp disabled") 167 | glg.Warn("timestamp disabled") 168 | glg.Log("timestamp disabled") 169 | glg.Get().EnableTimestamp() 170 | glg.Info("timestamp enabled") 171 | glg.Warn("timestamp enabled") 172 | glg.Log("timestamp enabled") 173 | 174 | glg.Info("kpango's glg support line trace logging") 175 | glg.Error("error log shows short line trace by default") 176 | glg.Info("error log shows none trace by default") 177 | glg.Get().SetLineTraceMode(glg.TraceLineShort) 178 | glg.Error("after configure TraceLineShort, error log shows short line trace") 179 | glg.Info("after configure TraceLineShort, info log shows short line trace") 180 | glg.Get().DisableTimestamp() 181 | glg.Error("after configure TraceLineShort and DisableTimestamp, error log shows short line trace without timestamp") 182 | glg.Info("after configure TraceLineShort and DisableTimestamp, info log shows short line trace without timestamp") 183 | glg.Get().EnableTimestamp() 184 | glg.Get().SetLineTraceMode(glg.TraceLineLong) 185 | glg.Error("after configure TraceLineLong, error log shows long line trace") 186 | glg.Info("after configure TraceLineLong, info log shows long line trace") 187 | glg.Get().DisableTimestamp() 188 | glg.Error("after configure TraceLineLong and DisableTimestamp, error log shows long line trace without timestamp") 189 | glg.Info("after configure TraceLineLong and DisableTimestamp, info log shows long line trace without timestamp") 190 | glg.Get().EnableTimestamp() 191 | glg.Get().SetLineTraceMode(glg.TraceLineNone) 192 | glg.Error("after configure TraceLineNone, error log without line trace") 193 | glg.Info("after configure TraceLineNone, info log without line trace") 194 | glg.Get().SetLevelLineTraceMode(glg.INFO, glg.TraceLineLong) 195 | glg.Info("after configure Level trace INFO=TraceLineLong, only info log shows long line trace") 196 | glg.Error("after configure Level trace INFO=TraceLineLong, error log without long line trace") 197 | glg.Get().SetLevelLineTraceMode(glg.ERR, glg.TraceLineShort) 198 | glg.Info("after configure Level trace ERR=TraceLineShort, info log still shows long line trace") 199 | glg.Error("after configure Level trace ERR=TraceLineShort, error log now shows short line trace") 200 | glg.Get().SetLineTraceMode(glg.TraceLineNone) 201 | 202 | glg.Info("kpango's glg support json logging") 203 | glg.Get().EnableJSON() 204 | err := glg.Warn("kpango's glg", "support", "json", "logging") 205 | if err != nil { 206 | glg.Get().DisableJSON() 207 | glg.Error(err) 208 | glg.Get().EnableJSON() 209 | } 210 | err = glg.Info("hello", struct { 211 | Name string 212 | Age int 213 | Gender string 214 | }{ 215 | Name: "kpango", 216 | Age: 28, 217 | Gender: "male", 218 | }, 2020) 219 | if err != nil { 220 | glg.Get().DisableJSON() 221 | glg.Error(err) 222 | glg.Get().EnableJSON() 223 | } 224 | 225 | go func() { 226 | time.Sleep(time.Second * 5) 227 | for i := 0; i < 100; i++ { 228 | glg.Info("info") 229 | } 230 | }() 231 | 232 | go func() { 233 | time.Sleep(time.Second * 5) 234 | for i := 0; i < 100; i++ { 235 | glg.Debug("debug") 236 | time.Sleep(time.Millisecond * 100) 237 | } 238 | }() 239 | 240 | go func() { 241 | time.Sleep(time.Second * 5) 242 | for i := 0; i < 100; i++ { 243 | glg.Warn("warn") 244 | } 245 | }() 246 | 247 | go func() { 248 | time.Sleep(time.Second * 5) 249 | for i := 0; i < 100; i++ { 250 | glg.Error("error") 251 | time.Sleep(time.Millisecond * 100) 252 | glg.CustomLog(customTag, dummyObject) 253 | } 254 | }() 255 | 256 | glg.Get().AddLevelWriter(glg.DEBG, NetWorkLogger{}).EnableJSON() // add info log file destination 257 | 258 | http.Handle("/glg", glg.HTTPLoggerFunc("glg sample", func(w http.ResponseWriter, r *http.Request) { 259 | glg.Info("glg HTTP server logger sample") 260 | })) 261 | 262 | http.Handle("/log", glg.HTTPLoggerFunc("log", func(w http.ResponseWriter, r *http.Request) { 263 | glg.Info("received") 264 | })) 265 | 266 | http.ListenAndServe(":8080", nil) 267 | 268 | glg.Get().SetLineTraceMode(glg.TraceLineLong) 269 | // fatal logging 270 | glg.Fatalln("fatal") 271 | } 272 | -------------------------------------------------------------------------------- /glg.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2019 kpango (Yusuke Kato) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | // Package glg can quickly output that are colored and leveled logs with simple syntax 24 | package glg 25 | 26 | import ( 27 | "bytes" 28 | "errors" 29 | "fmt" 30 | "io" 31 | "io/fs" 32 | "math" 33 | "net/http" 34 | "os" 35 | "path/filepath" 36 | "runtime" 37 | "strconv" 38 | "strings" 39 | "sync" 40 | "sync/atomic" 41 | "time" 42 | "unsafe" 43 | 44 | json "github.com/goccy/go-json" 45 | "github.com/kpango/fastime" 46 | ) 47 | 48 | // Glg is glg base struct 49 | type Glg struct { 50 | bs *uint64 51 | logger loggers 52 | levelCounter *uint32 53 | levelMap levelMap 54 | buffer sync.Pool 55 | callerDepth int 56 | enableJSON bool 57 | } 58 | 59 | // JSONFormat is json object structure for logging 60 | type JSONFormat struct { 61 | Date string `json:"date,omitempty"` 62 | Level string `json:"level,omitempty"` 63 | File string `json:"file,omitempty"` 64 | Detail interface{} `json:"detail,omitempty"` 65 | } 66 | 67 | // MODE is logging mode (std only, writer only, std & writer) 68 | type MODE uint8 69 | 70 | // LEVEL is log level 71 | type LEVEL uint8 72 | 73 | type wMode uint8 74 | 75 | type traceMode int64 76 | 77 | type logger struct { 78 | tag string 79 | rawtag []byte 80 | writer io.Writer 81 | std io.Writer 82 | color func(string) string 83 | isColor bool 84 | traceMode traceMode 85 | mode MODE 86 | prevMode MODE 87 | writeMode wMode 88 | disableTimestamp bool 89 | } 90 | 91 | const ( 92 | // DEBG is debug log level 93 | DEBG LEVEL = iota + 1 94 | // TRACE is trace log level 95 | TRACE 96 | // PRINT is print log level 97 | PRINT 98 | // LOG is log level 99 | LOG 100 | // INFO is info log level 101 | INFO 102 | // OK is success notify log level 103 | OK 104 | // WARN is warning log level 105 | WARN 106 | // ERR is error log level 107 | ERR 108 | // FAIL is failed log level 109 | FAIL 110 | // FATAL is fatal log level 111 | FATAL 112 | 113 | // UNKNOWN is unknown log level 114 | UNKNOWN LEVEL = LEVEL(math.MaxUint8) 115 | 116 | // NONE is disable Logging 117 | NONE MODE = iota + 1 118 | // STD is std log mode 119 | STD 120 | // BOTH is both log mode 121 | BOTH 122 | // WRITER is io.Writer log mode 123 | WRITER 124 | 125 | // Internal writeMode 126 | writeColorStd wMode = iota + 1 127 | writeStd 128 | writeWriter 129 | writeColorBoth 130 | writeBoth 131 | none 132 | 133 | // Default Format 134 | df = "%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " + 135 | "%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " + 136 | "%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " + 137 | "%v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v %v " 138 | 139 | dfl = len(df) / 3 140 | 141 | timeFormat = "2006-01-02 15:04:05" 142 | 143 | // return code 144 | rc = "\n" 145 | rcl = len(rc) 146 | 147 | tab = "\t" 148 | lsep = tab + "[" 149 | lsepl = len(lsep) 150 | sep = "]:" + tab 151 | sepl = len(sep) 152 | 153 | TraceLineNone traceMode = 1 << iota 154 | TraceLineShort 155 | TraceLineLong 156 | 157 | DefaultCallerDepth = 2 158 | ) 159 | 160 | var ( 161 | glg *Glg 162 | once sync.Once 163 | 164 | // exit for Faltal error 165 | exit = os.Exit 166 | ) 167 | 168 | func init() { 169 | Get() 170 | } 171 | 172 | func (l LEVEL) String() string { 173 | switch l { 174 | case DEBG: 175 | return "DEBG" 176 | case TRACE: 177 | return "TRACE" 178 | case PRINT: 179 | return "PRINT" 180 | case LOG: 181 | return "LOG" 182 | case INFO: 183 | return "INFO" 184 | case OK: 185 | return "OK" 186 | case WARN: 187 | return "WARN" 188 | case ERR: 189 | return "ERR" 190 | case FAIL: 191 | return "FAIL" 192 | case FATAL: 193 | return "FATAL" 194 | } 195 | return "" 196 | } 197 | 198 | func (l *logger) updateMode() *logger { 199 | switch { 200 | case l.mode == WRITER && l.writer != nil: 201 | l.writeMode = writeWriter 202 | case l.mode == BOTH && l.isColor && l.writer != nil: 203 | l.writeMode = writeColorBoth 204 | case l.mode == BOTH && !l.isColor && l.writer != nil: 205 | l.writeMode = writeBoth 206 | case l.isColor && ((l.mode == BOTH && l.writer == nil) || l.mode == STD): 207 | l.writeMode = writeColorStd 208 | case !l.isColor && ((l.mode == BOTH && l.writer == nil) || l.mode == STD): 209 | l.writeMode = writeStd 210 | default: 211 | l.writeMode = none 212 | } 213 | return l 214 | } 215 | 216 | // New returns plain glg instance 217 | func New() *Glg { 218 | g := &Glg{ 219 | levelCounter: new(uint32), 220 | callerDepth: DefaultCallerDepth, 221 | } 222 | g.bs = new(uint64) 223 | 224 | atomic.StoreUint64(g.bs, uint64(len(timeFormat)+lsepl+sepl)) 225 | 226 | g.buffer = sync.Pool{ 227 | New: func() interface{} { 228 | return bytes.NewBuffer(make([]byte, 0, int(atomic.LoadUint64(g.bs)))) 229 | }, 230 | } 231 | 232 | atomic.StoreUint32(g.levelCounter, uint32(FATAL)) 233 | 234 | for lev, log := range map[LEVEL]*logger{ 235 | // standard out 236 | DEBG: { 237 | std: os.Stdout, 238 | color: Purple, 239 | isColor: true, 240 | mode: STD, 241 | traceMode: TraceLineNone, 242 | }, 243 | TRACE: { 244 | std: os.Stdout, 245 | color: Yellow, 246 | isColor: true, 247 | mode: STD, 248 | traceMode: TraceLineNone, 249 | }, 250 | PRINT: { 251 | std: os.Stdout, 252 | color: Colorless, 253 | isColor: true, 254 | mode: STD, 255 | traceMode: TraceLineNone, 256 | }, 257 | LOG: { 258 | std: os.Stdout, 259 | color: Colorless, 260 | isColor: true, 261 | mode: STD, 262 | traceMode: TraceLineNone, 263 | }, 264 | INFO: { 265 | std: os.Stdout, 266 | color: Green, 267 | isColor: true, 268 | mode: STD, 269 | traceMode: TraceLineNone, 270 | }, 271 | OK: { 272 | std: os.Stdout, 273 | color: Cyan, 274 | isColor: true, 275 | mode: STD, 276 | traceMode: TraceLineNone, 277 | }, 278 | WARN: { 279 | std: os.Stdout, 280 | color: Orange, 281 | isColor: true, 282 | mode: STD, 283 | traceMode: TraceLineNone, 284 | }, 285 | // error out 286 | ERR: { 287 | std: os.Stderr, 288 | color: Red, 289 | isColor: true, 290 | mode: STD, 291 | traceMode: TraceLineShort, 292 | }, 293 | FAIL: { 294 | std: os.Stderr, 295 | color: Red, 296 | isColor: true, 297 | mode: STD, 298 | traceMode: TraceLineShort, 299 | }, 300 | FATAL: { 301 | std: os.Stderr, 302 | color: Red, 303 | isColor: true, 304 | mode: STD, 305 | traceMode: TraceLineLong, 306 | }, 307 | } { 308 | log.tag = lev.String() 309 | log.rawtag = []byte(lsep + log.tag + sep) 310 | log.prevMode = log.mode 311 | log.updateMode() 312 | g.logger.Store(lev, log) 313 | } 314 | 315 | return g 316 | } 317 | 318 | // Get returns singleton glg instance 319 | func Get() *Glg { 320 | once.Do(func() { 321 | fastime.SetFormat(timeFormat) 322 | glg = New() 323 | }) 324 | return glg 325 | } 326 | 327 | func (g *Glg) EnableJSON() *Glg { 328 | g.enableJSON = true 329 | return g 330 | } 331 | 332 | func (g *Glg) DisableJSON() *Glg { 333 | g.enableJSON = false 334 | return g 335 | } 336 | 337 | func (g *Glg) EnablePoolBuffer(size int) *Glg { 338 | for range make([]struct{}, size) { 339 | g.buffer.Put(g.buffer.Get().(*bytes.Buffer)) 340 | } 341 | return g 342 | } 343 | 344 | // SetLevel sets glg global log level 345 | func (g *Glg) SetLevel(lv LEVEL) *Glg { 346 | g.logger.Range(func(lev LEVEL, l *logger) bool { 347 | if lev < lv { 348 | l.prevMode = l.mode 349 | l.mode = NONE 350 | } else { 351 | l.mode = l.prevMode 352 | } 353 | l.updateMode() 354 | g.logger.Store(lev, l) 355 | return true 356 | }) 357 | return g 358 | } 359 | 360 | // SetMode sets glg logging mode 361 | func (g *Glg) SetMode(mode MODE) *Glg { 362 | g.logger.Range(func(lev LEVEL, l *logger) bool { 363 | l.mode = mode 364 | l.prevMode = mode 365 | l.updateMode() 366 | g.logger.Store(lev, l) 367 | return true 368 | }) 369 | 370 | return g 371 | } 372 | 373 | // SetLevelMode sets glg logging mode* per level 374 | func (g *Glg) SetLevelMode(level LEVEL, mode MODE) *Glg { 375 | l, ok := g.logger.Load(level) 376 | if ok { 377 | l.mode = mode 378 | l.prevMode = mode 379 | l.updateMode() 380 | g.logger.Store(level, l) 381 | } 382 | return g 383 | } 384 | 385 | // SetPrefix sets Print logger prefix 386 | func SetPrefix(lev LEVEL, pref string) *Glg { 387 | return glg.SetPrefix(lev, pref) 388 | } 389 | 390 | // SetPrefix sets Print logger prefix 391 | func (g *Glg) SetPrefix(lev LEVEL, pref string) *Glg { 392 | l, ok := g.logger.Load(lev) 393 | if ok { 394 | l.tag = pref 395 | l.rawtag = []byte(lsep + l.tag + sep) 396 | g.logger.Store(lev, l) 397 | } 398 | return g 399 | } 400 | 401 | // GetCurrentMode returns current logging mode 402 | func (g *Glg) GetCurrentMode(level LEVEL) MODE { 403 | l, ok := g.logger.Load(level) 404 | if ok { 405 | return l.mode 406 | } 407 | return NONE 408 | } 409 | 410 | // InitWriter is initialize glg writer 411 | func (g *Glg) InitWriter() *Glg { 412 | g.logger.Range(func(lev LEVEL, l *logger) bool { 413 | l.writer = nil 414 | l.updateMode() 415 | g.logger.Store(lev, l) 416 | return true 417 | }) 418 | return g 419 | } 420 | 421 | // SetWriter sets writer to glg std writers 422 | func (g *Glg) SetWriter(writer io.Writer) *Glg { 423 | if writer == nil { 424 | return g 425 | } 426 | 427 | g.logger.Range(func(lev LEVEL, l *logger) bool { 428 | l.writer = writer 429 | l.updateMode() 430 | g.logger.Store(lev, l) 431 | return true 432 | }) 433 | 434 | return g 435 | } 436 | 437 | // AddWriter adds writer to glg std writers 438 | func (g *Glg) AddWriter(writer io.Writer) *Glg { 439 | if writer == nil { 440 | return g 441 | } 442 | 443 | g.logger.Range(func(lev LEVEL, l *logger) bool { 444 | if l.writer == nil { 445 | l.writer = writer 446 | } else { 447 | l.writer = io.MultiWriter(l.writer, writer) 448 | } 449 | l.updateMode() 450 | g.logger.Store(lev, l) 451 | return true 452 | }) 453 | 454 | return g 455 | } 456 | 457 | // SetLevelColor sets the color for each level 458 | func (g *Glg) SetLevelColor(level LEVEL, color func(string) string) *Glg { 459 | l, ok := g.logger.Load(level) 460 | if ok { 461 | l.color = color 462 | g.logger.Store(level, l) 463 | } 464 | 465 | return g 466 | } 467 | 468 | // SetLevelWriter sets writer to glg std writer per logging level 469 | func (g *Glg) SetLevelWriter(level LEVEL, writer io.Writer) *Glg { 470 | if writer == nil { 471 | return g 472 | } 473 | 474 | l, ok := g.logger.Load(level) 475 | if ok { 476 | l.writer = writer 477 | l.updateMode() 478 | g.logger.Store(level, l) 479 | } 480 | 481 | return g 482 | } 483 | 484 | // AddLevelWriter adds writer to glg std writer per logging level 485 | func (g *Glg) AddLevelWriter(level LEVEL, writer io.Writer) *Glg { 486 | if writer == nil { 487 | return g 488 | } 489 | 490 | l, ok := g.logger.Load(level) 491 | if ok { 492 | if l.writer != nil { 493 | l.writer = io.MultiWriter(l.writer, writer) 494 | } else { 495 | l.writer = writer 496 | } 497 | l.updateMode() 498 | g.logger.Store(level, l) 499 | } 500 | 501 | return g 502 | } 503 | 504 | // AddStdLevel adds std log level and returns LEVEL 505 | func (g *Glg) AddStdLevel(tag string, mode MODE, isColor bool) *Glg { 506 | return g.addLevel(tag, mode, isColor, os.Stdout) 507 | } 508 | 509 | // AddErrLevel adds error log level and returns LEVEL 510 | func (g *Glg) AddErrLevel(tag string, mode MODE, isColor bool) *Glg { 511 | return g.addLevel(tag, mode, isColor, os.Stderr) 512 | } 513 | 514 | func (g *Glg) addLevel(tag string, mode MODE, isColor bool, std io.Writer) *Glg { 515 | lev := LEVEL(atomic.AddUint32(g.levelCounter, 1)) 516 | tag = strings.ToUpper(tag) 517 | g.levelMap.Store(tag, lev) 518 | l := &logger{ 519 | writer: nil, 520 | std: std, 521 | color: Colorless, 522 | isColor: isColor, 523 | mode: mode, 524 | prevMode: mode, 525 | tag: tag, 526 | rawtag: []byte(lsep + tag + sep), 527 | } 528 | l.updateMode() 529 | g.logger.Store(lev, l) 530 | return g 531 | } 532 | 533 | // SetTimeLocation configures specific time location 534 | func (g *Glg) SetTimeLocation(loc *time.Location) *Glg { 535 | if loc != nil { 536 | fastime.SetLocation(loc) 537 | } 538 | return g 539 | } 540 | 541 | // GetTimeLocation configures specific time location 542 | func (g *Glg) GetTimeLocation() (loc *time.Location) { 543 | return fastime.GetLocation() 544 | } 545 | 546 | // EnableTimestamp enables timestamp output 547 | func (g *Glg) EnableTimestamp() *Glg { 548 | g.logger.Range(func(lev LEVEL, l *logger) bool { 549 | l.disableTimestamp = false 550 | g.logger.Store(lev, l) 551 | return true 552 | }) 553 | 554 | return g 555 | } 556 | 557 | // DisableTimestamp disables timestamp output 558 | func (g *Glg) DisableTimestamp() *Glg { 559 | g.logger.Range(func(lev LEVEL, l *logger) bool { 560 | l.disableTimestamp = true 561 | g.logger.Store(lev, l) 562 | return true 563 | }) 564 | 565 | return g 566 | } 567 | 568 | // EnableLevelTimestamp enables timestamp output 569 | func (g *Glg) EnableLevelTimestamp(lv LEVEL) *Glg { 570 | l, ok := g.logger.Load(lv) 571 | if ok { 572 | l.disableTimestamp = false 573 | g.logger.Store(lv, l) 574 | } 575 | return g 576 | } 577 | 578 | // DisableLevelTimestamp disables timestamp output 579 | func (g *Glg) DisableLevelTimestamp(lv LEVEL) *Glg { 580 | l, ok := g.logger.Load(lv) 581 | if ok { 582 | l.disableTimestamp = true 583 | g.logger.Store(lv, l) 584 | } 585 | return g 586 | } 587 | 588 | // SetCallerDepth configures output line trace caller depth 589 | func (g *Glg) SetCallerDepth(depth int) *Glg { 590 | if depth > DefaultCallerDepth { 591 | g.callerDepth = depth 592 | } 593 | return g 594 | } 595 | 596 | // SetLineTraceMode configures output line traceFlag 597 | func (g *Glg) SetLineTraceMode(mode traceMode) *Glg { 598 | g.logger.Range(func(lev LEVEL, l *logger) bool { 599 | l.traceMode = mode 600 | g.logger.Store(lev, l) 601 | return true 602 | }) 603 | return g 604 | } 605 | 606 | // SetLevelLineTraceMode configures output line traceFlag 607 | func (g *Glg) SetLevelLineTraceMode(lv LEVEL, mode traceMode) *Glg { 608 | l, ok := g.logger.Load(lv) 609 | if ok { 610 | l.traceMode = mode 611 | g.logger.Store(lv, l) 612 | } 613 | return g 614 | } 615 | 616 | // EnableColor enables color output 617 | func (g *Glg) EnableColor() *Glg { 618 | g.logger.Range(func(lev LEVEL, l *logger) bool { 619 | l.isColor = true 620 | l.updateMode() 621 | g.logger.Store(lev, l) 622 | return true 623 | }) 624 | 625 | return g 626 | } 627 | 628 | // DisableColor disables color output 629 | func (g *Glg) DisableColor() *Glg { 630 | g.logger.Range(func(lev LEVEL, l *logger) bool { 631 | l.isColor = false 632 | l.updateMode() 633 | g.logger.Store(lev, l) 634 | return true 635 | }) 636 | 637 | return g 638 | } 639 | 640 | // EnableLevelColor enables color output 641 | func (g *Glg) EnableLevelColor(lv LEVEL) *Glg { 642 | l, ok := g.logger.Load(lv) 643 | if ok { 644 | l.isColor = true 645 | l.updateMode() 646 | g.logger.Store(lv, l) 647 | } 648 | return g 649 | } 650 | 651 | // DisableLevelColor disables color output 652 | func (g *Glg) DisableLevelColor(lv LEVEL) *Glg { 653 | l, ok := g.logger.Load(lv) 654 | if ok { 655 | l.isColor = false 656 | l.updateMode() 657 | g.logger.Store(lv, l) 658 | } 659 | return g 660 | } 661 | 662 | // RawString returns raw log string exclude time & tags 663 | func (g *Glg) RawString(data []byte) string { 664 | str := *(*string)(unsafe.Pointer(&data)) 665 | return str[strings.Index(str, sep)+sepl : len(str)-rcl] 666 | } 667 | 668 | // RawString returns raw log string exclude time & tags 669 | func RawString(data []byte) string { 670 | return glg.RawString(data) 671 | } 672 | 673 | // Atol converts level string to Glg.LEVEL 674 | func (g *Glg) Atol(tag string) LEVEL { 675 | return g.TagStringToLevel(tag) 676 | } 677 | 678 | // Atol converts level string to Glg.LEVEL 679 | func Atol(tag string) LEVEL { 680 | return glg.TagStringToLevel(tag) 681 | } 682 | 683 | // TagStringToLevel converts level string to Glg.LEVEL 684 | func (g *Glg) TagStringToLevel(tag string) LEVEL { 685 | tag = strings.TrimSpace(strings.ToUpper(tag)) 686 | lv, ok := g.levelMap.Load(tag) 687 | if ok { 688 | return lv 689 | } 690 | switch tag { 691 | case DEBG.String(), "DBG", "DEBUG", "D": 692 | return DEBG 693 | case TRACE.String(), "TRC", "TRA", "TR", "T": 694 | return TRACE 695 | case PRINT.String(), "PRINT", "PNT", "P": 696 | return PRINT 697 | case LOG.String(), "LO", "LG", "L": 698 | return LOG 699 | case INFO.String(), "IFO", "INF", "I": 700 | return INFO 701 | case OK.String(), "O", "K": 702 | return OK 703 | case WARN.String(), "WARNING", "WRN", "W": 704 | return WARN 705 | case ERR.String(), "ERROR", "ER", "E": 706 | return ERR 707 | case FAIL.String(), "FAILED", "FI": 708 | return FAIL 709 | case FATAL.String(), "FAT", "FL", "F": 710 | return FATAL 711 | } 712 | return UNKNOWN 713 | } 714 | 715 | // TagStringToLevel converts level string to glg.LEVEL 716 | func TagStringToLevel(tag string) LEVEL { 717 | return glg.TagStringToLevel(tag) 718 | } 719 | 720 | func OpenFile(path string, flg int, perm fs.FileMode) (file *os.File, err error) { 721 | if path == "" { 722 | return nil, errors.New("file path argument must not be empty") 723 | } 724 | 725 | defer func() { 726 | if err != nil && file != nil { 727 | err = errors.Join(file.Close(), err) 728 | file = nil 729 | } 730 | }() 731 | if ffi, err := os.Stat(path); err != nil { 732 | dir := filepath.Dir(path) 733 | fi, err := os.Stat(dir) 734 | if err != nil { 735 | err = os.MkdirAll(dir, perm) 736 | if err != nil { 737 | err = fmt.Errorf("failed to make directory %s using os.MkdirAll operation\tdir info: %s: %w", dir, fitos(dir, fi), err) 738 | return nil, err 739 | } 740 | } 741 | 742 | if flg&(os.O_CREATE|os.O_APPEND) > 0 { 743 | file, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_TRUNC, perm) 744 | if err != nil { 745 | err = fmt.Errorf("failed to create file %s using os.Create operation\tfile info: %s: %w", path, fitos(path, ffi), err) 746 | if file != nil { 747 | return nil, errors.Join(err, file.Close()) 748 | } 749 | return nil, err 750 | } 751 | if file != nil { 752 | err = file.Close() 753 | if err != nil { 754 | fi, ferr := file.Stat() 755 | if ferr == nil && fi != nil { 756 | return nil, fmt.Errorf("failed to close file %s\tfile info: %s: %w", path, fitos(path, fi), err) 757 | } 758 | return nil, errors.Join(err, ferr) 759 | } 760 | } 761 | } 762 | } 763 | 764 | file, err = os.OpenFile(path, flg, perm) 765 | if err != nil { 766 | err = fmt.Errorf("failed to open file %s using os.OpenFile operation with configuration, flg: %d, perm: %s\tfile info: %s: %w", path, flg, perm.String(), fitos(path, nil), err) 767 | if file != nil { 768 | return nil, errors.Join(err, file.Close()) 769 | } 770 | return nil, err 771 | } 772 | 773 | return file, nil 774 | } 775 | 776 | func fitos(path string, fi os.FileInfo) string { 777 | if fi == nil { 778 | var err error 779 | fi, err = os.Stat(path) 780 | if err != nil || fi == nil { 781 | return fmt.Sprintf("unknown file info: for %s\t%v", path, fi) 782 | } 783 | } 784 | if fi != nil { 785 | return fmt.Sprintf("{name: %s, size: %d, mode: %s, mode_int: %d, is_dir: %v}", 786 | fi.Name(), 787 | fi.Size(), 788 | fi.Mode().String(), 789 | fi.Mode(), 790 | fi.IsDir(), 791 | ) 792 | } 793 | return fmt.Sprintf("unknown file info: %v", fi) 794 | } 795 | 796 | // FileWriter generates *osFile -> io.Writer 797 | func FileWriter(path string, perm os.FileMode) *os.File { 798 | f, err := OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, perm) 799 | if err != nil { 800 | return nil 801 | } 802 | return f 803 | } 804 | 805 | // HTTPLogger is simple http access logger 806 | func (g *Glg) HTTPLogger(name string, handler http.Handler) http.Handler { 807 | return g.HTTPLoggerFunc(name, handler.ServeHTTP) 808 | } 809 | 810 | // HTTPLoggerFunc is simple http access logger 811 | func (g *Glg) HTTPLoggerFunc(name string, hf http.HandlerFunc) http.Handler { 812 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 813 | start := fastime.UnixNanoNow() 814 | 815 | hf(w, r) 816 | 817 | start -= fastime.UnixNanoNow() 818 | 819 | err := g.Logf("Method: %s\tURI: %s\tName: %s\tTime: %s", 820 | r.Method, r.RequestURI, name, (*(*time.Duration)(unsafe.Pointer(&start))).String()) 821 | if err != nil { 822 | err = g.Error(err) 823 | if err != nil { 824 | fmt.Println(err) 825 | } 826 | } 827 | }) 828 | } 829 | 830 | // HTTPLogger is simple http access logger 831 | func HTTPLogger(name string, handler http.Handler) http.Handler { 832 | return glg.HTTPLogger(name, handler) 833 | } 834 | 835 | // HTTPLoggerFunc is simple http access logger 836 | func HTTPLoggerFunc(name string, hf http.HandlerFunc) http.Handler { 837 | return glg.HTTPLoggerFunc(name, hf) 838 | } 839 | 840 | // Colorless returns colorless string 841 | func Colorless(str string) string { 842 | return str 843 | } 844 | 845 | func colorString(code, str string) string { 846 | return "\033["+code+"m" + str + "\033[39m" 847 | } 848 | 849 | // Red returns red colored string 850 | func Red(str string) string { 851 | return colorString("31", str) 852 | } 853 | 854 | // Green returns green colored string 855 | func Green(str string) string { 856 | return colorString("32", str) 857 | } 858 | 859 | // Orange returns orange colored string 860 | func Orange(str string) string { 861 | return colorString("33", str) 862 | } 863 | 864 | // Purple returns purple colored string 865 | func Purple(str string) string { 866 | return colorString("34", str) 867 | } 868 | 869 | // Cyan returns cyan colored string 870 | func Cyan(str string) string { 871 | return colorString("36", str) 872 | } 873 | 874 | // Yellow returns yellow colored string 875 | func Yellow(str string) string { 876 | return colorString("93", str) 877 | } 878 | 879 | // Brown returns Brown colored string 880 | func Brown(str string) string { 881 | return colorString("96", str) 882 | } 883 | 884 | // Gray returns Gray colored string 885 | func Gray(str string) string { 886 | return colorString("90", str) 887 | } 888 | 889 | // Black returns Black colored string 890 | func Black(str string) string { 891 | return colorString("30", str) 892 | } 893 | 894 | // White returns white colored string 895 | func White(str string) string { 896 | return colorString("97", str) 897 | } 898 | 899 | func (g *Glg) out(level LEVEL, format string, val ...interface{}) error { 900 | log, ok := g.logger.Load(level) 901 | if !ok { 902 | return fmt.Errorf("error:\tLog Level %d Not Found", level) 903 | } 904 | 905 | if log.mode == NONE { 906 | return nil 907 | } 908 | 909 | var fl string 910 | if log.traceMode&(TraceLineLong|TraceLineShort) != 0 { 911 | _, file, line, ok := runtime.Caller(g.callerDepth) 912 | switch { 913 | case !ok: 914 | fl = "???:0" 915 | case log.traceMode&TraceLineShort != 0: 916 | for i := len(file) - 1; i > 0; i-- { 917 | if file[i] == '/' { 918 | file = file[i+1:] 919 | break 920 | } 921 | } 922 | fl = file + ":" + strconv.Itoa(line) 923 | case strings.HasPrefix(file, runtime.GOROOT()+"/src"): 924 | fl = "https://github.com/golang/go/blob/" + runtime.Version() + strings.TrimPrefix(file, runtime.GOROOT()) + "#L" + strconv.Itoa(line) 925 | case strings.Contains(file, "go/pkg/mod/"): 926 | fl = "https:/" 927 | for _, path := range strings.Split(strings.SplitN(file, "go/pkg/mod/", 2)[1], "/") { 928 | left, right, ok := strings.Cut(path, "@") 929 | if ok { 930 | if strings.Count(right, "-") > 2 { 931 | path = left + "/blob/main" 932 | } else { 933 | path = left + "/blob/" + right 934 | } 935 | } 936 | fl += "/" + path 937 | } 938 | fl += "#L" + strconv.Itoa(line) 939 | case strings.Contains(file, "go/src"): 940 | fl = "https:/" 941 | cnt := 0 942 | for _, path := range strings.Split(strings.SplitN(file, "go/src/", 2)[1], "/") { 943 | if cnt == 3 { 944 | path = "blob/main/" + path 945 | } 946 | fl += "/" + path 947 | cnt++ 948 | } 949 | fl += "#L" + strconv.Itoa(line) 950 | default: 951 | fl = file + ":" + strconv.Itoa(line) 952 | } 953 | } 954 | 955 | if g.enableJSON { 956 | var w io.Writer 957 | switch log.writeMode { 958 | case writeStd, writeColorStd: 959 | w = log.std 960 | case writeWriter: 961 | w = log.writer 962 | case writeBoth, writeColorBoth: 963 | w = io.MultiWriter(log.std, log.writer) 964 | default: 965 | return nil 966 | } 967 | var detail interface{} 968 | if format != "" { 969 | detail = fmt.Sprintf(format, val...) 970 | } else if len(val) > 1 { 971 | detail = val 972 | } else { 973 | detail = val[0] 974 | } 975 | var timestamp string 976 | if !log.disableTimestamp { 977 | fn := fastime.FormattedNow() 978 | timestamp = *(*string)(unsafe.Pointer(&fn)) 979 | } 980 | return json.NewEncoder(w).Encode(JSONFormat{ 981 | Date: timestamp, 982 | Level: log.tag, 983 | File: fl, 984 | Detail: detail, 985 | }) 986 | } 987 | 988 | var ( 989 | buf []byte 990 | err error 991 | b = g.buffer.Get().(*bytes.Buffer) 992 | ) 993 | 994 | if log.disableTimestamp { 995 | b.Write(log.rawtag[len(tab):]) 996 | } else { 997 | b.Write(fastime.FormattedNow()) 998 | b.Write(log.rawtag) 999 | } 1000 | if len(fl) != 0 { 1001 | b.WriteString("(" + fl + "):\t") 1002 | } 1003 | b.WriteString(format) 1004 | 1005 | switch { 1006 | case log.writeMode^writeColorStd == 0: 1007 | buf = b.Bytes() 1008 | _, err = fmt.Fprintf(log.std, log.color(*(*string)(unsafe.Pointer(&buf)))+rc, val...) 1009 | case log.writeMode^writeStd == 0: 1010 | b.WriteString(rc) 1011 | buf = b.Bytes() 1012 | _, err = fmt.Fprintf(log.std, *(*string)(unsafe.Pointer(&buf)), val...) 1013 | case log.writeMode^writeWriter == 0: 1014 | b.WriteString(rc) 1015 | buf = b.Bytes() 1016 | _, err = fmt.Fprintf(log.writer, *(*string)(unsafe.Pointer(&buf)), val...) 1017 | case log.writeMode^writeColorBoth == 0: 1018 | buf = b.Bytes() 1019 | str := *(*string)(unsafe.Pointer(&buf)) 1020 | _, err = fmt.Fprintf(log.std, log.color(str)+rc, val...) 1021 | if err == nil { 1022 | _, err = fmt.Fprintf(log.writer, str+rc, val...) 1023 | } 1024 | case log.writeMode^writeBoth == 0: 1025 | b.WriteString(rc) 1026 | buf = b.Bytes() 1027 | _, err = fmt.Fprintf(io.MultiWriter(log.std, log.writer), *(*string)(unsafe.Pointer(&buf)), val...) 1028 | } 1029 | bl := uint64(len(buf)) 1030 | if atomic.LoadUint64(g.bs) < bl { 1031 | atomic.StoreUint64(g.bs, bl) 1032 | } 1033 | b.Reset() 1034 | g.buffer.Put(b) 1035 | 1036 | return err 1037 | } 1038 | 1039 | // Log writes std log event 1040 | func (g *Glg) Log(val ...interface{}) error { 1041 | return g.out(LOG, g.blankFormat(len(val)), val...) 1042 | } 1043 | 1044 | // Logf writes std log event with format 1045 | func (g *Glg) Logf(format string, val ...interface{}) error { 1046 | return g.out(LOG, format, val...) 1047 | } 1048 | 1049 | // LogFunc outputs Log level log returned from the function 1050 | func (g *Glg) LogFunc(f func() string) error { 1051 | if g.isModeEnable(LOG) { 1052 | return g.out(LOG, "%s", f()) 1053 | } 1054 | return nil 1055 | } 1056 | 1057 | // Log writes std log event 1058 | func Log(val ...interface{}) error { 1059 | return glg.out(LOG, glg.blankFormat(len(val)), val...) 1060 | } 1061 | 1062 | // Logf writes std log event with format 1063 | func Logf(format string, val ...interface{}) error { 1064 | return glg.out(LOG, format, val...) 1065 | } 1066 | 1067 | // LogFunc outputs Log level log returned from the function 1068 | func LogFunc(f func() string) error { 1069 | if isModeEnable(LOG) { 1070 | return glg.out(LOG, "%s", f()) 1071 | } 1072 | return nil 1073 | } 1074 | 1075 | // Info outputs Info level log 1076 | func (g *Glg) Info(val ...interface{}) error { 1077 | return g.out(INFO, g.blankFormat(len(val)), val...) 1078 | } 1079 | 1080 | // Infof outputs formatted Info level log 1081 | func (g *Glg) Infof(format string, val ...interface{}) error { 1082 | return g.out(INFO, format, val...) 1083 | } 1084 | 1085 | // InfoFunc outputs Info level log returned from the function 1086 | func (g *Glg) InfoFunc(f func() string) error { 1087 | if g.isModeEnable(INFO) { 1088 | return g.out(INFO, "%s", f()) 1089 | } 1090 | return nil 1091 | } 1092 | 1093 | // Info outputs Info level log 1094 | func Info(val ...interface{}) error { 1095 | return glg.out(INFO, glg.blankFormat(len(val)), val...) 1096 | } 1097 | 1098 | // Infof outputs formatted Info level log 1099 | func Infof(format string, val ...interface{}) error { 1100 | return glg.out(INFO, format, val...) 1101 | } 1102 | 1103 | // InfoFunc outputs Info level log returned from the function 1104 | func InfoFunc(f func() string) error { 1105 | if isModeEnable(INFO) { 1106 | return glg.out(INFO, "%s", f()) 1107 | } 1108 | return nil 1109 | } 1110 | 1111 | // Success outputs Success level log 1112 | func (g *Glg) Success(val ...interface{}) error { 1113 | return g.out(OK, g.blankFormat(len(val)), val...) 1114 | } 1115 | 1116 | // Successf outputs formatted Success level log 1117 | func (g *Glg) Successf(format string, val ...interface{}) error { 1118 | return g.out(OK, format, val...) 1119 | } 1120 | 1121 | // SuccessFunc outputs Success level log returned from the function 1122 | func (g *Glg) SuccessFunc(f func() string) error { 1123 | if g.isModeEnable(OK) { 1124 | return g.out(OK, "%s", f()) 1125 | } 1126 | return nil 1127 | } 1128 | 1129 | // Success outputs Success level log 1130 | func Success(val ...interface{}) error { 1131 | return glg.out(OK, glg.blankFormat(len(val)), val...) 1132 | } 1133 | 1134 | // Successf outputs formatted Success level log 1135 | func Successf(format string, val ...interface{}) error { 1136 | return glg.out(OK, format, val...) 1137 | } 1138 | 1139 | // SuccessFunc outputs Success level log returned from the function 1140 | func SuccessFunc(f func() string) error { 1141 | if isModeEnable(OK) { 1142 | return glg.out(OK, "%s", f()) 1143 | } 1144 | return nil 1145 | } 1146 | 1147 | // Debug outputs Debug level log 1148 | func (g *Glg) Debug(val ...interface{}) error { 1149 | return g.out(DEBG, g.blankFormat(len(val)), val...) 1150 | } 1151 | 1152 | // Debugf outputs formatted Debug level log 1153 | func (g *Glg) Debugf(format string, val ...interface{}) error { 1154 | return g.out(DEBG, format, val...) 1155 | } 1156 | 1157 | // DebugFunc outputs Debug level log returned from the function 1158 | func (g *Glg) DebugFunc(f func() string) error { 1159 | if g.isModeEnable(DEBG) { 1160 | return g.out(DEBG, "%s", f()) 1161 | } 1162 | return nil 1163 | } 1164 | 1165 | // Debug outputs Debug level log 1166 | func Debug(val ...interface{}) error { 1167 | return glg.out(DEBG, glg.blankFormat(len(val)), val...) 1168 | } 1169 | 1170 | // Debugf outputs formatted Debug level log 1171 | func Debugf(format string, val ...interface{}) error { 1172 | return glg.out(DEBG, format, val...) 1173 | } 1174 | 1175 | // DebugFunc outputs Debug level log returned from the function 1176 | func DebugFunc(f func() string) error { 1177 | if isModeEnable(DEBG) { 1178 | return glg.out(DEBG, "%s", f()) 1179 | } 1180 | return nil 1181 | } 1182 | 1183 | // Warn outputs Warn level log 1184 | func (g *Glg) Warn(val ...interface{}) error { 1185 | return g.out(WARN, g.blankFormat(len(val)), val...) 1186 | } 1187 | 1188 | // Warnf outputs formatted Warn level log 1189 | func (g *Glg) Warnf(format string, val ...interface{}) error { 1190 | return g.out(WARN, format, val...) 1191 | } 1192 | 1193 | // WarnFunc outputs Warn level log returned from the function 1194 | func (g *Glg) WarnFunc(f func() string) error { 1195 | if g.isModeEnable(WARN) { 1196 | return g.out(WARN, "%s", f()) 1197 | } 1198 | return nil 1199 | } 1200 | 1201 | // Warn outputs Warn level log 1202 | func Warn(val ...interface{}) error { 1203 | return glg.out(WARN, glg.blankFormat(len(val)), val...) 1204 | } 1205 | 1206 | // Warnf outputs formatted Warn level log 1207 | func Warnf(format string, val ...interface{}) error { 1208 | return glg.out(WARN, format, val...) 1209 | } 1210 | 1211 | // WarnFunc outputs Warn level log returned from the function 1212 | func WarnFunc(f func() string) error { 1213 | if isModeEnable(WARN) { 1214 | return glg.out(WARN, "%s", f()) 1215 | } 1216 | return nil 1217 | } 1218 | 1219 | // CustomLog outputs custom level log 1220 | func (g *Glg) CustomLog(level string, val ...interface{}) error { 1221 | return g.out(g.TagStringToLevel(level), g.blankFormat(len(val)), val...) 1222 | } 1223 | 1224 | // CustomLogf outputs formatted custom level log 1225 | func (g *Glg) CustomLogf(level string, format string, val ...interface{}) error { 1226 | return g.out(g.TagStringToLevel(level), format, val...) 1227 | } 1228 | 1229 | // CustomLogFunc outputs custom level log returned from the function 1230 | func (g *Glg) CustomLogFunc(level string, f func() string) error { 1231 | lv := g.TagStringToLevel(level) 1232 | if g.isModeEnable(lv) { 1233 | return g.out(lv, "%s", f()) 1234 | } 1235 | return nil 1236 | } 1237 | 1238 | // CustomLog outputs custom level log 1239 | func CustomLog(level string, val ...interface{}) error { 1240 | return glg.out(glg.TagStringToLevel(level), glg.blankFormat(len(val)), val...) 1241 | } 1242 | 1243 | // CustomLogf outputs formatted custom level log 1244 | func CustomLogf(level string, format string, val ...interface{}) error { 1245 | return glg.out(glg.TagStringToLevel(level), format, val...) 1246 | } 1247 | 1248 | // CustomLogFunc outputs custom level log returned from the function 1249 | func CustomLogFunc(level string, f func() string) error { 1250 | lv := TagStringToLevel(level) 1251 | if isModeEnable(lv) { 1252 | return glg.out(lv, "%s", f()) 1253 | } 1254 | return nil 1255 | } 1256 | 1257 | // Trace outputs Trace level log 1258 | func (g *Glg) Trace(val ...interface{}) error { 1259 | return g.out(TRACE, g.blankFormat(len(val)), val...) 1260 | } 1261 | 1262 | // Tracef outputs formatted Trace level log 1263 | func (g *Glg) Tracef(format string, val ...interface{}) error { 1264 | return g.out(TRACE, format, val...) 1265 | } 1266 | 1267 | // TraceFunc outputs Trace level log returned from the function 1268 | func (g *Glg) TraceFunc(f func() string) error { 1269 | if g.isModeEnable(TRACE) { 1270 | return g.out(TRACE, "%s", f()) 1271 | } 1272 | return nil 1273 | } 1274 | 1275 | // Trace outputs Trace level log 1276 | func Trace(val ...interface{}) error { 1277 | return glg.out(TRACE, glg.blankFormat(len(val)), val...) 1278 | } 1279 | 1280 | // Tracef outputs formatted Trace level log 1281 | func Tracef(format string, val ...interface{}) error { 1282 | return glg.out(TRACE, format, val...) 1283 | } 1284 | 1285 | // TraceFunc outputs Trace log returned from the function 1286 | func TraceFunc(f func() string) error { 1287 | if isModeEnable(TRACE) { 1288 | return glg.out(TRACE, "%s", f()) 1289 | } 1290 | return nil 1291 | } 1292 | 1293 | // Print outputs Print log 1294 | func (g *Glg) Print(val ...interface{}) error { 1295 | return g.out(PRINT, g.blankFormat(len(val)), val...) 1296 | } 1297 | 1298 | // Println outputs fixed line Print log 1299 | func (g *Glg) Println(val ...interface{}) error { 1300 | return g.out(PRINT, g.blankFormat(len(val)), val...) 1301 | } 1302 | 1303 | // Printf outputs formatted Print log 1304 | func (g *Glg) Printf(format string, val ...interface{}) error { 1305 | return g.out(PRINT, format, val...) 1306 | } 1307 | 1308 | // PrintFunc outputs Print log returned from the function 1309 | func (g *Glg) PrintFunc(f func() string) error { 1310 | if g.isModeEnable(PRINT) { 1311 | return g.out(PRINT, "%s", f()) 1312 | } 1313 | return nil 1314 | } 1315 | 1316 | // Print outputs Print log 1317 | func Print(val ...interface{}) error { 1318 | return glg.out(PRINT, glg.blankFormat(len(val)), val...) 1319 | } 1320 | 1321 | // Println outputs fixed line Print log 1322 | func Println(val ...interface{}) error { 1323 | return glg.out(PRINT, glg.blankFormat(len(val)), val...) 1324 | } 1325 | 1326 | // Printf outputs formatted Print log 1327 | func Printf(format string, val ...interface{}) error { 1328 | return glg.out(PRINT, format, val...) 1329 | } 1330 | 1331 | // PrintFunc outputs Print log returned from the function 1332 | func PrintFunc(f func() string) error { 1333 | if isModeEnable(PRINT) { 1334 | return glg.out(PRINT, "%s", f()) 1335 | } 1336 | return nil 1337 | } 1338 | 1339 | // Error outputs Error log 1340 | func (g *Glg) Error(val ...interface{}) error { 1341 | return g.out(ERR, g.blankFormat(len(val)), val...) 1342 | } 1343 | 1344 | // Errorf outputs formatted Error log 1345 | func (g *Glg) Errorf(format string, val ...interface{}) error { 1346 | return g.out(ERR, format, val...) 1347 | } 1348 | 1349 | // ErrorFunc outputs Error level log returned from the function 1350 | func (g *Glg) ErrorFunc(f func() string) error { 1351 | if g.isModeEnable(ERR) { 1352 | return g.out(ERR, "%s", f()) 1353 | } 1354 | return nil 1355 | } 1356 | 1357 | // Error outputs Error log 1358 | func Error(val ...interface{}) error { 1359 | return glg.out(ERR, glg.blankFormat(len(val)), val...) 1360 | } 1361 | 1362 | // Errorf outputs formatted Error log 1363 | func Errorf(format string, val ...interface{}) error { 1364 | return glg.out(ERR, format, val...) 1365 | } 1366 | 1367 | // ErrorFunc outputs Error level log returned from the function 1368 | func ErrorFunc(f func() string) error { 1369 | if isModeEnable(ERR) { 1370 | return glg.out(ERR, "%s", f()) 1371 | } 1372 | return nil 1373 | } 1374 | 1375 | // Fail outputs Failed log 1376 | func (g *Glg) Fail(val ...interface{}) error { 1377 | return g.out(FAIL, g.blankFormat(len(val)), val...) 1378 | } 1379 | 1380 | // Failf outputs formatted Failed log 1381 | func (g *Glg) Failf(format string, val ...interface{}) error { 1382 | return g.out(FAIL, format, val...) 1383 | } 1384 | 1385 | // FailFunc outputs Fail level log returned from the function 1386 | func (g *Glg) FailFunc(f func() string) error { 1387 | if g.isModeEnable(FAIL) { 1388 | return g.out(FAIL, "%s", f()) 1389 | } 1390 | return nil 1391 | } 1392 | 1393 | // Fail outputs Failed log 1394 | func Fail(val ...interface{}) error { 1395 | return glg.out(FAIL, glg.blankFormat(len(val)), val...) 1396 | } 1397 | 1398 | // Failf outputs formatted Failed log 1399 | func Failf(format string, val ...interface{}) error { 1400 | return glg.out(FAIL, format, val...) 1401 | } 1402 | 1403 | // FailFunc outputs Fail level log returned from the function 1404 | func FailFunc(f func() string) error { 1405 | if isModeEnable(FAIL) { 1406 | return glg.out(FAIL, "%s", f()) 1407 | } 1408 | return nil 1409 | } 1410 | 1411 | // Fatal outputs Failed log and exit program 1412 | func (g *Glg) Fatal(val ...interface{}) { 1413 | err := g.out(FATAL, g.blankFormat(len(val)), val...) 1414 | if err != nil { 1415 | err = g.out(ERR, g.blankFormat(1), err.Error()) 1416 | if err != nil { 1417 | panic(err) 1418 | } 1419 | } 1420 | exit(1) 1421 | } 1422 | 1423 | // Fatalln outputs line fixed Failed log and exit program 1424 | func (g *Glg) Fatalln(val ...interface{}) { 1425 | err := g.out(FATAL, g.blankFormat(len(val)), val...) 1426 | if err != nil { 1427 | err = g.out(ERR, g.blankFormat(1), err.Error()) 1428 | if err != nil { 1429 | panic(err) 1430 | } 1431 | } 1432 | exit(1) 1433 | } 1434 | 1435 | // Fatalf outputs formatted Failed log and exit program 1436 | func (g *Glg) Fatalf(format string, val ...interface{}) { 1437 | err := g.out(FATAL, format, val...) 1438 | if err != nil { 1439 | err = g.out(ERR, g.blankFormat(1), err.Error()) 1440 | if err != nil { 1441 | panic(err) 1442 | } 1443 | } 1444 | exit(1) 1445 | } 1446 | 1447 | // Fatal outputs Failed log and exit program 1448 | func Fatal(val ...interface{}) { 1449 | err := glg.out(FATAL, glg.blankFormat(len(val)), val...) 1450 | if err != nil { 1451 | err = glg.out(ERR, glg.blankFormat(1), err.Error()) 1452 | if err != nil { 1453 | panic(err) 1454 | } 1455 | } 1456 | exit(1) 1457 | } 1458 | 1459 | // Fatalf outputs formatted Failed log and exit program 1460 | func Fatalf(format string, val ...interface{}) { 1461 | err := glg.out(FATAL, format, val...) 1462 | if err != nil { 1463 | err = glg.out(ERR, glg.blankFormat(1), err.Error()) 1464 | if err != nil { 1465 | panic(err) 1466 | } 1467 | } 1468 | exit(1) 1469 | } 1470 | 1471 | // Fatalln outputs line fixed Failed log and exit program 1472 | func Fatalln(val ...interface{}) { 1473 | err := glg.out(FATAL, glg.blankFormat(len(val)), val...) 1474 | if err != nil { 1475 | err = glg.out(ERR, glg.blankFormat(1), err.Error()) 1476 | if err != nil { 1477 | panic(err) 1478 | } 1479 | } 1480 | exit(1) 1481 | } 1482 | 1483 | // ReplaceExitFunc replaces exit function. 1484 | // If you do not want to start os.Exit at glg.Fatal error, 1485 | // use this function to register arbitrary function 1486 | func ReplaceExitFunc(fn func(i int)) { 1487 | exit = fn 1488 | } 1489 | 1490 | // Reset provides parameter reset function for glg struct instance 1491 | func Reset() *Glg { 1492 | glg = glg.Reset() 1493 | return glg 1494 | } 1495 | 1496 | // Reset provides parameter reset function for glg struct instance 1497 | func (g *Glg) Reset() *Glg { 1498 | g = New() 1499 | return g 1500 | } 1501 | 1502 | func (g *Glg) blankFormat(l int) string { 1503 | if g.enableJSON { 1504 | return "" 1505 | } 1506 | if dfl > l { 1507 | return df[:l*3-1] 1508 | } 1509 | format := df 1510 | for c := l / dfl; c >= 0; c-- { 1511 | format += df 1512 | } 1513 | return format[:l*3-1] 1514 | } 1515 | 1516 | // isModeEnable returns the level has already turned on the logging 1517 | func isModeEnable(l LEVEL) bool { 1518 | return Get().GetCurrentMode(l) != NONE 1519 | } 1520 | 1521 | // isModeEnable returns the level has already turned on the logging 1522 | func (g *Glg) isModeEnable(l LEVEL) bool { 1523 | return g.GetCurrentMode(l) != NONE 1524 | } 1525 | -------------------------------------------------------------------------------- /glg_bench_test.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2019 kpango (Yusuke Kato) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package glg_test 24 | 25 | import ( 26 | "log" 27 | "testing" 28 | 29 | "github.com/kpango/glg" 30 | "github.com/sirupsen/logrus" 31 | "go.uber.org/zap" 32 | "go.uber.org/zap/zapcore" 33 | ) 34 | 35 | var ( 36 | testMsg = `benchmark sample message blow 37 | MIT License 38 | 39 | Copyright (c) 2021 kpango (Yusuke Kato) 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy 42 | of this software and associated documentation files (the "Software"), to deal 43 | in the Software without restriction, including without limitation the rights 44 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 45 | copies of the Software, and to permit persons to whom the Software is 46 | furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in all 49 | copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 52 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 53 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 54 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 55 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 56 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 57 | SOFTWARE.` 58 | 59 | testInt = 9999 60 | testFloat = 10.10 61 | 62 | testFormat = "format %s,\t%d,%f\n" 63 | 64 | testJSON = JSONMessage{ 65 | Message: testMsg, 66 | Number: testInt, 67 | Float: testFloat, 68 | } 69 | ) 70 | 71 | type JSONMessage struct { 72 | Message string `json:"message,omitempty"` 73 | Number int `json:"number,omitempty"` 74 | Float float64 `json:"float,omitempty"` 75 | } 76 | 77 | type MockWriter struct{} 78 | 79 | func (m MockWriter) Write(b []byte) (int, error) { 80 | _ = b 81 | return 0, nil 82 | } 83 | 84 | func BenchmarkDefaultLog(b *testing.B) { 85 | log.SetOutput(&MockWriter{}) 86 | b.ReportAllocs() 87 | b.ResetTimer() 88 | b.RunParallel(func(pb *testing.PB) { 89 | for pb.Next() { 90 | log.Println("\t[" + "LOG" + "]:\t" + testMsg) 91 | log.Println("\t[" + "LOG" + "]:\t" + testMsg) 92 | log.Println("\t[" + "LOG" + "]:\t" + testMsg) 93 | log.Println("\t[" + "LOG" + "]:\t" + testMsg) 94 | log.Println("\t[" + "LOG" + "]:\t" + testMsg) 95 | } 96 | }) 97 | } 98 | 99 | func BenchmarkGlg(b *testing.B) { 100 | glg.Reset() 101 | glg.Get().SetMode(glg.WRITER).SetWriter(&MockWriter{}).EnablePoolBuffer(32) 102 | b.ReportAllocs() 103 | b.ResetTimer() 104 | b.RunParallel(func(pb *testing.PB) { 105 | for pb.Next() { 106 | glg.Log(testMsg) 107 | glg.Log(testMsg) 108 | glg.Log(testMsg) 109 | glg.Log(testMsg) 110 | glg.Log(testMsg) 111 | } 112 | }) 113 | } 114 | 115 | func BenchmarkLogrus(b *testing.B) { 116 | logrus.SetOutput(&MockWriter{}) 117 | b.ReportAllocs() 118 | b.ResetTimer() 119 | b.RunParallel(func(pb *testing.PB) { 120 | for pb.Next() { 121 | logrus.Info(testMsg) 122 | logrus.Info(testMsg) 123 | logrus.Info(testMsg) 124 | logrus.Info(testMsg) 125 | logrus.Info(testMsg) 126 | } 127 | }) 128 | } 129 | 130 | func BenchmarkZap(b *testing.B) { 131 | cfg := zap.NewProductionConfig() 132 | logger := zap.New(zapcore.NewCore(zapcore.NewConsoleEncoder(cfg.EncoderConfig), zapcore.AddSync(&MockWriter{}), cfg.Level)) 133 | b.ReportAllocs() 134 | b.ResetTimer() 135 | b.RunParallel(func(pb *testing.PB) { 136 | for pb.Next() { 137 | logger.Info(testMsg) 138 | logger.Info(testMsg) 139 | logger.Info(testMsg) 140 | logger.Info(testMsg) 141 | logger.Info(testMsg) 142 | } 143 | }) 144 | } 145 | 146 | func BenchmarkDefaultLogf(b *testing.B) { 147 | log.SetOutput(&MockWriter{}) 148 | b.ReportAllocs() 149 | b.ResetTimer() 150 | b.RunParallel(func(pb *testing.PB) { 151 | for pb.Next() { 152 | log.Printf("\t["+"LOG"+"]:\t"+testFormat+"\n", testMsg, testInt, testFloat) 153 | log.Printf("\t["+"LOG"+"]:\t"+testFormat+"\n", testMsg, testInt, testFloat) 154 | log.Printf("\t["+"LOG"+"]:\t"+testFormat+"\n", testMsg, testInt, testFloat) 155 | log.Printf("\t["+"LOG"+"]:\t"+testFormat+"\n", testMsg, testInt, testFloat) 156 | log.Printf("\t["+"LOG"+"]:\t"+testFormat+"\n", testMsg, testInt, testFloat) 157 | } 158 | }) 159 | } 160 | 161 | func BenchmarkGlgf(b *testing.B) { 162 | glg.Reset() 163 | glg.Get().SetMode(glg.WRITER).SetWriter(&MockWriter{}).EnablePoolBuffer(32) 164 | b.ReportAllocs() 165 | b.ResetTimer() 166 | b.RunParallel(func(pb *testing.PB) { 167 | for pb.Next() { 168 | glg.Logf(testFormat, testMsg, testInt, testFloat) 169 | glg.Logf(testFormat, testMsg, testInt, testFloat) 170 | glg.Logf(testFormat, testMsg, testInt, testFloat) 171 | glg.Logf(testFormat, testMsg, testInt, testFloat) 172 | glg.Logf(testFormat, testMsg, testInt, testFloat) 173 | } 174 | }) 175 | } 176 | 177 | func BenchmarkLogrusf(b *testing.B) { 178 | logrus.SetOutput(&MockWriter{}) 179 | b.ReportAllocs() 180 | b.ResetTimer() 181 | b.RunParallel(func(pb *testing.PB) { 182 | for pb.Next() { 183 | logrus.Infof(testFormat, testMsg, testInt, testFloat) 184 | logrus.Infof(testFormat, testMsg, testInt, testFloat) 185 | logrus.Infof(testFormat, testMsg, testInt, testFloat) 186 | logrus.Infof(testFormat, testMsg, testInt, testFloat) 187 | logrus.Infof(testFormat, testMsg, testInt, testFloat) 188 | } 189 | }) 190 | } 191 | 192 | func BenchmarkZapf(b *testing.B) { 193 | cfg := zap.NewProductionConfig() 194 | logger := zap.New(zapcore.NewCore(zapcore.NewConsoleEncoder(cfg.EncoderConfig), zapcore.AddSync(&MockWriter{}), cfg.Level)).Sugar() 195 | b.ReportAllocs() 196 | b.ResetTimer() 197 | b.RunParallel(func(pb *testing.PB) { 198 | for pb.Next() { 199 | logger.Infof(testFormat, testMsg, testInt, testFloat) 200 | logger.Infof(testFormat, testMsg, testInt, testFloat) 201 | logger.Infof(testFormat, testMsg, testInt, testFloat) 202 | logger.Infof(testFormat, testMsg, testInt, testFloat) 203 | logger.Infof(testFormat, testMsg, testInt, testFloat) 204 | } 205 | }) 206 | } 207 | 208 | func BenchmarkGlgJSON(b *testing.B) { 209 | glg.Reset() 210 | glg.Get().SetMode(glg.WRITER).SetWriter(&MockWriter{}).EnablePoolBuffer(32).EnableJSON() 211 | b.ReportAllocs() 212 | b.ResetTimer() 213 | b.RunParallel(func(pb *testing.PB) { 214 | for pb.Next() { 215 | glg.Log(testJSON) 216 | glg.Log(testJSON) 217 | glg.Log(testJSON) 218 | glg.Log(testJSON) 219 | glg.Log(testJSON) 220 | } 221 | }) 222 | } 223 | 224 | func BenchmarkLogrusJSON(b *testing.B) { 225 | logrus.SetOutput(&MockWriter{}) 226 | logrus.SetFormatter(&logrus.JSONFormatter{}) 227 | b.ReportAllocs() 228 | b.ResetTimer() 229 | b.RunParallel(func(pb *testing.PB) { 230 | for pb.Next() { 231 | logrus.Info(testJSON) 232 | logrus.Info(testJSON) 233 | logrus.Info(testJSON) 234 | logrus.Info(testJSON) 235 | logrus.Info(testJSON) 236 | } 237 | }) 238 | } 239 | 240 | func BenchmarkZapJSON(b *testing.B) { 241 | cfg := zap.NewProductionConfig() 242 | logger := zap.New(zapcore.NewCore(zapcore.NewJSONEncoder(cfg.EncoderConfig), zapcore.AddSync(&MockWriter{}), cfg.Level)) 243 | b.ReportAllocs() 244 | b.ResetTimer() 245 | b.RunParallel(func(pb *testing.PB) { 246 | for pb.Next() { 247 | logger.Info("", zap.String("message", testJSON.Message), 248 | zap.Int("number", testJSON.Number), 249 | zap.Float64("float", testJSON.Float)) 250 | logger.Info("", zap.String("message", testJSON.Message), 251 | zap.Int("number", testJSON.Number), 252 | zap.Float64("float", testJSON.Float)) 253 | logger.Info("", zap.String("message", testJSON.Message), 254 | zap.Int("number", testJSON.Number), 255 | zap.Float64("float", testJSON.Float)) 256 | logger.Info("", zap.String("message", testJSON.Message), 257 | zap.Int("number", testJSON.Number), 258 | zap.Float64("float", testJSON.Float)) 259 | logger.Info("", zap.String("message", testJSON.Message), 260 | zap.Int("number", testJSON.Number), 261 | zap.Float64("float", testJSON.Float)) 262 | } 263 | }) 264 | } 265 | 266 | func BenchmarkZapSugarJSON(b *testing.B) { 267 | cfg := zap.NewProductionConfig() 268 | logger := zap.New(zapcore.NewCore(zapcore.NewJSONEncoder(cfg.EncoderConfig), zapcore.AddSync(&MockWriter{}), cfg.Level)).Sugar() 269 | b.ReportAllocs() 270 | b.ResetTimer() 271 | b.RunParallel(func(pb *testing.PB) { 272 | for pb.Next() { 273 | logger.Info(testJSON) 274 | logger.Info(testJSON) 275 | logger.Info(testJSON) 276 | logger.Info(testJSON) 277 | logger.Info(testJSON) 278 | } 279 | }) 280 | } 281 | -------------------------------------------------------------------------------- /glg_test.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2019 kpango (Yusuke Kato) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package glg 24 | 25 | import ( 26 | "bytes" 27 | "errors" 28 | "fmt" 29 | "io" 30 | "net/http" 31 | "net/http/httptest" 32 | "os" 33 | "reflect" 34 | "strings" 35 | "sync" 36 | "testing" 37 | "time" 38 | 39 | json "github.com/goccy/go-json" 40 | ) 41 | 42 | type ExitError int 43 | 44 | const ( 45 | dummy = "dummy" 46 | ) 47 | 48 | func (e ExitError) Error() string { 49 | return fmt.Sprintf("exited with code %d", int(e)) 50 | } 51 | 52 | func init() { 53 | exit = func(n int) { 54 | panic(ExitError(n)) 55 | } 56 | } 57 | 58 | func testExit(code int, f func()) (err error) { 59 | defer func() { 60 | e := recover() 61 | switch t := e.(type) { 62 | case ExitError: 63 | if int(t) == code { 64 | err = nil 65 | } else { 66 | err = fmt.Errorf("expected exit with %v but %v", code, e) 67 | } 68 | default: 69 | err = fmt.Errorf("expected exit with %v but %v", code, e) 70 | } 71 | }() 72 | f() 73 | return errors.New("expected exited but not") 74 | } 75 | 76 | func TestLEVEL_String(t *testing.T) { 77 | l := LEVEL(100) 78 | if l.String() != "" { 79 | t.Error("invalid value") 80 | } 81 | } 82 | 83 | func TestNew(t *testing.T) { 84 | t.Run("Comparing simple instances", func(t *testing.T) { 85 | ins1 := New() 86 | ins2 := New() 87 | if ins1.GetCurrentMode(LOG) != ins2.GetCurrentMode(LOG) { 88 | t.Errorf("glg mode = %v, want %v", ins1.GetCurrentMode(LOG), ins2.GetCurrentMode(LOG)) 89 | } 90 | 91 | ins1.logger.Range(func(lev LEVEL, lev1 *logger) bool { 92 | lev2, ok := ins2.logger.Load(lev) 93 | if !ok { 94 | t.Error("glg instance 2 not found") 95 | } 96 | if lev1.tag != lev2.tag || lev1.mode != lev2.mode { 97 | t.Errorf("Expect %v, want %v", lev2, lev1) 98 | return false 99 | } 100 | return true 101 | }) 102 | }) 103 | } 104 | 105 | func TestGet(t *testing.T) { 106 | t.Run("Comparing singleton instances", func(t *testing.T) { 107 | ins1 := Get() 108 | ins2 := Get() 109 | 110 | if !reflect.DeepEqual(ins1, ins2) { 111 | t.Errorf("Expect %v, want %v", ins2, ins1) 112 | } 113 | ins1.logger.Range(func(lev LEVEL, lev1 *logger) bool { 114 | lev2, ok := ins2.logger.Load(lev) 115 | if !ok { 116 | t.Error("glg instance 2 not found") 117 | } 118 | if !reflect.DeepEqual(lev1, lev2) { 119 | t.Errorf("Expect %v, want %v", lev2, lev1) 120 | return false 121 | } 122 | return true 123 | }) 124 | }) 125 | } 126 | 127 | func TestGlg_SetMode(t *testing.T) { 128 | tests := []struct { 129 | name string 130 | mode MODE 131 | want MODE 132 | isErr bool 133 | }{ 134 | { 135 | name: "std", 136 | mode: STD, 137 | want: STD, 138 | isErr: false, 139 | }, 140 | { 141 | name: "writer", 142 | mode: WRITER, 143 | want: WRITER, 144 | isErr: false, 145 | }, 146 | { 147 | name: "both", 148 | mode: BOTH, 149 | want: BOTH, 150 | isErr: false, 151 | }, 152 | { 153 | name: "none", 154 | mode: NONE, 155 | want: NONE, 156 | isErr: false, 157 | }, 158 | { 159 | name: "writer-both", 160 | mode: WRITER, 161 | want: BOTH, 162 | isErr: true, 163 | }, 164 | { 165 | name: "different mode", 166 | mode: NONE, 167 | want: STD, 168 | isErr: true, 169 | }, 170 | } 171 | g := New() 172 | for _, tt := range tests { 173 | t.Run(tt.name, func(t *testing.T) { 174 | if got := g.SetMode(tt.mode).GetCurrentMode(LOG); !reflect.DeepEqual(got, tt.want) && !tt.isErr { 175 | t.Errorf("Glg.SetMode() = %v, want %v", got, tt.want) 176 | } 177 | }) 178 | } 179 | } 180 | 181 | func TestGlg_SetLevel(t *testing.T) { 182 | tests := []struct { 183 | name string 184 | level LEVEL 185 | lv LEVEL 186 | expect MODE 187 | }{ 188 | { 189 | name: "debug mode enables all", 190 | level: DEBG, 191 | lv: LOG, 192 | expect: STD, 193 | }, 194 | { 195 | name: "WARN mode disables ok", 196 | level: WARN, 197 | lv: OK, 198 | expect: NONE, 199 | }, 200 | { 201 | name: "WARN mode disables info", 202 | level: WARN, 203 | lv: INFO, 204 | expect: NONE, 205 | }, 206 | { 207 | name: "WARN mode disables log", 208 | level: WARN, 209 | lv: LOG, 210 | expect: NONE, 211 | }, 212 | { 213 | name: "WARN mode disables print", 214 | level: WARN, 215 | lv: PRINT, 216 | expect: NONE, 217 | }, 218 | { 219 | name: "WARN mode disables debug", 220 | level: WARN, 221 | lv: DEBG, 222 | expect: NONE, 223 | }, 224 | { 225 | name: "FATAL mode disables fail", 226 | level: FATAL, 227 | lv: FAIL, 228 | expect: NONE, 229 | }, 230 | { 231 | name: "FATAL mode disables err", 232 | level: FATAL, 233 | lv: ERR, 234 | expect: NONE, 235 | }, 236 | { 237 | name: "FATAL mode disables ok", 238 | level: FATAL, 239 | lv: OK, 240 | expect: NONE, 241 | }, 242 | { 243 | name: "FATAL mode disables info", 244 | level: FATAL, 245 | lv: INFO, 246 | expect: NONE, 247 | }, 248 | { 249 | name: "FATAL mode disables log", 250 | level: FATAL, 251 | lv: LOG, 252 | expect: NONE, 253 | }, 254 | { 255 | name: "FATAL mode disables print", 256 | level: FATAL, 257 | lv: PRINT, 258 | expect: NONE, 259 | }, 260 | { 261 | name: "FATAL mode disables debug", 262 | level: FATAL, 263 | lv: DEBG, 264 | expect: NONE, 265 | }, 266 | } 267 | g := New() 268 | for _, tt := range tests { 269 | t.Run(tt.name, func(t *testing.T) { 270 | if got := g.SetLevel(tt.level).GetCurrentMode(tt.lv); got != tt.expect { 271 | t.Errorf("Glg.SetLevel() = %v, want %v", got, tt.expect) 272 | } 273 | }) 274 | } 275 | } 276 | 277 | func TestGlg_SetLevelMode(t *testing.T) { 278 | tests := []struct { 279 | name string 280 | mode MODE 281 | want MODE 282 | level LEVEL 283 | isErr bool 284 | }{ 285 | { 286 | name: "std", 287 | mode: STD, 288 | want: STD, 289 | level: LOG, 290 | isErr: false, 291 | }, 292 | { 293 | name: "writer", 294 | mode: WRITER, 295 | want: WRITER, 296 | level: LOG, 297 | isErr: false, 298 | }, 299 | { 300 | name: "both", 301 | mode: BOTH, 302 | want: BOTH, 303 | level: LOG, 304 | isErr: false, 305 | }, 306 | { 307 | name: "none", 308 | mode: NONE, 309 | want: NONE, 310 | level: LOG, 311 | isErr: false, 312 | }, 313 | { 314 | name: "writer-both", 315 | mode: WRITER, 316 | want: BOTH, 317 | level: LOG, 318 | isErr: true, 319 | }, 320 | { 321 | name: "different mode", 322 | mode: NONE, 323 | want: STD, 324 | level: LOG, 325 | isErr: true, 326 | }, 327 | { 328 | name: "different mode", 329 | mode: WRITER, 330 | want: NONE, 331 | level: 123, 332 | isErr: false, 333 | }, 334 | } 335 | g := New() 336 | for _, tt := range tests { 337 | t.Run(tt.name, func(t *testing.T) { 338 | if got := g.SetLevelMode(tt.level, tt.mode).GetCurrentMode(tt.level); !reflect.DeepEqual(got, tt.want) && !tt.isErr { 339 | t.Errorf("Glg.SetMode() = %v, want %v", got, tt.want) 340 | } 341 | }) 342 | } 343 | } 344 | 345 | func TestGlg_GetCurrentMode(t *testing.T) { 346 | tests := []struct { 347 | name string 348 | mode MODE 349 | want MODE 350 | level LEVEL 351 | }{ 352 | { 353 | name: "std", 354 | mode: STD, 355 | want: STD, 356 | level: LOG, 357 | }, 358 | { 359 | name: "writer", 360 | mode: WRITER, 361 | want: WRITER, 362 | level: LOG, 363 | }, 364 | { 365 | name: "both", 366 | mode: BOTH, 367 | want: BOTH, 368 | level: LOG, 369 | }, 370 | { 371 | name: "none", 372 | mode: NONE, 373 | want: NONE, 374 | level: LOG, 375 | }, 376 | { 377 | name: "different mode", 378 | mode: WRITER, 379 | want: NONE, 380 | level: 123, 381 | }, 382 | } 383 | for _, tt := range tests { 384 | t.Run(tt.name, func(t *testing.T) { 385 | if got := New().SetMode(tt.mode).GetCurrentMode(tt.level); !reflect.DeepEqual(got, tt.want) { 386 | t.Errorf("Glg.GetCurrentMode(LOG) = %v, want %v", got, tt.want) 387 | } 388 | }) 389 | } 390 | } 391 | 392 | func TestGlg_InitWriter(t *testing.T) { 393 | t.Run("InitWriter Check", func(t *testing.T) { 394 | ins1 := New() 395 | ins2 := ins1.InitWriter() 396 | if ins1.GetCurrentMode(LOG) != ins2.GetCurrentMode(LOG) { 397 | t.Errorf("glg mode = %v, want %v", ins1.GetCurrentMode(LOG), ins2.GetCurrentMode(LOG)) 398 | } 399 | 400 | if ins2.GetCurrentMode(LOG) != STD { 401 | t.Errorf("Expect %v, want %v", ins2.GetCurrentMode(LOG), STD) 402 | } 403 | 404 | ins1.logger.Range(func(lev LEVEL, lev1 *logger) bool { 405 | lev2, ok := ins2.logger.Load(lev) 406 | if !ok { 407 | t.Error("glg instance 2 not found") 408 | } 409 | if !reflect.DeepEqual(lev1, lev2) { 410 | t.Errorf("Expect %v, want %v", lev2, lev1) 411 | return false 412 | } 413 | return true 414 | }) 415 | }) 416 | } 417 | 418 | func TestGlg_SetWriter(t *testing.T) { 419 | tests := []struct { 420 | name string 421 | want io.Writer 422 | msg string 423 | }{ 424 | { 425 | name: "Set Custom writer", 426 | want: new(bytes.Buffer), 427 | msg: "test", 428 | }, 429 | { 430 | name: "Set nil writer", 431 | want: nil, 432 | msg: "nil", 433 | }, 434 | } 435 | 436 | for _, tt := range tests { 437 | t.Run(tt.name, func(t *testing.T) { 438 | g := New().SetMode(WRITER).SetWriter(tt.want) 439 | g.Info(tt.msg) 440 | if tt.want != nil { 441 | got := tt.want.(*bytes.Buffer).String() 442 | t.Log(got) 443 | if !strings.Contains(got, tt.msg) { 444 | t.Errorf("Glg.SetWriter() = %v, want %v", got, tt.msg) 445 | } 446 | } else { 447 | ins, ok := g.logger.Load(INFO) 448 | if !ok { 449 | t.Error("glg instance not found") 450 | } 451 | if ins.writer != nil { 452 | t.Errorf("Glg.SetWriter() = %v, want %v", ins.writer, tt.want) 453 | } 454 | } 455 | }) 456 | } 457 | } 458 | 459 | func TestGlg_AddWriter(t *testing.T) { 460 | tests := []struct { 461 | name string 462 | want io.Writer 463 | msg string 464 | }{ 465 | { 466 | name: "Add Custom writer", 467 | want: new(bytes.Buffer), 468 | msg: "test", 469 | }, 470 | { 471 | name: "Add nil writer", 472 | want: nil, 473 | msg: "nil", 474 | }, 475 | } 476 | for _, tt := range tests { 477 | t.Run(tt.name, func(t *testing.T) { 478 | var writer io.Writer = new(bytes.Buffer) 479 | g := New().SetMode(WRITER).AddWriter(tt.want).AddWriter(writer) 480 | g.Info(tt.msg) 481 | if tt.want != nil { 482 | got := tt.want.(*bytes.Buffer).String() 483 | want := writer.(*bytes.Buffer).String() 484 | if !reflect.DeepEqual(got, want) { 485 | t.Errorf("Glg.AddWriter() = %vwant %v", got, want) 486 | } 487 | } else { 488 | ins, ok := g.logger.Load(INFO) 489 | if !ok { 490 | t.Error("glg instance not found") 491 | } 492 | if ins.writer == nil { 493 | t.Errorf("Glg.AddWriter() = %v, want %v", ins.writer, tt.want) 494 | } 495 | } 496 | }) 497 | } 498 | } 499 | 500 | func TestGlg_SetLevelColor(t *testing.T) { 501 | tests := []struct { 502 | name string 503 | level LEVEL 504 | color func(string) string 505 | txt string 506 | want string 507 | }{ 508 | { 509 | name: "Set Level Color INFO=Green", 510 | level: INFO, 511 | color: Green, 512 | txt: "green", 513 | want: Green("green"), 514 | }, 515 | { 516 | name: "Set Level Color DEBG=Purple", 517 | level: DEBG, 518 | color: Purple, 519 | txt: "purple", 520 | want: Purple("purple"), 521 | }, 522 | { 523 | name: "Set Level Color WARN=Orange", 524 | level: WARN, 525 | color: Orange, 526 | txt: "orange", 527 | want: Orange("orange"), 528 | }, 529 | { 530 | name: "Set Level Color ERR=Red", 531 | level: ERR, 532 | color: Red, 533 | txt: "red", 534 | want: Red("red"), 535 | }, 536 | } 537 | for _, tt := range tests { 538 | t.Run(tt.name, func(t *testing.T) { 539 | g := New() 540 | g.SetLevelColor(tt.level, tt.color) 541 | ins, ok := g.logger.Load(tt.level) 542 | if !ok { 543 | t.Error("glg instance not found") 544 | } 545 | got := ins.color(tt.txt) 546 | if !reflect.DeepEqual(got, tt.want) { 547 | t.Errorf("Glg.SetLevelColor() = %v, want %v", got, tt.want) 548 | } 549 | }) 550 | } 551 | } 552 | 553 | func TestGlg_SetLevelWriter(t *testing.T) { 554 | tests := []struct { 555 | name string 556 | writer io.Writer 557 | level LEVEL 558 | }{ 559 | { 560 | name: "Info level", 561 | writer: new(bytes.Buffer), 562 | level: INFO, 563 | }, 564 | { 565 | name: "Error level", 566 | writer: new(bytes.Buffer), 567 | level: ERR, 568 | }, 569 | { 570 | name: "Set INFO level nil writer", 571 | writer: nil, 572 | level: INFO, 573 | }, 574 | } 575 | 576 | for _, tt := range tests { 577 | t.Run(tt.name, func(t *testing.T) { 578 | g := New() 579 | g.SetLevelWriter(tt.level, tt.writer) 580 | ins, ok := g.logger.Load(tt.level) 581 | if !ok { 582 | t.Error("glg instance not found") 583 | } 584 | if !reflect.DeepEqual(ins.writer, tt.writer) { 585 | t.Errorf("Glg.SetLevelWriter() = %v, want %v", ins.writer, tt.writer) 586 | } 587 | }) 588 | } 589 | } 590 | 591 | func TestGlg_AddLevelWriter(t *testing.T) { 592 | tests := []struct { 593 | glg *Glg 594 | name string 595 | writer io.Writer 596 | level LEVEL 597 | multi bool 598 | }{ 599 | { 600 | glg: New(), 601 | name: "Info level", 602 | writer: new(bytes.Buffer), 603 | level: INFO, 604 | multi: false, 605 | }, 606 | { 607 | glg: New(), 608 | name: "Error level", 609 | writer: new(bytes.Buffer), 610 | level: ERR, 611 | multi: false, 612 | }, 613 | { 614 | glg: New(), 615 | name: "Append DEBG level", 616 | writer: new(bytes.Buffer), 617 | level: DEBG, 618 | multi: false, 619 | }, 620 | { 621 | glg: New(), 622 | name: "Add INFO level nil writer", 623 | writer: nil, 624 | level: INFO, 625 | multi: false, 626 | }, 627 | { 628 | glg: Get().AddStdLevel("glg is fast", BOTH, false), 629 | name: "Add Custom", 630 | writer: new(bytes.Buffer), 631 | level: TagStringToLevel("glg is fast"), 632 | multi: false, 633 | }, 634 | { 635 | glg: Get().AddStdLevel("glg", BOTH, false). 636 | AddLevelWriter(TagStringToLevel("glg"), 637 | new(bytes.Buffer)), 638 | name: "Add Custom", 639 | writer: new(bytes.Buffer), 640 | level: TagStringToLevel("glg"), 641 | multi: true, 642 | }, 643 | } 644 | 645 | for _, tt := range tests { 646 | t.Run(tt.name, func(t *testing.T) { 647 | g := tt.glg 648 | g.AddLevelWriter(tt.level, tt.writer) 649 | ins, ok := g.logger.Load(tt.level) 650 | if !ok { 651 | t.Error("glg instance not found") 652 | } 653 | if !tt.multi && tt.writer != nil && !reflect.DeepEqual(ins.writer, tt.writer) { 654 | t.Errorf("Glg.AddLevelWriter() = %v, want %v", ins.writer, tt.writer) 655 | } 656 | }) 657 | } 658 | } 659 | 660 | func TestGlg_AddStdLevel(t *testing.T) { 661 | tests := []struct { 662 | name string 663 | level string 664 | want io.Writer 665 | }{ 666 | { 667 | name: "custom std", 668 | level: "STD2", 669 | want: os.Stdout, 670 | }, 671 | { 672 | name: "custom xxxx", 673 | level: "XXXX", 674 | want: os.Stdout, 675 | }, 676 | } 677 | for _, tt := range tests { 678 | t.Run(tt.name, func(t *testing.T) { 679 | g := New().AddStdLevel(tt.level, STD, false) 680 | _, ok := g.logger.Load(g.TagStringToLevel(tt.level)) 681 | if !ok { 682 | t.Error("glg instance not found") 683 | } 684 | }) 685 | } 686 | } 687 | 688 | func TestGlg_AddErrLevel(t *testing.T) { 689 | tests := []struct { 690 | name string 691 | level string 692 | want io.Writer 693 | }{ 694 | { 695 | name: "custom err", 696 | level: "ERR2", 697 | want: os.Stderr, 698 | }, 699 | { 700 | name: "custom xxxx", 701 | level: "XXXX", 702 | want: os.Stderr, 703 | }, 704 | } 705 | for _, tt := range tests { 706 | t.Run(tt.name, func(t *testing.T) { 707 | g := New().AddErrLevel(tt.level, STD, false) 708 | _, ok := g.logger.Load(g.TagStringToLevel(tt.level)) 709 | if !ok { 710 | t.Error("glg instance not found") 711 | } 712 | }) 713 | } 714 | } 715 | 716 | func TestSetPrefix(t *testing.T) { 717 | tests := []struct { 718 | prefix string 719 | name string 720 | want string 721 | }{ 722 | { 723 | name: "Prefix GLG", 724 | prefix: "GLG", 725 | want: "GLG", 726 | }, 727 | } 728 | for _, tt := range tests { 729 | t.Run(tt.name, func(t *testing.T) { 730 | SetPrefix(PRINT, tt.prefix) 731 | buf := new(bytes.Buffer) 732 | Get().SetWriter(buf) 733 | Get().SetMode(WRITER) 734 | Println("sample") 735 | if !strings.Contains(buf.String(), tt.want) { 736 | t.Errorf("SetPrefix = got %v want %v", buf.String(), tt.want) 737 | } 738 | }) 739 | } 740 | } 741 | 742 | func TestGlg_SetPrefix(t *testing.T) { 743 | tests := []struct { 744 | prefix string 745 | name string 746 | glg *Glg 747 | want string 748 | }{ 749 | { 750 | name: "Prefix GLG", 751 | glg: New(), 752 | prefix: "GLG", 753 | want: "GLG", 754 | }, 755 | } 756 | for _, tt := range tests { 757 | t.Run(tt.name, func(t *testing.T) { 758 | tt.glg.SetPrefix(PRINT, tt.prefix) 759 | buf := new(bytes.Buffer) 760 | tt.glg.SetWriter(buf) 761 | tt.glg.SetMode(WRITER) 762 | tt.glg.Println("sample") 763 | if !strings.Contains(buf.String(), tt.want) { 764 | t.Errorf("SetPrefix = got %v want %v", buf.String(), tt.want) 765 | } 766 | }) 767 | } 768 | } 769 | 770 | func TestGlg_EnableColor(t *testing.T) { 771 | tests := []struct { 772 | name string 773 | glg *Glg 774 | want bool 775 | }{ 776 | { 777 | name: "EnableColor", 778 | glg: New().DisableColor(), 779 | want: true, 780 | }, 781 | } 782 | for _, tt := range tests { 783 | t.Run(tt.name, func(t *testing.T) { 784 | l, ok := tt.glg.EnableColor().logger.Load(LOG) 785 | if !ok { 786 | t.Error("glg instance not found") 787 | } 788 | got := l.isColor 789 | if !reflect.DeepEqual(got, tt.want) { 790 | t.Errorf("Glg.EnableColor() = %v, want %v", got, tt.want) 791 | } 792 | }) 793 | } 794 | } 795 | 796 | func TestGlg_DisableColor(t *testing.T) { 797 | tests := []struct { 798 | name string 799 | glg *Glg 800 | want bool 801 | }{ 802 | { 803 | name: "DisableColor", 804 | glg: New().EnableColor(), 805 | want: false, 806 | }, 807 | } 808 | for _, tt := range tests { 809 | t.Run(tt.name, func(t *testing.T) { 810 | l, ok := tt.glg.DisableColor().logger.Load(LOG) 811 | if !ok { 812 | t.Error("glg instance not found") 813 | } 814 | got := l.isColor 815 | if !reflect.DeepEqual(got, tt.want) { 816 | t.Errorf("Glg.DisableColor() = %v, want %v", got, tt.want) 817 | } 818 | }) 819 | } 820 | } 821 | 822 | func TestGlg_EnableLevelColor(t *testing.T) { 823 | tests := []struct { 824 | name string 825 | glg *Glg 826 | want bool 827 | level LEVEL 828 | }{ 829 | { 830 | name: "EnableColor", 831 | glg: New().DisableColor(), 832 | want: true, 833 | level: INFO, 834 | }, 835 | } 836 | for _, tt := range tests { 837 | t.Run(tt.name, func(t *testing.T) { 838 | l, ok := tt.glg.EnableLevelColor(tt.level).logger.Load(tt.level) 839 | if !ok { 840 | t.Error("glg instance not found") 841 | } 842 | got := l.isColor 843 | if !reflect.DeepEqual(got, tt.want) { 844 | t.Errorf("Glg.DisableColor() = %v, want %v", got, tt.want) 845 | } 846 | }) 847 | } 848 | } 849 | 850 | func TestGlg_DisableLevelColor(t *testing.T) { 851 | tests := []struct { 852 | name string 853 | glg *Glg 854 | want bool 855 | level LEVEL 856 | }{ 857 | { 858 | name: "DisableColor", 859 | glg: New().EnableColor(), 860 | want: false, 861 | level: WARN, 862 | }, 863 | } 864 | for _, tt := range tests { 865 | t.Run(tt.name, func(t *testing.T) { 866 | l, ok := tt.glg.DisableLevelColor(tt.level).logger.Load(tt.level) 867 | if !ok { 868 | t.Error("glg instance not found") 869 | } 870 | got := l.isColor 871 | if !reflect.DeepEqual(got, tt.want) { 872 | t.Errorf("Glg.DisableColor() = %v, want %v", got, tt.want) 873 | } 874 | }) 875 | } 876 | } 877 | 878 | func TestTagStringToLevel(t *testing.T) { 879 | tests := []struct { 880 | name string 881 | g *Glg 882 | tag string 883 | want LEVEL 884 | createFlg bool 885 | }{ 886 | { 887 | name: "customTag", 888 | g: Get().Reset(), 889 | tag: "customTag", 890 | want: TagStringToLevel("customTag"), 891 | createFlg: true, 892 | }, 893 | { 894 | name: "customTag No create", 895 | g: Get(), 896 | tag: "customTagFail", 897 | want: UNKNOWN, 898 | createFlg: false, 899 | }, 900 | } 901 | for _, tt := range tests { 902 | t.Run(tt.name, func(t *testing.T) { 903 | if tt.createFlg { 904 | tt.g.AddStdLevel(tt.tag, STD, false) 905 | } 906 | got := TagStringToLevel(tt.tag) 907 | if got != tt.want { 908 | t.Errorf("Glg.TagStringToLevel = %v, want %v", got, tt.want) 909 | } 910 | }) 911 | } 912 | } 913 | 914 | func TestGlg_TagStringToLevel(t *testing.T) { 915 | tests := []struct { 916 | name string 917 | g *Glg 918 | tag string 919 | want LEVEL 920 | createFlg bool 921 | }{ 922 | { 923 | name: "customTag", 924 | g: New(), 925 | tag: "customTag", 926 | want: TagStringToLevel("customTag"), 927 | createFlg: true, 928 | }, 929 | { 930 | name: "customTag No create", 931 | g: New(), 932 | tag: "customTagFail", 933 | want: UNKNOWN, 934 | createFlg: false, 935 | }, 936 | } 937 | for _, tt := range tests { 938 | t.Run(tt.name, func(t *testing.T) { 939 | if tt.createFlg { 940 | tt.g.AddStdLevel(tt.tag, STD, false) 941 | } 942 | got := glg.TagStringToLevel(tt.tag) 943 | if got != tt.want { 944 | t.Errorf("Glg.TagStringToLevel = %v, want %v", got, tt.want) 945 | } 946 | }) 947 | } 948 | } 949 | 950 | func TestFileWriter(t *testing.T) { 951 | tests := []struct { 952 | name string 953 | path string 954 | want string 955 | isErr bool 956 | }{ 957 | { 958 | name: "sample file log", 959 | path: "./sample.log", 960 | want: "./sample.log", 961 | isErr: false, 962 | }, 963 | { 964 | name: "error file log", 965 | path: "./error.log", 966 | want: "./error.log", 967 | isErr: false, 968 | }, 969 | { 970 | name: "empty", 971 | path: "", 972 | want: "", 973 | isErr: false, 974 | }, 975 | { 976 | name: "root file log", 977 | path: "/root.log", 978 | want: "/root.log", 979 | isErr: false, 980 | }, 981 | { 982 | name: "root file log", 983 | path: "/usr/tmp/root.log", 984 | want: "/usr/tmp/root.log", 985 | isErr: true, 986 | }, 987 | } 988 | for _, tt := range tests { 989 | t.Run(tt.name, func(t *testing.T) { 990 | f := FileWriter(tt.path, 0o755) 991 | if f != nil { 992 | got := f.Name() 993 | if !tt.isErr && !reflect.DeepEqual(got, tt.want) { 994 | t.Errorf("FileWriter() = %v, want %v", got, tt.want) 995 | } 996 | } 997 | }) 998 | } 999 | } 1000 | 1001 | func TestGlg_HTTPLogger(t *testing.T) { 1002 | type args struct { 1003 | name string 1004 | uri string 1005 | } 1006 | tests := []struct { 1007 | name string 1008 | args args 1009 | mode MODE 1010 | }{ 1011 | { 1012 | name: "http logger simple", 1013 | args: args{ 1014 | name: "simple", 1015 | uri: "/", 1016 | }, 1017 | mode: WRITER, 1018 | }, 1019 | { 1020 | name: "http logger err", 1021 | args: args{ 1022 | name: "err", 1023 | uri: "err", 1024 | }, 1025 | mode: WRITER, 1026 | }, 1027 | { 1028 | name: "none logger simple", 1029 | args: args{ 1030 | name: "none", 1031 | uri: "/", 1032 | }, 1033 | mode: NONE, 1034 | }, 1035 | } 1036 | for _, tt := range tests { 1037 | t.Run(tt.name, func(t *testing.T) { 1038 | w := new(bytes.Buffer) 1039 | 1040 | req, err := http.NewRequest(http.MethodGet, tt.args.uri, nil) 1041 | if err != nil { 1042 | t.Fatal(err) 1043 | } 1044 | rr := httptest.NewRecorder() 1045 | 1046 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) 1047 | want := fmt.Sprintf("Method: %s\tURI: %s\tName: %s", 1048 | req.Method, req.RequestURI, tt.args.name) 1049 | 1050 | g := New().SetMode(tt.mode).SetWriter(w) 1051 | 1052 | g.HTTPLogger(tt.args.name, handler).ServeHTTP(rr, req) 1053 | 1054 | if !strings.Contains(w.String(), want) && tt.mode != NONE { 1055 | t.Errorf("Glg.HTTPLogger() = %v, want %v", w.String(), want) 1056 | } 1057 | }) 1058 | } 1059 | } 1060 | 1061 | func TestGlg_HTTPLoggerFunc(t *testing.T) { 1062 | type args struct { 1063 | name string 1064 | uri string 1065 | } 1066 | tests := []struct { 1067 | w *bytes.Buffer 1068 | name string 1069 | args args 1070 | mode MODE 1071 | }{ 1072 | { 1073 | w: new(bytes.Buffer), 1074 | name: "http logger simple", 1075 | args: args{ 1076 | name: "simple", 1077 | uri: "/", 1078 | }, 1079 | mode: WRITER, 1080 | }, 1081 | { 1082 | w: new(bytes.Buffer), 1083 | name: "http logger err", 1084 | args: args{ 1085 | name: "err", 1086 | uri: "err", 1087 | }, 1088 | mode: WRITER, 1089 | }, 1090 | { 1091 | w: new(bytes.Buffer), 1092 | name: "none logger simple", 1093 | args: args{ 1094 | name: "none", 1095 | uri: "/", 1096 | }, 1097 | mode: NONE, 1098 | }, 1099 | { 1100 | w: new(bytes.Buffer), 1101 | name: "http logger write to nil buffer error", 1102 | args: args{ 1103 | name: "err", 1104 | uri: "err", 1105 | }, 1106 | mode: WRITER, 1107 | }, 1108 | } 1109 | for _, tt := range tests { 1110 | t.Run(tt.name, func(t *testing.T) { 1111 | req, err := http.NewRequest(http.MethodGet, tt.args.uri, nil) 1112 | if err != nil { 1113 | t.Fatal(err) 1114 | } 1115 | rr := httptest.NewRecorder() 1116 | 1117 | want := fmt.Sprintf("Method: %s\tURI: %s\tName: %s", 1118 | req.Method, req.RequestURI, tt.args.name) 1119 | 1120 | g := New().SetMode(tt.mode).SetWriter(tt.w) 1121 | 1122 | g.HTTPLoggerFunc(tt.args.name, func(w http.ResponseWriter, r *http.Request) {}).ServeHTTP(rr, req) 1123 | 1124 | if tt.w != nil && !strings.Contains(tt.w.String(), want) && tt.mode != NONE { 1125 | t.Errorf("Glg.HTTPLogger() = %v, want %v", tt.w.String(), want) 1126 | } 1127 | }) 1128 | } 1129 | } 1130 | 1131 | func TestHTTPLogger(t *testing.T) { 1132 | type args struct { 1133 | name string 1134 | uri string 1135 | } 1136 | tests := []struct { 1137 | name string 1138 | args args 1139 | }{ 1140 | { 1141 | name: "http logger simple", 1142 | args: args{ 1143 | name: "simple", 1144 | uri: "/", 1145 | }, 1146 | }, 1147 | { 1148 | name: "http logger err", 1149 | args: args{ 1150 | name: "err", 1151 | uri: "err", 1152 | }, 1153 | }, 1154 | } 1155 | for _, tt := range tests { 1156 | t.Run(tt.name, func(t *testing.T) { 1157 | w := new(bytes.Buffer) 1158 | 1159 | req, err := http.NewRequest(http.MethodGet, tt.args.uri, nil) 1160 | if err != nil { 1161 | t.Fatal(err) 1162 | } 1163 | rr := httptest.NewRecorder() 1164 | 1165 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) 1166 | want := fmt.Sprintf("Method: %s\tURI: %s\tName: %s", 1167 | req.Method, req.RequestURI, tt.args.name) 1168 | 1169 | Get().SetMode(WRITER).SetWriter(w) 1170 | 1171 | HTTPLogger(tt.args.name, handler).ServeHTTP(rr, req) 1172 | 1173 | if !strings.Contains(w.String(), want) { 1174 | t.Errorf("HTTPLogger() = %v, want %v", w.String(), want) 1175 | } 1176 | }) 1177 | } 1178 | } 1179 | 1180 | func TestHTTPLoggerFunc(t *testing.T) { 1181 | type args struct { 1182 | name string 1183 | uri string 1184 | } 1185 | tests := []struct { 1186 | name string 1187 | args args 1188 | }{ 1189 | { 1190 | name: "http logger simple", 1191 | args: args{ 1192 | name: "simple", 1193 | uri: "/", 1194 | }, 1195 | }, 1196 | { 1197 | name: "http logger err", 1198 | args: args{ 1199 | name: "err", 1200 | uri: "err", 1201 | }, 1202 | }, 1203 | } 1204 | for _, tt := range tests { 1205 | t.Run(tt.name, func(t *testing.T) { 1206 | w := new(bytes.Buffer) 1207 | 1208 | req, err := http.NewRequest(http.MethodGet, tt.args.uri, nil) 1209 | if err != nil { 1210 | t.Fatal(err) 1211 | } 1212 | rr := httptest.NewRecorder() 1213 | 1214 | want := fmt.Sprintf("Method: %s\tURI: %s\tName: %s", 1215 | req.Method, req.RequestURI, tt.args.name) 1216 | 1217 | Get().SetMode(WRITER).SetWriter(w) 1218 | 1219 | HTTPLoggerFunc(tt.args.name, func(w http.ResponseWriter, r *http.Request) {}).ServeHTTP(rr, req) 1220 | 1221 | if !strings.Contains(w.String(), want) { 1222 | t.Errorf("HTTPLoggerFunc() = %v, want %v", w.String(), want) 1223 | } 1224 | }) 1225 | } 1226 | } 1227 | 1228 | func TestColorless(t *testing.T) { 1229 | tests := []struct { 1230 | name string 1231 | txt string 1232 | want string 1233 | }{ 1234 | { 1235 | name: "colorless", 1236 | txt: "message", 1237 | want: "message", 1238 | }, 1239 | } 1240 | for _, tt := range tests { 1241 | t.Run(tt.name, func(t *testing.T) { 1242 | if got := Colorless(tt.txt); got != tt.want { 1243 | t.Errorf("Colorless() = %v, want %v", got, tt.want) 1244 | } 1245 | }) 1246 | } 1247 | } 1248 | 1249 | func TestRed(t *testing.T) { 1250 | tests := []struct { 1251 | name string 1252 | txt string 1253 | want string 1254 | }{ 1255 | { 1256 | name: "red", 1257 | txt: "message", 1258 | }, 1259 | } 1260 | for _, tt := range tests { 1261 | t.Run(tt.name, func(t *testing.T) { 1262 | if got := Red(tt.txt); !strings.HasPrefix(got, "\033[31m") || !strings.HasSuffix(got, "\033[39m") { 1263 | t.Errorf("Red() = %v, want %v", got, tt.want) 1264 | } 1265 | }) 1266 | } 1267 | } 1268 | 1269 | func TestGreen(t *testing.T) { 1270 | tests := []struct { 1271 | name string 1272 | txt string 1273 | want string 1274 | }{ 1275 | { 1276 | name: "green", 1277 | txt: "message", 1278 | }, 1279 | } 1280 | for _, tt := range tests { 1281 | t.Run(tt.name, func(t *testing.T) { 1282 | if got := Green(tt.txt); !strings.HasPrefix(got, "\033[32m") || !strings.HasSuffix(got, "\033[39m") { 1283 | t.Errorf("Green() = %v, want %v", got, tt.want) 1284 | } 1285 | }) 1286 | } 1287 | } 1288 | 1289 | func TestOrange(t *testing.T) { 1290 | tests := []struct { 1291 | name string 1292 | txt string 1293 | want string 1294 | }{ 1295 | { 1296 | name: "orange", 1297 | txt: "message", 1298 | }, 1299 | } 1300 | for _, tt := range tests { 1301 | t.Run(tt.name, func(t *testing.T) { 1302 | if got := Orange(tt.txt); !strings.HasPrefix(got, "\033[33m") || !strings.HasSuffix(got, "\033[39m") { 1303 | t.Errorf("Orange() = %v, want %v", got, tt.want) 1304 | } 1305 | }) 1306 | } 1307 | } 1308 | 1309 | func TestPurple(t *testing.T) { 1310 | tests := []struct { 1311 | name string 1312 | txt string 1313 | want string 1314 | }{ 1315 | { 1316 | name: "purple", 1317 | txt: "message", 1318 | }, 1319 | } 1320 | for _, tt := range tests { 1321 | t.Run(tt.name, func(t *testing.T) { 1322 | if got := Purple(tt.txt); !strings.HasPrefix(got, "\033[34m") || !strings.HasSuffix(got, "\033[39m") { 1323 | t.Errorf("Purple() = %v, want %v", got, tt.want) 1324 | } 1325 | }) 1326 | } 1327 | } 1328 | 1329 | func TestCyan(t *testing.T) { 1330 | tests := []struct { 1331 | name string 1332 | txt string 1333 | want string 1334 | }{ 1335 | { 1336 | name: "cyan", 1337 | txt: "message", 1338 | }, 1339 | } 1340 | for _, tt := range tests { 1341 | t.Run(tt.name, func(t *testing.T) { 1342 | if got := Cyan(tt.txt); !strings.HasPrefix(got, "\033[36m") || !strings.HasSuffix(got, "\033[39m") { 1343 | t.Errorf("Cyan() = %v, want %v", got, tt.want) 1344 | } 1345 | }) 1346 | } 1347 | } 1348 | 1349 | func TestYellow(t *testing.T) { 1350 | tests := []struct { 1351 | name string 1352 | txt string 1353 | want string 1354 | }{ 1355 | { 1356 | name: "yellow", 1357 | txt: "message", 1358 | }, 1359 | } 1360 | for _, tt := range tests { 1361 | t.Run(tt.name, func(t *testing.T) { 1362 | if got := Yellow(tt.txt); !strings.HasPrefix(got, "\033[93m") || !strings.HasSuffix(got, "\033[39m") { 1363 | t.Errorf("Yellow() = %v, want %v", got, tt.want) 1364 | } 1365 | }) 1366 | } 1367 | } 1368 | 1369 | func TestBrown(t *testing.T) { 1370 | tests := []struct { 1371 | name string 1372 | txt string 1373 | want string 1374 | }{ 1375 | { 1376 | name: "brown", 1377 | txt: "message", 1378 | }, 1379 | } 1380 | for _, tt := range tests { 1381 | t.Run(tt.name, func(t *testing.T) { 1382 | if got := Brown(tt.txt); !strings.HasPrefix(got, "\033[96m") || !strings.HasSuffix(got, "\033[39m") { 1383 | t.Errorf("Brown() = %v, want %v", got, tt.want) 1384 | } 1385 | }) 1386 | } 1387 | } 1388 | 1389 | func TestGray(t *testing.T) { 1390 | tests := []struct { 1391 | name string 1392 | txt string 1393 | want string 1394 | }{ 1395 | { 1396 | name: "gray", 1397 | txt: "message", 1398 | }, 1399 | } 1400 | for _, tt := range tests { 1401 | t.Run(tt.name, func(t *testing.T) { 1402 | if got := Gray(tt.txt); !strings.HasPrefix(got, "\033[90m") || !strings.HasSuffix(got, "\033[39m") { 1403 | t.Errorf("Gray() = %v, want %v", got, tt.want) 1404 | } 1405 | }) 1406 | } 1407 | } 1408 | 1409 | func TestBlack(t *testing.T) { 1410 | tests := []struct { 1411 | name string 1412 | txt string 1413 | want string 1414 | }{ 1415 | { 1416 | name: "black", 1417 | txt: "message", 1418 | }, 1419 | } 1420 | for _, tt := range tests { 1421 | t.Run(tt.name, func(t *testing.T) { 1422 | if got := Black(tt.txt); !strings.HasPrefix(got, "\033[30m") || !strings.HasSuffix(got, "\033[39m") { 1423 | t.Errorf("Black() = %v, want %v", got, tt.want) 1424 | } 1425 | }) 1426 | } 1427 | } 1428 | 1429 | func TestWhite(t *testing.T) { 1430 | tests := []struct { 1431 | name string 1432 | txt string 1433 | want string 1434 | }{ 1435 | { 1436 | name: "white", 1437 | txt: "message", 1438 | }, 1439 | } 1440 | for _, tt := range tests { 1441 | t.Run(tt.name, func(t *testing.T) { 1442 | if got := White(tt.txt); !strings.HasPrefix(got, "\033[97m") || !strings.HasSuffix(got, "\033[39m") { 1443 | t.Errorf("White() = %v, want %v", got, tt.want) 1444 | } 1445 | }) 1446 | } 1447 | } 1448 | 1449 | func TestGlg_out(t *testing.T) { 1450 | tests := []struct { 1451 | glg *Glg 1452 | name string 1453 | level LEVEL 1454 | format string 1455 | val []interface{} 1456 | }{ 1457 | { 1458 | glg: New().SetMode(WRITER), 1459 | name: "sample info", 1460 | level: INFO, 1461 | format: "%d%s%f", 1462 | val: []interface{}{ 1463 | 2, 1464 | "aaa", 1465 | 3.6, 1466 | }, 1467 | }, 1468 | { 1469 | glg: New().SetMode(WRITER), 1470 | name: "sample log", 1471 | level: LOG, 1472 | format: "%d%s%f", 1473 | val: []interface{}{ 1474 | 2, 1475 | "aaa", 1476 | 3.6, 1477 | }, 1478 | }, 1479 | { 1480 | glg: New().SetMode(NONE), 1481 | name: "no log", 1482 | level: LOG, 1483 | format: "%d%s%f", 1484 | val: []interface{}{ 1485 | 2, 1486 | "aaa", 1487 | 3.6, 1488 | }, 1489 | }, 1490 | { 1491 | glg: New().SetMode(STD), 1492 | name: "no log", 1493 | level: LOG, 1494 | format: "%d%s%f", 1495 | val: []interface{}{ 1496 | 2, 1497 | "aaa", 1498 | 3.6, 1499 | }, 1500 | }, 1501 | { 1502 | glg: New().SetMode(BOTH), 1503 | name: "no log", 1504 | level: LOG, 1505 | format: "%d%s%f", 1506 | val: []interface{}{ 1507 | 2, 1508 | "aaa", 1509 | 3.6, 1510 | }, 1511 | }, 1512 | { 1513 | glg: New().SetMode(STD).DisableColor(), 1514 | name: "no log", 1515 | level: LOG, 1516 | format: "%d%s%f", 1517 | val: []interface{}{ 1518 | 2, 1519 | "aaa", 1520 | 3.6, 1521 | }, 1522 | }, 1523 | { 1524 | glg: New().SetMode(BOTH).DisableColor(), 1525 | name: "no log", 1526 | level: LOG, 1527 | format: "%d%s%f", 1528 | val: []interface{}{ 1529 | 2, 1530 | "aaa", 1531 | 3.6, 1532 | }, 1533 | }, 1534 | { 1535 | glg: New().SetMode(NONE).DisableColor(), 1536 | name: "not found level", 1537 | level: LEVEL(10), 1538 | format: "%d%s%f", 1539 | val: []interface{}{ 1540 | 2, 1541 | "aaa", 1542 | 3.6, 1543 | }, 1544 | }, 1545 | { 1546 | glg: New().SetMode(NONE).DisableColor(), 1547 | name: "too long argument log", 1548 | level: LOG, 1549 | format: "", 1550 | val: func() []interface{} { 1551 | var vals []interface{} 1552 | for i := 0; i < 1000; i++ { 1553 | vals = append(vals, i) 1554 | } 1555 | return vals 1556 | }(), 1557 | }, 1558 | } 1559 | for _, tt := range tests { 1560 | t.Run(tt.name, func(t *testing.T) { 1561 | buf := new(bytes.Buffer) 1562 | g := tt.glg.SetWriter(buf) 1563 | g.out(tt.level, tt.format, tt.val...) 1564 | want := fmt.Sprintf(tt.format, tt.val...) 1565 | if !strings.Contains(buf.String(), want) && tt.glg.GetCurrentMode(LOG) != NONE && tt.glg.GetCurrentMode(LOG) != STD { 1566 | t.Errorf("Glg.out() = got %v want %v", buf.String(), want) 1567 | } 1568 | }) 1569 | } 1570 | } 1571 | 1572 | func TestGlg_Log(t *testing.T) { 1573 | tests := []struct { 1574 | name string 1575 | val []interface{} 1576 | }{ 1577 | { 1578 | name: "sample log", 1579 | val: []interface{}{ 1580 | "sample log", 1581 | }, 1582 | }, 1583 | } 1584 | for _, tt := range tests { 1585 | t.Run(tt.name, func(t *testing.T) { 1586 | buf := new(bytes.Buffer) 1587 | g := New().SetMode(WRITER).SetWriter(buf) 1588 | err := g.Log(tt.val...) 1589 | want := fmt.Sprintf("%v", tt.val...) 1590 | if err != nil { 1591 | t.Errorf("Glg.Log() unexpected error: %v", err) 1592 | } 1593 | if !strings.Contains(buf.String(), want) { 1594 | t.Errorf("Glg.Log() = got %v want %v", buf.String(), want) 1595 | } 1596 | }) 1597 | } 1598 | } 1599 | 1600 | func TestGlg_Logf(t *testing.T) { 1601 | tests := []struct { 1602 | name string 1603 | format string 1604 | val []interface{} 1605 | }{ 1606 | { 1607 | name: "sample log", 1608 | format: "%d%s%f", 1609 | val: []interface{}{ 1610 | 2, 1611 | "aaa", 1612 | 3.6, 1613 | }, 1614 | }, 1615 | { 1616 | name: "sample log", 1617 | format: "%d%s%f", 1618 | val: []interface{}{ 1619 | 2, 1620 | "aaa", 1621 | 3.6, 1622 | }, 1623 | }, 1624 | } 1625 | for _, tt := range tests { 1626 | t.Run(tt.name, func(t *testing.T) { 1627 | buf := new(bytes.Buffer) 1628 | g := New().SetMode(WRITER).SetWriter(buf) 1629 | err := g.Logf(tt.format, tt.val...) 1630 | want := fmt.Sprintf(tt.format, tt.val...) 1631 | if err != nil { 1632 | t.Errorf("Glg.Logf() unexpected error: %v", err) 1633 | } 1634 | if !strings.Contains(buf.String(), want) { 1635 | t.Errorf("Glg.Logf() = got %v want %v", buf.String(), want) 1636 | } 1637 | }) 1638 | } 1639 | } 1640 | 1641 | func TestGlg_LogFunc(t *testing.T) { 1642 | tests := []struct { 1643 | name string 1644 | logMode MODE 1645 | f func() string 1646 | want string 1647 | }{ 1648 | { 1649 | name: "sample log", 1650 | logMode: WRITER, 1651 | f: func() string { 1652 | return dummy 1653 | }, 1654 | want: dummy, 1655 | }, 1656 | { 1657 | name: "sample log", 1658 | logMode: NONE, 1659 | f: func() string { 1660 | return dummy 1661 | }, 1662 | want: "", 1663 | }, 1664 | } 1665 | for _, tt := range tests { 1666 | t.Run(tt.name, func(t *testing.T) { 1667 | buf := new(bytes.Buffer) 1668 | g := New().SetMode(tt.logMode).SetWriter(buf) 1669 | err := g.LogFunc(tt.f) 1670 | if err != nil { 1671 | t.Errorf("Glg.LogFunc() unexpected error: %v", err) 1672 | } 1673 | if !strings.Contains(buf.String(), tt.want) { 1674 | t.Errorf("Glg.LogFunc() = got %v want %v", buf.String(), tt.want) 1675 | } 1676 | }) 1677 | } 1678 | } 1679 | 1680 | func TestLog(t *testing.T) { 1681 | tests := []struct { 1682 | name string 1683 | val []interface{} 1684 | }{ 1685 | { 1686 | name: "sample log", 1687 | val: []interface{}{ 1688 | "sample log", 1689 | }, 1690 | }, 1691 | } 1692 | for _, tt := range tests { 1693 | t.Run(tt.name, func(t *testing.T) { 1694 | buf := new(bytes.Buffer) 1695 | Get().SetMode(WRITER).SetWriter(buf) 1696 | err := Log(tt.val...) 1697 | want := fmt.Sprintf("%v", tt.val...) 1698 | if err != nil { 1699 | t.Errorf("Log() unexpected error: %v", err) 1700 | } 1701 | if !strings.Contains(buf.String(), want) { 1702 | t.Errorf("Log() = got %v want %v", buf.String(), want) 1703 | } 1704 | }) 1705 | } 1706 | } 1707 | 1708 | func TestLogf(t *testing.T) { 1709 | tests := []struct { 1710 | name string 1711 | format string 1712 | val []interface{} 1713 | }{ 1714 | { 1715 | name: "sample info", 1716 | format: "%d%s%f", 1717 | val: []interface{}{ 1718 | 2, 1719 | "aaa", 1720 | 3.6, 1721 | }, 1722 | }, 1723 | { 1724 | name: "sample log", 1725 | format: "%d%s%f", 1726 | val: []interface{}{ 1727 | 2, 1728 | "aaa", 1729 | 3.6, 1730 | }, 1731 | }, 1732 | } 1733 | for _, tt := range tests { 1734 | t.Run(tt.name, func(t *testing.T) { 1735 | buf := new(bytes.Buffer) 1736 | Get().SetMode(WRITER).SetWriter(buf) 1737 | err := Logf(tt.format, tt.val...) 1738 | want := fmt.Sprintf(tt.format, tt.val...) 1739 | if err != nil { 1740 | t.Errorf("Logf() unexpected error: %v", err) 1741 | } 1742 | if !strings.Contains(buf.String(), want) { 1743 | t.Errorf("Logf() = got %v want %v", buf.String(), want) 1744 | } 1745 | }) 1746 | } 1747 | } 1748 | 1749 | func TestLogFunc(t *testing.T) { 1750 | tests := []struct { 1751 | name string 1752 | logMode MODE 1753 | f func() string 1754 | want string 1755 | }{ 1756 | { 1757 | name: "sample log", 1758 | logMode: WRITER, 1759 | f: func() string { 1760 | return dummy 1761 | }, 1762 | want: dummy, 1763 | }, 1764 | { 1765 | name: "sample log", 1766 | logMode: NONE, 1767 | f: func() string { 1768 | return dummy 1769 | }, 1770 | want: "", 1771 | }, 1772 | } 1773 | for _, tt := range tests { 1774 | t.Run(tt.name, func(t *testing.T) { 1775 | buf := new(bytes.Buffer) 1776 | Get().SetMode(tt.logMode).SetWriter(buf) 1777 | err := LogFunc(tt.f) 1778 | if err != nil { 1779 | t.Errorf("LogFunc() unexpected error: %v", err) 1780 | } 1781 | if !strings.Contains(buf.String(), tt.want) { 1782 | t.Errorf("LogFunc() = got %v want %v", buf.String(), tt.want) 1783 | } 1784 | }) 1785 | } 1786 | } 1787 | 1788 | func TestGlg_Info(t *testing.T) { 1789 | tests := []struct { 1790 | name string 1791 | val []interface{} 1792 | }{ 1793 | { 1794 | name: "sample info", 1795 | val: []interface{}{ 1796 | "sample info", 1797 | }, 1798 | }, 1799 | } 1800 | for _, tt := range tests { 1801 | t.Run(tt.name, func(t *testing.T) { 1802 | buf := new(bytes.Buffer) 1803 | g := New().SetMode(WRITER).SetWriter(buf) 1804 | err := g.Info(tt.val...) 1805 | want := fmt.Sprintf("%v", tt.val...) 1806 | if err != nil { 1807 | t.Errorf("Glg.Info() unexpected error: %v", err) 1808 | } 1809 | if !strings.Contains(buf.String(), want) { 1810 | t.Errorf("Glg.Info() = got %v want %v", buf.String(), want) 1811 | } 1812 | }) 1813 | } 1814 | } 1815 | 1816 | func TestGlg_Infof(t *testing.T) { 1817 | tests := []struct { 1818 | name string 1819 | format string 1820 | val []interface{} 1821 | }{ 1822 | { 1823 | name: "sample info", 1824 | format: "%d%s%f", 1825 | val: []interface{}{ 1826 | 2, 1827 | "aaa", 1828 | 3.6, 1829 | }, 1830 | }, 1831 | { 1832 | name: "sample info", 1833 | format: "%d%s%f", 1834 | val: []interface{}{ 1835 | 2, 1836 | "aaa", 1837 | 3.6, 1838 | }, 1839 | }, 1840 | } 1841 | for _, tt := range tests { 1842 | t.Run(tt.name, func(t *testing.T) { 1843 | buf := new(bytes.Buffer) 1844 | g := New().SetMode(WRITER).SetWriter(buf) 1845 | err := g.Infof(tt.format, tt.val...) 1846 | want := fmt.Sprintf(tt.format, tt.val...) 1847 | if err != nil { 1848 | t.Errorf("Glg.Infof() unexpected error: %v", err) 1849 | } 1850 | if !strings.Contains(buf.String(), want) { 1851 | t.Errorf("Glg.Infof() = got %v want %v", buf.String(), want) 1852 | } 1853 | }) 1854 | } 1855 | } 1856 | 1857 | func TestGlg_InfoFunc(t *testing.T) { 1858 | tests := []struct { 1859 | name string 1860 | logMode MODE 1861 | f func() string 1862 | want string 1863 | }{ 1864 | { 1865 | name: "sample log", 1866 | logMode: WRITER, 1867 | f: func() string { 1868 | return dummy 1869 | }, 1870 | want: dummy, 1871 | }, 1872 | { 1873 | name: "sample log", 1874 | logMode: NONE, 1875 | f: func() string { 1876 | return dummy 1877 | }, 1878 | want: "", 1879 | }, 1880 | } 1881 | for _, tt := range tests { 1882 | t.Run(tt.name, func(t *testing.T) { 1883 | buf := new(bytes.Buffer) 1884 | g := New().SetMode(tt.logMode).SetWriter(buf) 1885 | err := g.InfoFunc(tt.f) 1886 | if err != nil { 1887 | t.Errorf("Glg.InfoFunc() unexpected error: %v", err) 1888 | } 1889 | if !strings.Contains(buf.String(), tt.want) { 1890 | t.Errorf("Glg.InfoFunc() = got %v want %v", buf.String(), tt.want) 1891 | } 1892 | }) 1893 | } 1894 | } 1895 | 1896 | func TestInfo(t *testing.T) { 1897 | tests := []struct { 1898 | name string 1899 | val []interface{} 1900 | }{ 1901 | { 1902 | name: "sample info", 1903 | val: []interface{}{ 1904 | "sample info", 1905 | }, 1906 | }, 1907 | } 1908 | for _, tt := range tests { 1909 | t.Run(tt.name, func(t *testing.T) { 1910 | buf := new(bytes.Buffer) 1911 | Get().SetMode(WRITER).SetWriter(buf) 1912 | err := Info(tt.val...) 1913 | want := fmt.Sprintf("%v", tt.val...) 1914 | if err != nil { 1915 | t.Errorf("Info() unexpected error: %v", err) 1916 | } 1917 | if !strings.Contains(buf.String(), want) { 1918 | t.Errorf("Info() = got %v want %v", buf.String(), want) 1919 | } 1920 | }) 1921 | } 1922 | } 1923 | 1924 | func TestInfof(t *testing.T) { 1925 | tests := []struct { 1926 | name string 1927 | format string 1928 | val []interface{} 1929 | }{ 1930 | { 1931 | name: "sample info", 1932 | format: "%d%s%f", 1933 | val: []interface{}{ 1934 | 2, 1935 | "aaa", 1936 | 3.6, 1937 | }, 1938 | }, 1939 | { 1940 | name: "sample info", 1941 | format: "%d%s%f", 1942 | val: []interface{}{ 1943 | 2, 1944 | "aaa", 1945 | 3.6, 1946 | }, 1947 | }, 1948 | } 1949 | for _, tt := range tests { 1950 | t.Run(tt.name, func(t *testing.T) { 1951 | buf := new(bytes.Buffer) 1952 | Get().SetMode(WRITER).SetWriter(buf) 1953 | err := Infof(tt.format, tt.val...) 1954 | want := fmt.Sprintf(tt.format, tt.val...) 1955 | if err != nil { 1956 | t.Errorf("Infof() unexpected error: %v", err) 1957 | } 1958 | if !strings.Contains(buf.String(), want) { 1959 | t.Errorf("Infof() = got %v want %v", buf.String(), want) 1960 | } 1961 | }) 1962 | } 1963 | } 1964 | 1965 | func TestInfoFunc(t *testing.T) { 1966 | tests := []struct { 1967 | name string 1968 | logMode MODE 1969 | f func() string 1970 | want string 1971 | }{ 1972 | { 1973 | name: "sample log", 1974 | logMode: WRITER, 1975 | f: func() string { 1976 | return dummy 1977 | }, 1978 | want: dummy, 1979 | }, 1980 | { 1981 | name: "sample log", 1982 | logMode: NONE, 1983 | f: func() string { 1984 | return dummy 1985 | }, 1986 | want: "", 1987 | }, 1988 | } 1989 | for _, tt := range tests { 1990 | t.Run(tt.name, func(t *testing.T) { 1991 | buf := new(bytes.Buffer) 1992 | Get().SetMode(tt.logMode).SetWriter(buf) 1993 | err := InfoFunc(tt.f) 1994 | if err != nil { 1995 | t.Errorf("InfoFunc() unexpected error: %v", err) 1996 | } 1997 | if !strings.Contains(buf.String(), tt.want) { 1998 | t.Errorf("InfoFunc() = got %v want %v", buf.String(), tt.want) 1999 | } 2000 | }) 2001 | } 2002 | } 2003 | 2004 | func TestGlg_Success(t *testing.T) { 2005 | tests := []struct { 2006 | name string 2007 | val []interface{} 2008 | }{ 2009 | { 2010 | name: "sample success", 2011 | val: []interface{}{ 2012 | "sample success", 2013 | }, 2014 | }, 2015 | } 2016 | for _, tt := range tests { 2017 | t.Run(tt.name, func(t *testing.T) { 2018 | buf := new(bytes.Buffer) 2019 | g := New().SetMode(WRITER).SetWriter(buf) 2020 | err := g.Success(tt.val...) 2021 | want := fmt.Sprintf("%v", tt.val...) 2022 | if err != nil { 2023 | t.Errorf("Glg.Success() unexpected error: %v", err) 2024 | } 2025 | if !strings.Contains(buf.String(), want) { 2026 | t.Errorf("Glg.Success() = got %v want %v", buf.String(), want) 2027 | } 2028 | }) 2029 | } 2030 | } 2031 | 2032 | func TestGlg_Successf(t *testing.T) { 2033 | tests := []struct { 2034 | name string 2035 | format string 2036 | val []interface{} 2037 | }{ 2038 | { 2039 | name: "sample success", 2040 | format: "%d%s%f", 2041 | val: []interface{}{ 2042 | 2, 2043 | "aaa", 2044 | 3.6, 2045 | }, 2046 | }, 2047 | { 2048 | name: "sample success", 2049 | format: "%d%s%f", 2050 | val: []interface{}{ 2051 | 2, 2052 | "aaa", 2053 | 3.6, 2054 | }, 2055 | }, 2056 | } 2057 | for _, tt := range tests { 2058 | t.Run(tt.name, func(t *testing.T) { 2059 | buf := new(bytes.Buffer) 2060 | g := New().SetMode(WRITER).SetWriter(buf) 2061 | err := g.Successf(tt.format, tt.val...) 2062 | want := fmt.Sprintf(tt.format, tt.val...) 2063 | if err != nil { 2064 | t.Errorf("Glg.Successf() unexpected error: %v", err) 2065 | } 2066 | if !strings.Contains(buf.String(), want) { 2067 | t.Errorf("Glg.Successf() = got %v want %v", buf.String(), want) 2068 | } 2069 | }) 2070 | } 2071 | } 2072 | 2073 | func TestGlg_SuccessFunc(t *testing.T) { 2074 | tests := []struct { 2075 | name string 2076 | logMode MODE 2077 | f func() string 2078 | want string 2079 | }{ 2080 | { 2081 | name: "sample log", 2082 | logMode: WRITER, 2083 | f: func() string { 2084 | return dummy 2085 | }, 2086 | want: dummy, 2087 | }, 2088 | { 2089 | name: "sample log", 2090 | logMode: NONE, 2091 | f: func() string { 2092 | return dummy 2093 | }, 2094 | want: "", 2095 | }, 2096 | } 2097 | for _, tt := range tests { 2098 | t.Run(tt.name, func(t *testing.T) { 2099 | buf := new(bytes.Buffer) 2100 | g := New().SetMode(tt.logMode).SetWriter(buf) 2101 | err := g.SuccessFunc(tt.f) 2102 | if err != nil { 2103 | t.Errorf("Glg.SuccessFunc() unexpected error: %v", err) 2104 | } 2105 | if !strings.Contains(buf.String(), tt.want) { 2106 | t.Errorf("Glg.SuccessFunc() = got %v want %v", buf.String(), tt.want) 2107 | } 2108 | }) 2109 | } 2110 | } 2111 | 2112 | func TestSuccess(t *testing.T) { 2113 | tests := []struct { 2114 | name string 2115 | val []interface{} 2116 | }{ 2117 | { 2118 | name: "sample success", 2119 | val: []interface{}{ 2120 | "sample success", 2121 | }, 2122 | }, 2123 | } 2124 | for _, tt := range tests { 2125 | t.Run(tt.name, func(t *testing.T) { 2126 | buf := new(bytes.Buffer) 2127 | Get().SetMode(WRITER).SetWriter(buf) 2128 | err := Success(tt.val...) 2129 | want := fmt.Sprintf("%v", tt.val...) 2130 | if err != nil { 2131 | t.Errorf("Success() unexpected error: %v", err) 2132 | } 2133 | if !strings.Contains(buf.String(), want) { 2134 | t.Errorf("Success() = got %v want %v", buf.String(), want) 2135 | } 2136 | }) 2137 | } 2138 | } 2139 | 2140 | func TestSuccessf(t *testing.T) { 2141 | tests := []struct { 2142 | name string 2143 | format string 2144 | val []interface{} 2145 | }{ 2146 | { 2147 | name: "sample success", 2148 | format: "%d%s%f", 2149 | val: []interface{}{ 2150 | 2, 2151 | "aaa", 2152 | 3.6, 2153 | }, 2154 | }, 2155 | { 2156 | name: "sample success", 2157 | format: "%d%s%f", 2158 | val: []interface{}{ 2159 | 2, 2160 | "aaa", 2161 | 3.6, 2162 | }, 2163 | }, 2164 | } 2165 | for _, tt := range tests { 2166 | t.Run(tt.name, func(t *testing.T) { 2167 | buf := new(bytes.Buffer) 2168 | Get().SetMode(WRITER).SetWriter(buf) 2169 | err := Successf(tt.format, tt.val...) 2170 | want := fmt.Sprintf(tt.format, tt.val...) 2171 | if err != nil { 2172 | t.Errorf("Successf() unexpected error: %v", err) 2173 | } 2174 | if !strings.Contains(buf.String(), want) { 2175 | t.Errorf("Successf() = got %v want %v", buf.String(), want) 2176 | } 2177 | }) 2178 | } 2179 | } 2180 | 2181 | func TestSuccessFunc(t *testing.T) { 2182 | tests := []struct { 2183 | name string 2184 | logMode MODE 2185 | f func() string 2186 | want string 2187 | }{ 2188 | { 2189 | name: "sample log", 2190 | logMode: WRITER, 2191 | f: func() string { 2192 | return dummy 2193 | }, 2194 | want: dummy, 2195 | }, 2196 | { 2197 | name: "sample log", 2198 | logMode: NONE, 2199 | f: func() string { 2200 | return dummy 2201 | }, 2202 | want: "", 2203 | }, 2204 | } 2205 | for _, tt := range tests { 2206 | t.Run(tt.name, func(t *testing.T) { 2207 | buf := new(bytes.Buffer) 2208 | Get().SetMode(tt.logMode).SetWriter(buf) 2209 | err := SuccessFunc(tt.f) 2210 | if err != nil { 2211 | t.Errorf("SuccessFunc() unexpected error: %v", err) 2212 | } 2213 | if !strings.Contains(buf.String(), tt.want) { 2214 | t.Errorf("SuccessFunc() = got %v want %v", buf.String(), tt.want) 2215 | } 2216 | }) 2217 | } 2218 | } 2219 | 2220 | func TestGlg_Debug(t *testing.T) { 2221 | tests := []struct { 2222 | name string 2223 | val []interface{} 2224 | }{ 2225 | { 2226 | name: "sample debug", 2227 | val: []interface{}{ 2228 | "sample debug", 2229 | }, 2230 | }, 2231 | } 2232 | for _, tt := range tests { 2233 | t.Run(tt.name, func(t *testing.T) { 2234 | buf := new(bytes.Buffer) 2235 | g := New().SetMode(WRITER).SetWriter(buf) 2236 | err := g.Debug(tt.val...) 2237 | want := fmt.Sprintf("%v", tt.val...) 2238 | if err != nil { 2239 | t.Errorf("Glg.Debug() unexpected error: %v", err) 2240 | } 2241 | if !strings.Contains(buf.String(), want) { 2242 | t.Errorf("Glg.Debug() = got %v want %v", buf.String(), want) 2243 | } 2244 | }) 2245 | } 2246 | } 2247 | 2248 | func TestGlg_Debugf(t *testing.T) { 2249 | tests := []struct { 2250 | name string 2251 | format string 2252 | val []interface{} 2253 | }{ 2254 | { 2255 | name: "sample debug", 2256 | format: "%d%s%f", 2257 | val: []interface{}{ 2258 | 2, 2259 | "aaa", 2260 | 3.6, 2261 | }, 2262 | }, 2263 | { 2264 | name: "sample debug", 2265 | format: "%d%s%f", 2266 | val: []interface{}{ 2267 | 2, 2268 | "aaa", 2269 | 3.6, 2270 | }, 2271 | }, 2272 | } 2273 | for _, tt := range tests { 2274 | t.Run(tt.name, func(t *testing.T) { 2275 | buf := new(bytes.Buffer) 2276 | g := New().SetMode(WRITER).SetWriter(buf) 2277 | err := g.Debugf(tt.format, tt.val...) 2278 | want := fmt.Sprintf(tt.format, tt.val...) 2279 | if err != nil { 2280 | t.Errorf("Glg.Debugf() unexpected error: %v", err) 2281 | } 2282 | if !strings.Contains(buf.String(), want) { 2283 | t.Errorf("Glg.Debugf() = got %v want %v", buf.String(), want) 2284 | } 2285 | }) 2286 | } 2287 | } 2288 | 2289 | func TestGlg_DebugFunc(t *testing.T) { 2290 | tests := []struct { 2291 | name string 2292 | logMode MODE 2293 | f func() string 2294 | want string 2295 | }{ 2296 | { 2297 | name: "sample log", 2298 | logMode: WRITER, 2299 | f: func() string { 2300 | return dummy 2301 | }, 2302 | want: dummy, 2303 | }, 2304 | { 2305 | name: "sample log", 2306 | logMode: NONE, 2307 | f: func() string { 2308 | return dummy 2309 | }, 2310 | want: "", 2311 | }, 2312 | } 2313 | for _, tt := range tests { 2314 | t.Run(tt.name, func(t *testing.T) { 2315 | buf := new(bytes.Buffer) 2316 | g := New().SetMode(tt.logMode).SetWriter(buf) 2317 | err := g.DebugFunc(tt.f) 2318 | if err != nil { 2319 | t.Errorf("Glg.DebugFunc() unexpected error: %v", err) 2320 | } 2321 | if !strings.Contains(buf.String(), tt.want) { 2322 | t.Errorf("Glg.DebugFunc() = got %v want %v", buf.String(), tt.want) 2323 | } 2324 | }) 2325 | } 2326 | } 2327 | 2328 | func TestDebug(t *testing.T) { 2329 | tests := []struct { 2330 | name string 2331 | val []interface{} 2332 | }{ 2333 | { 2334 | name: "sample debug", 2335 | val: []interface{}{ 2336 | "sample debug", 2337 | }, 2338 | }, 2339 | } 2340 | for _, tt := range tests { 2341 | t.Run(tt.name, func(t *testing.T) { 2342 | buf := new(bytes.Buffer) 2343 | Get().SetMode(WRITER).SetWriter(buf) 2344 | err := Debug(tt.val...) 2345 | want := fmt.Sprintf("%v", tt.val...) 2346 | if err != nil { 2347 | t.Errorf("Debug() unexpected error: %v", err) 2348 | } 2349 | if !strings.Contains(buf.String(), want) { 2350 | t.Errorf("Debug() = got %v want %v", buf.String(), want) 2351 | } 2352 | }) 2353 | } 2354 | } 2355 | 2356 | func TestDebugf(t *testing.T) { 2357 | tests := []struct { 2358 | name string 2359 | format string 2360 | val []interface{} 2361 | }{ 2362 | { 2363 | name: "sample debug", 2364 | format: "%d%s%f", 2365 | val: []interface{}{ 2366 | 2, 2367 | "aaa", 2368 | 3.6, 2369 | }, 2370 | }, 2371 | { 2372 | name: "sample debug", 2373 | format: "%d%s%f", 2374 | val: []interface{}{ 2375 | 2, 2376 | "aaa", 2377 | 3.6, 2378 | }, 2379 | }, 2380 | } 2381 | for _, tt := range tests { 2382 | t.Run(tt.name, func(t *testing.T) { 2383 | buf := new(bytes.Buffer) 2384 | Get().SetMode(WRITER).SetWriter(buf) 2385 | err := Debugf(tt.format, tt.val...) 2386 | want := fmt.Sprintf(tt.format, tt.val...) 2387 | if err != nil { 2388 | t.Errorf("Debugf() unexpected error: %v", err) 2389 | } 2390 | if !strings.Contains(buf.String(), want) { 2391 | t.Errorf("Debugf() = got %v want %v", buf.String(), want) 2392 | } 2393 | }) 2394 | } 2395 | } 2396 | 2397 | func TestDebugFunc(t *testing.T) { 2398 | tests := []struct { 2399 | name string 2400 | logMode MODE 2401 | f func() string 2402 | want string 2403 | }{ 2404 | { 2405 | name: "sample log", 2406 | logMode: WRITER, 2407 | f: func() string { 2408 | return dummy 2409 | }, 2410 | want: dummy, 2411 | }, 2412 | { 2413 | name: "sample log", 2414 | logMode: NONE, 2415 | f: func() string { 2416 | return dummy 2417 | }, 2418 | want: "", 2419 | }, 2420 | } 2421 | for _, tt := range tests { 2422 | t.Run(tt.name, func(t *testing.T) { 2423 | buf := new(bytes.Buffer) 2424 | Get().SetMode(tt.logMode).SetWriter(buf) 2425 | err := DebugFunc(tt.f) 2426 | if err != nil { 2427 | t.Errorf("DebugFunc() unexpected error: %v", err) 2428 | } 2429 | if !strings.Contains(buf.String(), tt.want) { 2430 | t.Errorf("DebugFunc() = got %v want %v", buf.String(), tt.want) 2431 | } 2432 | }) 2433 | } 2434 | } 2435 | 2436 | func TestGlg_Warn(t *testing.T) { 2437 | tests := []struct { 2438 | name string 2439 | val []interface{} 2440 | }{ 2441 | { 2442 | name: "sample warn", 2443 | val: []interface{}{ 2444 | "sample warn", 2445 | }, 2446 | }, 2447 | } 2448 | for _, tt := range tests { 2449 | t.Run(tt.name, func(t *testing.T) { 2450 | buf := new(bytes.Buffer) 2451 | g := New().SetMode(WRITER).SetWriter(buf) 2452 | err := g.Warn(tt.val...) 2453 | want := fmt.Sprintf("%v", tt.val...) 2454 | if err != nil { 2455 | t.Errorf("Glg.Warn() unexpected error: %v", err) 2456 | } 2457 | if !strings.Contains(buf.String(), want) { 2458 | t.Errorf("Glg.Warn() = got %v want %v", buf.String(), want) 2459 | } 2460 | }) 2461 | } 2462 | } 2463 | 2464 | func TestGlg_Warnf(t *testing.T) { 2465 | tests := []struct { 2466 | name string 2467 | format string 2468 | val []interface{} 2469 | }{ 2470 | { 2471 | name: "sample warnf", 2472 | format: "%d%s%f", 2473 | val: []interface{}{ 2474 | 2, 2475 | "aaa", 2476 | 3.6, 2477 | }, 2478 | }, 2479 | { 2480 | name: "sample warnf", 2481 | format: "%d%s%f", 2482 | val: []interface{}{ 2483 | 2, 2484 | "aaa", 2485 | 3.6, 2486 | }, 2487 | }, 2488 | } 2489 | for _, tt := range tests { 2490 | t.Run(tt.name, func(t *testing.T) { 2491 | buf := new(bytes.Buffer) 2492 | g := New().SetMode(WRITER).SetWriter(buf) 2493 | err := g.Warnf(tt.format, tt.val...) 2494 | want := fmt.Sprintf(tt.format, tt.val...) 2495 | if err != nil { 2496 | t.Errorf("Glg.Warnf() unexpected error: %v", err) 2497 | } 2498 | if !strings.Contains(buf.String(), want) { 2499 | t.Errorf("Glg.Warnf() = got %v want %v", buf.String(), want) 2500 | } 2501 | }) 2502 | } 2503 | } 2504 | 2505 | func TestGlg_WarnFunc(t *testing.T) { 2506 | tests := []struct { 2507 | name string 2508 | logMode MODE 2509 | f func() string 2510 | want string 2511 | }{ 2512 | { 2513 | name: "sample log", 2514 | logMode: WRITER, 2515 | f: func() string { 2516 | return dummy 2517 | }, 2518 | want: dummy, 2519 | }, 2520 | { 2521 | name: "sample log", 2522 | logMode: NONE, 2523 | f: func() string { 2524 | return dummy 2525 | }, 2526 | want: "", 2527 | }, 2528 | } 2529 | for _, tt := range tests { 2530 | t.Run(tt.name, func(t *testing.T) { 2531 | buf := new(bytes.Buffer) 2532 | g := New().SetMode(tt.logMode).SetWriter(buf) 2533 | err := g.WarnFunc(tt.f) 2534 | if err != nil { 2535 | t.Errorf("Glg.WarnFunc() unexpected error: %v", err) 2536 | } 2537 | if !strings.Contains(buf.String(), tt.want) { 2538 | t.Errorf("Glg.WarnFunc() = got %v want %v", buf.String(), tt.want) 2539 | } 2540 | }) 2541 | } 2542 | } 2543 | 2544 | func TestWarn(t *testing.T) { 2545 | tests := []struct { 2546 | name string 2547 | val []interface{} 2548 | }{ 2549 | { 2550 | name: "sample warn", 2551 | val: []interface{}{ 2552 | "sample warn", 2553 | }, 2554 | }, 2555 | } 2556 | for _, tt := range tests { 2557 | t.Run(tt.name, func(t *testing.T) { 2558 | buf := new(bytes.Buffer) 2559 | Get().SetMode(WRITER).SetWriter(buf) 2560 | err := Warn(tt.val...) 2561 | want := fmt.Sprintf("%v", tt.val...) 2562 | if err != nil { 2563 | t.Errorf("Warn() unexpected error: %v", err) 2564 | } 2565 | if !strings.Contains(buf.String(), want) { 2566 | t.Errorf("Warn() = got %v want %v", buf.String(), want) 2567 | } 2568 | }) 2569 | } 2570 | } 2571 | 2572 | func TestWarnf(t *testing.T) { 2573 | tests := []struct { 2574 | name string 2575 | format string 2576 | val []interface{} 2577 | }{ 2578 | { 2579 | name: "sample warnf", 2580 | format: "%d%s%f", 2581 | val: []interface{}{ 2582 | 2, 2583 | "aaa", 2584 | 3.6, 2585 | }, 2586 | }, 2587 | { 2588 | name: "sample warnf", 2589 | format: "%d%s%f", 2590 | val: []interface{}{ 2591 | 2, 2592 | "aaa", 2593 | 3.6, 2594 | }, 2595 | }, 2596 | } 2597 | for _, tt := range tests { 2598 | t.Run(tt.name, func(t *testing.T) { 2599 | buf := new(bytes.Buffer) 2600 | Get().SetMode(WRITER).SetWriter(buf) 2601 | err := Warnf(tt.format, tt.val...) 2602 | want := fmt.Sprintf(tt.format, tt.val...) 2603 | if err != nil { 2604 | t.Errorf("Warnf() unexpected error: %v", err) 2605 | } 2606 | if !strings.Contains(buf.String(), want) { 2607 | t.Errorf("Warnf() = got %v want %v", buf.String(), want) 2608 | } 2609 | }) 2610 | } 2611 | } 2612 | 2613 | func TestWarnFunc(t *testing.T) { 2614 | tests := []struct { 2615 | name string 2616 | logMode MODE 2617 | f func() string 2618 | want string 2619 | }{ 2620 | { 2621 | name: "sample log", 2622 | logMode: WRITER, 2623 | f: func() string { 2624 | return dummy 2625 | }, 2626 | want: dummy, 2627 | }, 2628 | { 2629 | name: "sample log", 2630 | logMode: NONE, 2631 | f: func() string { 2632 | return dummy 2633 | }, 2634 | want: "", 2635 | }, 2636 | } 2637 | for _, tt := range tests { 2638 | t.Run(tt.name, func(t *testing.T) { 2639 | buf := new(bytes.Buffer) 2640 | Get().SetMode(tt.logMode).SetWriter(buf) 2641 | err := WarnFunc(tt.f) 2642 | if err != nil { 2643 | t.Errorf("WarnFunc() unexpected error: %v", err) 2644 | } 2645 | if !strings.Contains(buf.String(), tt.want) { 2646 | t.Errorf("WarnFunc() = got %v want %v", buf.String(), tt.want) 2647 | } 2648 | }) 2649 | } 2650 | } 2651 | 2652 | func TestGlg_CustomLog(t *testing.T) { 2653 | tests := []struct { 2654 | name string 2655 | level string 2656 | val []interface{} 2657 | }{ 2658 | { 2659 | name: "sample custom", 2660 | level: "custom", 2661 | val: []interface{}{ 2662 | "sample custom", 2663 | }, 2664 | }, 2665 | } 2666 | for _, tt := range tests { 2667 | t.Run(tt.name, func(t *testing.T) { 2668 | buf := new(bytes.Buffer) 2669 | g := New() 2670 | g.SetMode(WRITER).AddStdLevel(tt.level, WRITER, false) 2671 | g.SetWriter(buf) 2672 | err := g.CustomLog(tt.level, tt.val...) 2673 | want := fmt.Sprintf("%v", tt.val...) 2674 | if err != nil { 2675 | t.Errorf("Glg.CustomLog() unexpected error: %v", err) 2676 | } 2677 | if !strings.Contains(buf.String(), want) { 2678 | t.Errorf("Glg.CustomLog() = got %v want %v", buf.String(), want) 2679 | } 2680 | }) 2681 | } 2682 | } 2683 | 2684 | func TestGlg_CustomLogf(t *testing.T) { 2685 | tests := []struct { 2686 | name string 2687 | format string 2688 | level string 2689 | val []interface{} 2690 | }{ 2691 | { 2692 | name: "sample customf", 2693 | level: "custom", 2694 | format: "%d%s%f", 2695 | val: []interface{}{ 2696 | 2, 2697 | "aaa", 2698 | 3.6, 2699 | }, 2700 | }, 2701 | { 2702 | name: "sample customf", 2703 | level: "custom", 2704 | format: "%d%s%f", 2705 | val: []interface{}{ 2706 | 2, 2707 | "aaa", 2708 | 3.6, 2709 | }, 2710 | }, 2711 | } 2712 | for _, tt := range tests { 2713 | t.Run(tt.name, func(t *testing.T) { 2714 | buf := new(bytes.Buffer) 2715 | g := New() 2716 | g.SetMode(WRITER).AddStdLevel(tt.level, WRITER, false) 2717 | g.SetWriter(buf) 2718 | err := g.CustomLogf(tt.level, tt.format, tt.val...) 2719 | want := fmt.Sprintf(tt.format, tt.val...) 2720 | if err != nil { 2721 | t.Errorf("Glg.CustomLogf() unexpected error: %v", err) 2722 | } 2723 | if !strings.Contains(buf.String(), want) { 2724 | t.Errorf("Glg.CustomLogf() = got %v want %v", buf.String(), want) 2725 | } 2726 | }) 2727 | } 2728 | } 2729 | 2730 | func TestGlg_CustomLogFunc(t *testing.T) { 2731 | tests := []struct { 2732 | name string 2733 | logMode MODE 2734 | level string 2735 | f func() string 2736 | want string 2737 | }{ 2738 | { 2739 | name: "sample log", 2740 | logMode: WRITER, 2741 | level: "custom", 2742 | f: func() string { 2743 | return dummy 2744 | }, 2745 | want: dummy, 2746 | }, 2747 | { 2748 | name: "sample log", 2749 | logMode: NONE, 2750 | level: "custom", 2751 | f: func() string { 2752 | return dummy 2753 | }, 2754 | want: "", 2755 | }, 2756 | } 2757 | for _, tt := range tests { 2758 | t.Run(tt.name, func(t *testing.T) { 2759 | buf := new(bytes.Buffer) 2760 | g := New() 2761 | g.SetMode(tt.logMode).AddStdLevel(tt.level, tt.logMode, false) 2762 | g.SetWriter(buf) 2763 | err := g.CustomLogFunc(tt.level, tt.f) 2764 | if err != nil { 2765 | t.Errorf("Glg.CustomLogFunc() unexpected error: %v", err) 2766 | } 2767 | if !strings.Contains(buf.String(), tt.want) { 2768 | t.Errorf("Glg.CustomLogFunc() = got %v want %v", buf.String(), tt.want) 2769 | } 2770 | }) 2771 | } 2772 | } 2773 | 2774 | func TestCustomLog(t *testing.T) { 2775 | tests := []struct { 2776 | name string 2777 | level string 2778 | val []interface{} 2779 | }{ 2780 | { 2781 | name: "sample custom", 2782 | level: "custom", 2783 | val: []interface{}{ 2784 | "sample custom", 2785 | }, 2786 | }, 2787 | } 2788 | for _, tt := range tests { 2789 | t.Run(tt.name, func(t *testing.T) { 2790 | buf := new(bytes.Buffer) 2791 | Get().SetMode(WRITER).AddStdLevel(tt.level, WRITER, false) 2792 | Get().SetWriter(buf) 2793 | err := CustomLog(tt.level, tt.val...) 2794 | want := fmt.Sprintf("%v", tt.val...) 2795 | if err != nil { 2796 | t.Errorf("CustomLog() unexpected error: %v", err) 2797 | } 2798 | if !strings.Contains(buf.String(), want) { 2799 | t.Errorf("CustomLog() = got %v want %v", buf.String(), want) 2800 | } 2801 | }) 2802 | } 2803 | } 2804 | 2805 | func TestCustomLogf(t *testing.T) { 2806 | tests := []struct { 2807 | name string 2808 | format string 2809 | level string 2810 | val []interface{} 2811 | }{ 2812 | { 2813 | name: "sample customf", 2814 | level: "custom", 2815 | format: "%d%s%f", 2816 | val: []interface{}{ 2817 | 2, 2818 | "aaa", 2819 | 3.6, 2820 | }, 2821 | }, 2822 | { 2823 | name: "sample customf", 2824 | level: "custom", 2825 | format: "%d%s%f", 2826 | val: []interface{}{ 2827 | 2, 2828 | "aaa", 2829 | 3.6, 2830 | }, 2831 | }, 2832 | } 2833 | for _, tt := range tests { 2834 | t.Run(tt.name, func(t *testing.T) { 2835 | buf := new(bytes.Buffer) 2836 | Get().SetMode(WRITER).AddStdLevel(tt.level, WRITER, false) 2837 | Get().SetWriter(buf) 2838 | err := CustomLogf(tt.level, tt.format, tt.val...) 2839 | want := fmt.Sprintf(tt.format, tt.val...) 2840 | if err != nil { 2841 | t.Errorf("CustomLogf() unexpected error: %v", err) 2842 | } 2843 | if !strings.Contains(buf.String(), want) { 2844 | t.Errorf("CustomLogf() = got %v want %v", buf.String(), want) 2845 | } 2846 | }) 2847 | } 2848 | } 2849 | 2850 | func TestCustomLogFunc(t *testing.T) { 2851 | tests := []struct { 2852 | name string 2853 | logMode MODE 2854 | level string 2855 | f func() string 2856 | want string 2857 | }{ 2858 | { 2859 | name: "sample log", 2860 | logMode: WRITER, 2861 | level: "custom", 2862 | f: func() string { 2863 | return dummy 2864 | }, 2865 | want: dummy, 2866 | }, 2867 | { 2868 | name: "sample log", 2869 | logMode: NONE, 2870 | level: "custom", 2871 | f: func() string { 2872 | return dummy 2873 | }, 2874 | want: "", 2875 | }, 2876 | } 2877 | for _, tt := range tests { 2878 | t.Run(tt.name, func(t *testing.T) { 2879 | buf := new(bytes.Buffer) 2880 | Get().SetMode(tt.logMode).AddStdLevel(tt.level, tt.logMode, false) 2881 | Get().SetWriter(buf) 2882 | err := CustomLogFunc(tt.level, tt.f) 2883 | if err != nil { 2884 | t.Errorf("CustomLogFunc() unexpected error: %v", err) 2885 | } 2886 | if !strings.Contains(buf.String(), tt.want) { 2887 | t.Errorf("CustomLogFunc() = got %v want %v", buf.String(), tt.want) 2888 | } 2889 | }) 2890 | } 2891 | } 2892 | 2893 | func TestGlg_Trace(t *testing.T) { 2894 | tests := []struct { 2895 | name string 2896 | val []interface{} 2897 | }{ 2898 | { 2899 | name: "sample trace", 2900 | val: []interface{}{ 2901 | "sample trace", 2902 | }, 2903 | }, 2904 | } 2905 | for _, tt := range tests { 2906 | t.Run(tt.name, func(t *testing.T) { 2907 | buf := new(bytes.Buffer) 2908 | g := New().SetMode(WRITER).SetWriter(buf) 2909 | err := g.Trace(tt.val...) 2910 | want := fmt.Sprintf("%v", tt.val...) 2911 | if err != nil { 2912 | t.Errorf("Glg.Trace() unexpected error: %v", err) 2913 | } 2914 | if !strings.Contains(buf.String(), want) { 2915 | t.Errorf("Glg.Trace() = got %v want %v", buf.String(), want) 2916 | } 2917 | }) 2918 | } 2919 | } 2920 | 2921 | func TestGlg_Tracef(t *testing.T) { 2922 | tests := []struct { 2923 | name string 2924 | format string 2925 | val []interface{} 2926 | }{ 2927 | { 2928 | name: "sample tracef", 2929 | format: "%d%s%f", 2930 | val: []interface{}{ 2931 | 2, 2932 | "aaa", 2933 | 3.6, 2934 | }, 2935 | }, 2936 | { 2937 | name: "sample tracef", 2938 | format: "%d%s%f", 2939 | val: []interface{}{ 2940 | 2, 2941 | "aaa", 2942 | 3.6, 2943 | }, 2944 | }, 2945 | } 2946 | for _, tt := range tests { 2947 | t.Run(tt.name, func(t *testing.T) { 2948 | buf := new(bytes.Buffer) 2949 | g := New().SetMode(WRITER).SetWriter(buf) 2950 | err := g.Tracef(tt.format, tt.val...) 2951 | want := fmt.Sprintf(tt.format, tt.val...) 2952 | if err != nil { 2953 | t.Errorf("Glg.Tracef() unexpected error: %v", err) 2954 | } 2955 | if !strings.Contains(buf.String(), want) { 2956 | t.Errorf("Glg.Tracef() = got %v want %v", buf.String(), want) 2957 | } 2958 | }) 2959 | } 2960 | } 2961 | 2962 | func TestGlg_TraceFunc(t *testing.T) { 2963 | tests := []struct { 2964 | name string 2965 | logMode MODE 2966 | f func() string 2967 | want string 2968 | }{ 2969 | { 2970 | name: "sample log", 2971 | logMode: WRITER, 2972 | f: func() string { 2973 | return dummy 2974 | }, 2975 | want: dummy, 2976 | }, 2977 | { 2978 | name: "sample log", 2979 | logMode: NONE, 2980 | f: func() string { 2981 | return dummy 2982 | }, 2983 | want: "", 2984 | }, 2985 | } 2986 | for _, tt := range tests { 2987 | t.Run(tt.name, func(t *testing.T) { 2988 | buf := new(bytes.Buffer) 2989 | g := New().SetMode(tt.logMode).SetWriter(buf) 2990 | err := g.TraceFunc(tt.f) 2991 | if err != nil { 2992 | t.Errorf("Glg.TraceFunc() unexpected error: %v", err) 2993 | } 2994 | if !strings.Contains(buf.String(), tt.want) { 2995 | t.Errorf("Glg.TraceFunc() = got %v want %v", buf.String(), tt.want) 2996 | } 2997 | }) 2998 | } 2999 | } 3000 | 3001 | func TestTrace(t *testing.T) { 3002 | tests := []struct { 3003 | name string 3004 | val []interface{} 3005 | }{ 3006 | { 3007 | name: "sample trace", 3008 | val: []interface{}{ 3009 | "sample trace", 3010 | }, 3011 | }, 3012 | } 3013 | for _, tt := range tests { 3014 | t.Run(tt.name, func(t *testing.T) { 3015 | buf := new(bytes.Buffer) 3016 | Get().SetMode(WRITER).SetWriter(buf) 3017 | err := Trace(tt.val...) 3018 | want := fmt.Sprintf("%v", tt.val...) 3019 | if err != nil { 3020 | t.Errorf("Trace() unexpected error: %v", err) 3021 | } 3022 | if !strings.Contains(buf.String(), want) { 3023 | t.Errorf("Trace() = got %v want %v", buf.String(), want) 3024 | } 3025 | }) 3026 | } 3027 | } 3028 | 3029 | func TestTracef(t *testing.T) { 3030 | tests := []struct { 3031 | name string 3032 | format string 3033 | val []interface{} 3034 | }{ 3035 | { 3036 | name: "sample tracef", 3037 | format: "%d%s%f", 3038 | val: []interface{}{ 3039 | 2, 3040 | "aaa", 3041 | 3.6, 3042 | }, 3043 | }, 3044 | { 3045 | name: "sample tracef", 3046 | format: "%d%s%f", 3047 | val: []interface{}{ 3048 | 2, 3049 | "aaa", 3050 | 3.6, 3051 | }, 3052 | }, 3053 | } 3054 | for _, tt := range tests { 3055 | t.Run(tt.name, func(t *testing.T) { 3056 | buf := new(bytes.Buffer) 3057 | Get().SetMode(WRITER).SetWriter(buf) 3058 | err := Tracef(tt.format, tt.val...) 3059 | want := fmt.Sprintf(tt.format, tt.val...) 3060 | if err != nil { 3061 | t.Errorf("Tracef() unexpected error: %v", err) 3062 | } 3063 | if !strings.Contains(buf.String(), want) { 3064 | t.Errorf("Tracef() = got %v want %v", buf.String(), want) 3065 | } 3066 | }) 3067 | } 3068 | } 3069 | 3070 | func TestTraceFunc(t *testing.T) { 3071 | tests := []struct { 3072 | name string 3073 | logMode MODE 3074 | f func() string 3075 | want string 3076 | }{ 3077 | { 3078 | name: "sample log", 3079 | logMode: WRITER, 3080 | f: func() string { 3081 | return dummy 3082 | }, 3083 | want: dummy, 3084 | }, 3085 | { 3086 | name: "sample log", 3087 | logMode: NONE, 3088 | f: func() string { 3089 | return dummy 3090 | }, 3091 | want: "", 3092 | }, 3093 | } 3094 | for _, tt := range tests { 3095 | t.Run(tt.name, func(t *testing.T) { 3096 | buf := new(bytes.Buffer) 3097 | Get().SetMode(tt.logMode).SetWriter(buf) 3098 | err := TraceFunc(tt.f) 3099 | if err != nil { 3100 | t.Errorf("TraceFunc() unexpected error: %v", err) 3101 | } 3102 | if !strings.Contains(buf.String(), tt.want) { 3103 | t.Errorf("TraceFunc() = got %v want %v", buf.String(), tt.want) 3104 | } 3105 | }) 3106 | } 3107 | } 3108 | 3109 | func TestGlg_Print(t *testing.T) { 3110 | tests := []struct { 3111 | name string 3112 | val []interface{} 3113 | }{ 3114 | { 3115 | name: "sample print", 3116 | val: []interface{}{ 3117 | "sample print", 3118 | }, 3119 | }, 3120 | } 3121 | for _, tt := range tests { 3122 | t.Run(tt.name, func(t *testing.T) { 3123 | buf := new(bytes.Buffer) 3124 | g := New().SetMode(WRITER).SetWriter(buf) 3125 | err := g.Print(tt.val...) 3126 | want := fmt.Sprintf("%v", tt.val...) 3127 | if err != nil { 3128 | t.Errorf("Glg.Print() unexpected error: %v", err) 3129 | } 3130 | if !strings.Contains(buf.String(), want) { 3131 | t.Errorf("Glg.Print() = got %v want %v", buf.String(), want) 3132 | } 3133 | }) 3134 | } 3135 | } 3136 | 3137 | func TestGlg_Println(t *testing.T) { 3138 | tests := []struct { 3139 | name string 3140 | val []interface{} 3141 | }{ 3142 | { 3143 | name: "sample println", 3144 | val: []interface{}{ 3145 | "sample println", 3146 | }, 3147 | }, 3148 | } 3149 | for _, tt := range tests { 3150 | t.Run(tt.name, func(t *testing.T) { 3151 | buf := new(bytes.Buffer) 3152 | g := New().SetMode(WRITER).SetWriter(buf) 3153 | err := g.Println(tt.val...) 3154 | want := fmt.Sprintf("%v", tt.val...) 3155 | if err != nil { 3156 | t.Errorf("Glg.Println() unexpected error: %v", err) 3157 | } 3158 | if !strings.Contains(buf.String(), want) { 3159 | t.Errorf("Glg.Println() = got %v want %v", buf.String(), want) 3160 | } 3161 | }) 3162 | } 3163 | } 3164 | 3165 | func TestGlg_Printf(t *testing.T) { 3166 | tests := []struct { 3167 | name string 3168 | format string 3169 | val []interface{} 3170 | }{ 3171 | { 3172 | name: "sample printf", 3173 | format: "%d%s%f", 3174 | val: []interface{}{ 3175 | 2, 3176 | "aaa", 3177 | 3.6, 3178 | }, 3179 | }, 3180 | { 3181 | name: "sample printf", 3182 | format: "%d%s%f", 3183 | val: []interface{}{ 3184 | 2, 3185 | "aaa", 3186 | 3.6, 3187 | }, 3188 | }, 3189 | } 3190 | for _, tt := range tests { 3191 | t.Run(tt.name, func(t *testing.T) { 3192 | buf := new(bytes.Buffer) 3193 | g := New().SetMode(WRITER).SetWriter(buf) 3194 | err := g.Printf(tt.format, tt.val...) 3195 | want := fmt.Sprintf(tt.format, tt.val...) 3196 | if err != nil { 3197 | t.Errorf("Glg.Printf() unexpected error: %v", err) 3198 | } 3199 | if !strings.Contains(buf.String(), want) { 3200 | t.Errorf("Glg.Printf() = got %v want %v", buf.String(), want) 3201 | } 3202 | }) 3203 | } 3204 | } 3205 | 3206 | func TestGlg_PrintFunc(t *testing.T) { 3207 | tests := []struct { 3208 | name string 3209 | logMode MODE 3210 | f func() string 3211 | want string 3212 | }{ 3213 | { 3214 | name: "sample log", 3215 | logMode: WRITER, 3216 | f: func() string { 3217 | return dummy 3218 | }, 3219 | want: dummy, 3220 | }, 3221 | { 3222 | name: "sample log", 3223 | logMode: NONE, 3224 | f: func() string { 3225 | return dummy 3226 | }, 3227 | want: "", 3228 | }, 3229 | } 3230 | for _, tt := range tests { 3231 | t.Run(tt.name, func(t *testing.T) { 3232 | buf := new(bytes.Buffer) 3233 | g := New().SetMode(tt.logMode).SetWriter(buf) 3234 | err := g.PrintFunc(tt.f) 3235 | if err != nil { 3236 | t.Errorf("Glg.PrintFunc() unexpected error: %v", err) 3237 | } 3238 | if !strings.Contains(buf.String(), tt.want) { 3239 | t.Errorf("Glg.PrintFunc() = got %v want %v", buf.String(), tt.want) 3240 | } 3241 | }) 3242 | } 3243 | } 3244 | 3245 | func TestPrint(t *testing.T) { 3246 | tests := []struct { 3247 | name string 3248 | val []interface{} 3249 | }{ 3250 | { 3251 | name: "sample print", 3252 | val: []interface{}{ 3253 | "sample print", 3254 | }, 3255 | }, 3256 | } 3257 | for _, tt := range tests { 3258 | t.Run(tt.name, func(t *testing.T) { 3259 | buf := new(bytes.Buffer) 3260 | Get().SetMode(WRITER).SetWriter(buf) 3261 | err := Print(tt.val...) 3262 | want := fmt.Sprintf("%v", tt.val...) 3263 | if err != nil { 3264 | t.Errorf("Print() unexpected error: %v", err) 3265 | } 3266 | if !strings.Contains(buf.String(), want) { 3267 | t.Errorf("Print() = got %v want %v", buf.String(), want) 3268 | } 3269 | }) 3270 | } 3271 | } 3272 | 3273 | func TestPrintln(t *testing.T) { 3274 | tests := []struct { 3275 | name string 3276 | val []interface{} 3277 | }{ 3278 | { 3279 | name: "sample println", 3280 | val: []interface{}{ 3281 | "sample println", 3282 | }, 3283 | }, 3284 | } 3285 | for _, tt := range tests { 3286 | t.Run(tt.name, func(t *testing.T) { 3287 | buf := new(bytes.Buffer) 3288 | Get().SetMode(WRITER).SetWriter(buf) 3289 | err := Println(tt.val...) 3290 | want := fmt.Sprintf("%v", tt.val...) 3291 | if err != nil { 3292 | t.Errorf("Println() unexpected error: %v", err) 3293 | } 3294 | if !strings.Contains(buf.String(), want) { 3295 | t.Errorf("Println() = got %v want %v", buf.String(), want) 3296 | } 3297 | }) 3298 | } 3299 | } 3300 | 3301 | func TestPrintf(t *testing.T) { 3302 | tests := []struct { 3303 | name string 3304 | format string 3305 | val []interface{} 3306 | }{ 3307 | { 3308 | name: "sample printf", 3309 | format: "%d%s%f", 3310 | val: []interface{}{ 3311 | 2, 3312 | "aaa", 3313 | 3.6, 3314 | }, 3315 | }, 3316 | { 3317 | name: "sample printf", 3318 | format: "%d%s%f", 3319 | val: []interface{}{ 3320 | 2, 3321 | "aaa", 3322 | 3.6, 3323 | }, 3324 | }, 3325 | } 3326 | for _, tt := range tests { 3327 | t.Run(tt.name, func(t *testing.T) { 3328 | buf := new(bytes.Buffer) 3329 | Get().SetMode(WRITER).SetWriter(buf) 3330 | err := Printf(tt.format, tt.val...) 3331 | want := fmt.Sprintf(tt.format, tt.val...) 3332 | if err != nil { 3333 | t.Errorf("Printf() unexpected error: %v", err) 3334 | } 3335 | if !strings.Contains(buf.String(), want) { 3336 | t.Errorf("Printf() = got %v want %v", buf.String(), want) 3337 | } 3338 | }) 3339 | } 3340 | } 3341 | 3342 | func TestPrintFunc(t *testing.T) { 3343 | tests := []struct { 3344 | name string 3345 | logMode MODE 3346 | f func() string 3347 | want string 3348 | }{ 3349 | { 3350 | name: "sample log", 3351 | logMode: WRITER, 3352 | f: func() string { 3353 | return dummy 3354 | }, 3355 | want: dummy, 3356 | }, 3357 | { 3358 | name: "sample log", 3359 | logMode: NONE, 3360 | f: func() string { 3361 | return dummy 3362 | }, 3363 | want: "", 3364 | }, 3365 | } 3366 | for _, tt := range tests { 3367 | t.Run(tt.name, func(t *testing.T) { 3368 | buf := new(bytes.Buffer) 3369 | Get().SetMode(tt.logMode).SetWriter(buf) 3370 | err := PrintFunc(tt.f) 3371 | if err != nil { 3372 | t.Errorf("PrintFunc() unexpected error: %v", err) 3373 | } 3374 | if !strings.Contains(buf.String(), tt.want) { 3375 | t.Errorf("PrintFunc() = got %v want %v", buf.String(), tt.want) 3376 | } 3377 | }) 3378 | } 3379 | } 3380 | 3381 | func TestGlg_Error(t *testing.T) { 3382 | tests := []struct { 3383 | name string 3384 | val []interface{} 3385 | }{ 3386 | { 3387 | name: "sample error", 3388 | val: []interface{}{ 3389 | "sample error", 3390 | }, 3391 | }, 3392 | } 3393 | for _, tt := range tests { 3394 | t.Run(tt.name, func(t *testing.T) { 3395 | buf := new(bytes.Buffer) 3396 | g := New().SetMode(WRITER).SetWriter(buf) 3397 | err := g.Error(tt.val...) 3398 | want := fmt.Sprintf("%v", tt.val...) 3399 | if err != nil { 3400 | t.Errorf("Glg.Error() unexpected error: %v", err) 3401 | } 3402 | if !strings.Contains(buf.String(), want) { 3403 | t.Errorf("Glg.Error() = got %v want %v", buf.String(), want) 3404 | } 3405 | }) 3406 | } 3407 | } 3408 | 3409 | func TestGlg_Errorf(t *testing.T) { 3410 | tests := []struct { 3411 | name string 3412 | format string 3413 | val []interface{} 3414 | }{ 3415 | { 3416 | name: "sample errorf", 3417 | format: "%d%s%f", 3418 | val: []interface{}{ 3419 | 2, 3420 | "aaa", 3421 | 3.6, 3422 | }, 3423 | }, 3424 | { 3425 | name: "sample errorf", 3426 | format: "%d%s%f", 3427 | val: []interface{}{ 3428 | 2, 3429 | "aaa", 3430 | 3.6, 3431 | }, 3432 | }, 3433 | } 3434 | for _, tt := range tests { 3435 | t.Run(tt.name, func(t *testing.T) { 3436 | buf := new(bytes.Buffer) 3437 | g := New().SetMode(WRITER).SetWriter(buf) 3438 | err := g.Errorf(tt.format, tt.val...) 3439 | want := fmt.Sprintf(tt.format, tt.val...) 3440 | if err != nil { 3441 | t.Errorf("Glg.Errorf() unexpected error: %v", err) 3442 | } 3443 | if !strings.Contains(buf.String(), want) { 3444 | t.Errorf("Glg.Errorf() = got %v want %v", buf.String(), want) 3445 | } 3446 | }) 3447 | } 3448 | } 3449 | 3450 | func TestGlg_ErrorFunc(t *testing.T) { 3451 | tests := []struct { 3452 | name string 3453 | logMode MODE 3454 | f func() string 3455 | want string 3456 | }{ 3457 | { 3458 | name: "sample log", 3459 | logMode: WRITER, 3460 | f: func() string { 3461 | return dummy 3462 | }, 3463 | want: dummy, 3464 | }, 3465 | { 3466 | name: "sample log", 3467 | logMode: NONE, 3468 | f: func() string { 3469 | return dummy 3470 | }, 3471 | want: "", 3472 | }, 3473 | } 3474 | for _, tt := range tests { 3475 | t.Run(tt.name, func(t *testing.T) { 3476 | buf := new(bytes.Buffer) 3477 | g := New().SetMode(tt.logMode).SetWriter(buf) 3478 | err := g.ErrorFunc(tt.f) 3479 | if err != nil { 3480 | t.Errorf("Glg.ErrorFunc() unexpected error: %v", err) 3481 | } 3482 | if !strings.Contains(buf.String(), tt.want) { 3483 | t.Errorf("Glg.ErrorFunc() = got %v want %v", buf.String(), tt.want) 3484 | } 3485 | }) 3486 | } 3487 | } 3488 | 3489 | func TestError(t *testing.T) { 3490 | tests := []struct { 3491 | name string 3492 | val []interface{} 3493 | }{ 3494 | { 3495 | name: "sample error", 3496 | val: []interface{}{ 3497 | "sample error", 3498 | }, 3499 | }, 3500 | } 3501 | for _, tt := range tests { 3502 | t.Run(tt.name, func(t *testing.T) { 3503 | buf := new(bytes.Buffer) 3504 | Get().SetMode(WRITER).SetWriter(buf) 3505 | err := Error(tt.val...) 3506 | want := fmt.Sprintf("%v", tt.val...) 3507 | if err != nil { 3508 | t.Errorf("Error() unexpected error: %v", err) 3509 | } 3510 | if !strings.Contains(buf.String(), want) { 3511 | t.Errorf("Error() = got %v want %v", buf.String(), want) 3512 | } 3513 | }) 3514 | } 3515 | } 3516 | 3517 | func TestErrorf(t *testing.T) { 3518 | tests := []struct { 3519 | name string 3520 | format string 3521 | val []interface{} 3522 | }{ 3523 | { 3524 | name: "sample errorf", 3525 | format: "%d%s%f", 3526 | val: []interface{}{ 3527 | 2, 3528 | "aaa", 3529 | 3.6, 3530 | }, 3531 | }, 3532 | { 3533 | name: "sample errorf", 3534 | format: "%d%s%f", 3535 | val: []interface{}{ 3536 | 2, 3537 | "aaa", 3538 | 3.6, 3539 | }, 3540 | }, 3541 | } 3542 | for _, tt := range tests { 3543 | t.Run(tt.name, func(t *testing.T) { 3544 | buf := new(bytes.Buffer) 3545 | Get().SetMode(WRITER).SetWriter(buf) 3546 | err := Errorf(tt.format, tt.val...) 3547 | want := fmt.Sprintf(tt.format, tt.val...) 3548 | if err != nil { 3549 | t.Errorf("Errorf() unexpected error: %v", err) 3550 | } 3551 | if !strings.Contains(buf.String(), want) { 3552 | t.Errorf("Errorf() = got %v want %v", buf.String(), want) 3553 | } 3554 | }) 3555 | } 3556 | } 3557 | 3558 | func TestErrorFunc(t *testing.T) { 3559 | tests := []struct { 3560 | name string 3561 | logMode MODE 3562 | f func() string 3563 | want string 3564 | }{ 3565 | { 3566 | name: "sample log", 3567 | logMode: WRITER, 3568 | f: func() string { 3569 | return dummy 3570 | }, 3571 | want: dummy, 3572 | }, 3573 | { 3574 | name: "sample log", 3575 | logMode: NONE, 3576 | f: func() string { 3577 | return dummy 3578 | }, 3579 | want: "", 3580 | }, 3581 | } 3582 | for _, tt := range tests { 3583 | t.Run(tt.name, func(t *testing.T) { 3584 | buf := new(bytes.Buffer) 3585 | Get().SetMode(tt.logMode).SetWriter(buf) 3586 | err := ErrorFunc(tt.f) 3587 | if err != nil { 3588 | t.Errorf("ErrorFunc() unexpected error: %v", err) 3589 | } 3590 | if !strings.Contains(buf.String(), tt.want) { 3591 | t.Errorf("ErrorFunc() = got %v want %v", buf.String(), tt.want) 3592 | } 3593 | }) 3594 | } 3595 | } 3596 | 3597 | func TestGlg_Fail(t *testing.T) { 3598 | tests := []struct { 3599 | name string 3600 | val []interface{} 3601 | }{ 3602 | { 3603 | name: "sample fail", 3604 | val: []interface{}{ 3605 | "sample fail", 3606 | }, 3607 | }, 3608 | } 3609 | for _, tt := range tests { 3610 | t.Run(tt.name, func(t *testing.T) { 3611 | buf := new(bytes.Buffer) 3612 | g := New().SetMode(WRITER).SetWriter(buf) 3613 | err := g.Fail(tt.val...) 3614 | want := fmt.Sprintf("%v", tt.val...) 3615 | if err != nil { 3616 | t.Errorf("Glg.Fail() unexpected error: %v", err) 3617 | } 3618 | if !strings.Contains(buf.String(), want) { 3619 | t.Errorf("Glg.Fail() = got %v want %v", buf.String(), want) 3620 | } 3621 | }) 3622 | } 3623 | } 3624 | 3625 | func TestGlg_Failf(t *testing.T) { 3626 | tests := []struct { 3627 | name string 3628 | format string 3629 | val []interface{} 3630 | }{ 3631 | { 3632 | name: "sample failf", 3633 | format: "%d%s%f", 3634 | val: []interface{}{ 3635 | 2, 3636 | "aaa", 3637 | 3.6, 3638 | }, 3639 | }, 3640 | { 3641 | name: "sample failf", 3642 | format: "%d%s%f", 3643 | val: []interface{}{ 3644 | 2, 3645 | "aaa", 3646 | 3.6, 3647 | }, 3648 | }, 3649 | } 3650 | for _, tt := range tests { 3651 | t.Run(tt.name, func(t *testing.T) { 3652 | buf := new(bytes.Buffer) 3653 | g := New().SetMode(WRITER).SetWriter(buf) 3654 | err := g.Failf(tt.format, tt.val...) 3655 | want := fmt.Sprintf(tt.format, tt.val...) 3656 | if err != nil { 3657 | t.Errorf("Glg.Failf() unexpected error: %v", err) 3658 | } 3659 | if !strings.Contains(buf.String(), want) { 3660 | t.Errorf("Glg.Failf() = got %v want %v", buf.String(), want) 3661 | } 3662 | }) 3663 | } 3664 | } 3665 | 3666 | func TestGlg_FailFunc(t *testing.T) { 3667 | tests := []struct { 3668 | name string 3669 | logMode MODE 3670 | f func() string 3671 | want string 3672 | }{ 3673 | { 3674 | name: "sample log", 3675 | logMode: WRITER, 3676 | f: func() string { 3677 | return dummy 3678 | }, 3679 | want: dummy, 3680 | }, 3681 | { 3682 | name: "sample log", 3683 | logMode: NONE, 3684 | f: func() string { 3685 | return dummy 3686 | }, 3687 | want: "", 3688 | }, 3689 | } 3690 | for _, tt := range tests { 3691 | t.Run(tt.name, func(t *testing.T) { 3692 | buf := new(bytes.Buffer) 3693 | g := New().SetMode(tt.logMode).SetWriter(buf) 3694 | err := g.FailFunc(tt.f) 3695 | if err != nil { 3696 | t.Errorf("Glg.FailFunc() unexpected error: %v", err) 3697 | } 3698 | if !strings.Contains(buf.String(), tt.want) { 3699 | t.Errorf("Glg.FailFunc() = got %v want %v", buf.String(), tt.want) 3700 | } 3701 | }) 3702 | } 3703 | } 3704 | 3705 | func TestFail(t *testing.T) { 3706 | tests := []struct { 3707 | name string 3708 | val []interface{} 3709 | }{ 3710 | { 3711 | name: "sample fail", 3712 | val: []interface{}{ 3713 | "sample fail", 3714 | }, 3715 | }, 3716 | } 3717 | for _, tt := range tests { 3718 | t.Run(tt.name, func(t *testing.T) { 3719 | buf := new(bytes.Buffer) 3720 | Get().SetMode(WRITER).SetWriter(buf) 3721 | err := Fail(tt.val...) 3722 | want := fmt.Sprintf("%v", tt.val...) 3723 | if err != nil { 3724 | t.Errorf("Fail() unexpected error: %v", err) 3725 | } 3726 | if !strings.Contains(buf.String(), want) { 3727 | t.Errorf("Fail() = got %v want %v", buf.String(), want) 3728 | } 3729 | }) 3730 | } 3731 | } 3732 | 3733 | func TestFailf(t *testing.T) { 3734 | tests := []struct { 3735 | name string 3736 | format string 3737 | val []interface{} 3738 | }{ 3739 | { 3740 | name: "sample failf", 3741 | format: "%d%s%f", 3742 | val: []interface{}{ 3743 | 2, 3744 | "aaa", 3745 | 3.6, 3746 | }, 3747 | }, 3748 | { 3749 | name: "sample failf", 3750 | format: "%d%s%f", 3751 | val: []interface{}{ 3752 | 2, 3753 | "aaa", 3754 | 3.6, 3755 | }, 3756 | }, 3757 | } 3758 | for _, tt := range tests { 3759 | t.Run(tt.name, func(t *testing.T) { 3760 | buf := new(bytes.Buffer) 3761 | Get().SetMode(WRITER).SetWriter(buf) 3762 | err := Failf(tt.format, tt.val...) 3763 | want := fmt.Sprintf(tt.format, tt.val...) 3764 | if err != nil { 3765 | t.Errorf("Failf() unexpected error: %v", err) 3766 | } 3767 | if !strings.Contains(buf.String(), want) { 3768 | t.Errorf("Failf() = got %v want %v", buf.String(), want) 3769 | } 3770 | }) 3771 | } 3772 | } 3773 | 3774 | func TestFailFunc(t *testing.T) { 3775 | tests := []struct { 3776 | name string 3777 | logMode MODE 3778 | f func() string 3779 | want string 3780 | }{ 3781 | { 3782 | name: "sample log", 3783 | logMode: WRITER, 3784 | f: func() string { 3785 | return dummy 3786 | }, 3787 | want: dummy, 3788 | }, 3789 | { 3790 | name: "sample log", 3791 | logMode: NONE, 3792 | f: func() string { 3793 | return dummy 3794 | }, 3795 | want: "", 3796 | }, 3797 | } 3798 | for _, tt := range tests { 3799 | t.Run(tt.name, func(t *testing.T) { 3800 | buf := new(bytes.Buffer) 3801 | Get().SetMode(tt.logMode).SetWriter(buf) 3802 | err := FailFunc(tt.f) 3803 | if err != nil { 3804 | t.Errorf("FailFunc() unexpected error: %v", err) 3805 | } 3806 | if !strings.Contains(buf.String(), tt.want) { 3807 | t.Errorf("FailFunc() = got %v want %v", buf.String(), tt.want) 3808 | } 3809 | }) 3810 | } 3811 | } 3812 | 3813 | func TestGlg_Fatal(t *testing.T) { 3814 | tests := []struct { 3815 | name string 3816 | val []interface{} 3817 | }{ 3818 | { 3819 | name: "sample fatal", 3820 | val: []interface{}{ 3821 | "aaa", 3822 | }, 3823 | }, 3824 | { 3825 | name: "sample fatal", 3826 | val: []interface{}{ 3827 | "aaa", 3828 | }, 3829 | }, 3830 | } 3831 | for _, tt := range tests { 3832 | t.Run(tt.name, func(t *testing.T) { 3833 | buf := new(bytes.Buffer) 3834 | g := New().SetMode(WRITER).SetWriter(buf) 3835 | testExit(0, func() { 3836 | g.Fatal(tt.val...) 3837 | }) 3838 | want := fmt.Sprintf("%v", tt.val...) 3839 | if !strings.Contains(buf.String(), want) { 3840 | t.Errorf("Glg.Fatal() = got %v want %v", buf.String(), want) 3841 | } 3842 | }) 3843 | } 3844 | } 3845 | 3846 | func TestGlg_Fatalln(t *testing.T) { 3847 | tests := []struct { 3848 | name string 3849 | val []interface{} 3850 | }{ 3851 | { 3852 | name: "sample fatalln", 3853 | val: []interface{}{ 3854 | "aaa", 3855 | }, 3856 | }, 3857 | { 3858 | name: "sample fatalln", 3859 | val: []interface{}{ 3860 | "aaa", 3861 | }, 3862 | }, 3863 | } 3864 | for _, tt := range tests { 3865 | t.Run(tt.name, func(t *testing.T) { 3866 | buf := new(bytes.Buffer) 3867 | g := New().SetMode(WRITER).SetWriter(buf) 3868 | testExit(0, func() { 3869 | g.Fatalln(tt.val...) 3870 | }) 3871 | want := fmt.Sprintf("%v", tt.val...) 3872 | if !strings.Contains(buf.String(), want) { 3873 | t.Errorf("Glg.Fatalln() = got %v want %v", buf.String(), want) 3874 | } 3875 | }) 3876 | } 3877 | } 3878 | 3879 | func TestGlg_Fatalf(t *testing.T) { 3880 | tests := []struct { 3881 | name string 3882 | format string 3883 | val []interface{} 3884 | }{ 3885 | { 3886 | name: "sample fatalf", 3887 | format: "%d%s%f", 3888 | val: []interface{}{ 3889 | 2, 3890 | "aaa", 3891 | 3.6, 3892 | }, 3893 | }, 3894 | { 3895 | name: "sample fatalf", 3896 | format: "%d%s%f", 3897 | val: []interface{}{ 3898 | 2, 3899 | "aaa", 3900 | 3.6, 3901 | }, 3902 | }, 3903 | } 3904 | for _, tt := range tests { 3905 | t.Run(tt.name, func(t *testing.T) { 3906 | buf := new(bytes.Buffer) 3907 | g := New().SetMode(WRITER).SetWriter(buf) 3908 | testExit(0, func() { 3909 | g.Fatalf(tt.format, tt.val...) 3910 | }) 3911 | want := fmt.Sprintf(tt.format, tt.val...) 3912 | if !strings.Contains(buf.String(), want) { 3913 | t.Errorf("Glg.Fatalf() = got %v want %v", buf.String(), want) 3914 | } 3915 | }) 3916 | } 3917 | } 3918 | 3919 | func TestFatal(t *testing.T) { 3920 | tests := []struct { 3921 | name string 3922 | val []interface{} 3923 | }{ 3924 | { 3925 | name: "sample fatal", 3926 | val: []interface{}{ 3927 | "aaa", 3928 | }, 3929 | }, 3930 | { 3931 | name: "sample fatal", 3932 | val: []interface{}{ 3933 | "aaa", 3934 | }, 3935 | }, 3936 | } 3937 | for _, tt := range tests { 3938 | t.Run(tt.name, func(t *testing.T) { 3939 | buf := new(bytes.Buffer) 3940 | Get().SetMode(WRITER).SetWriter(buf) 3941 | testExit(0, func() { 3942 | Fatal(tt.val...) 3943 | }) 3944 | want := fmt.Sprintf("%v", tt.val...) 3945 | if !strings.Contains(buf.String(), want) { 3946 | t.Errorf("Fatal() = got %v want %v", buf.String(), want) 3947 | } 3948 | }) 3949 | } 3950 | } 3951 | 3952 | func TestFatalf(t *testing.T) { 3953 | tests := []struct { 3954 | name string 3955 | format string 3956 | val []interface{} 3957 | }{ 3958 | { 3959 | name: "sample fatalf", 3960 | format: "%d%s%f", 3961 | val: []interface{}{ 3962 | 2, 3963 | "aaa", 3964 | 3.6, 3965 | }, 3966 | }, 3967 | { 3968 | name: "sample fatalf", 3969 | format: "%d%s%f", 3970 | val: []interface{}{ 3971 | 2, 3972 | "aaa", 3973 | 3.6, 3974 | }, 3975 | }, 3976 | } 3977 | for _, tt := range tests { 3978 | t.Run(tt.name, func(t *testing.T) { 3979 | buf := new(bytes.Buffer) 3980 | Get().SetMode(WRITER).SetWriter(buf) 3981 | testExit(0, func() { 3982 | Fatalf(tt.format, tt.val...) 3983 | }) 3984 | want := fmt.Sprintf(tt.format, tt.val...) 3985 | if !strings.Contains(buf.String(), want) { 3986 | t.Errorf("Fatalf() = got %v want %v", buf.String(), want) 3987 | } 3988 | }) 3989 | } 3990 | } 3991 | 3992 | func TestFatalln(t *testing.T) { 3993 | tests := []struct { 3994 | name string 3995 | val []interface{} 3996 | }{ 3997 | { 3998 | name: "sample fatalln", 3999 | val: []interface{}{ 4000 | "aaa", 4001 | }, 4002 | }, 4003 | { 4004 | name: "sample fatalln", 4005 | val: []interface{}{ 4006 | "aaa", 4007 | }, 4008 | }, 4009 | } 4010 | for _, tt := range tests { 4011 | t.Run(tt.name, func(t *testing.T) { 4012 | buf := new(bytes.Buffer) 4013 | Get().SetMode(WRITER).SetWriter(buf) 4014 | testExit(0, func() { 4015 | Fatalln(tt.val...) 4016 | }) 4017 | want := fmt.Sprintf("%v", tt.val...) 4018 | if !strings.Contains(buf.String(), want) { 4019 | t.Errorf("Fatalln() = got %v want %v", buf.String(), want) 4020 | } 4021 | }) 4022 | } 4023 | } 4024 | 4025 | func TestReplaceExitFunc(t *testing.T) { 4026 | tests := []struct { 4027 | name string 4028 | fn func(i int) 4029 | }{ 4030 | { 4031 | name: "just pass", 4032 | fn: func(i int) {}, 4033 | }, 4034 | } 4035 | for _, tt := range tests { 4036 | t.Run(tt.name, func(t *testing.T) { 4037 | ReplaceExitFunc(tt.fn) 4038 | }) 4039 | } 4040 | } 4041 | 4042 | func TestReset(t *testing.T) { 4043 | tests := []struct { 4044 | name string 4045 | tag string 4046 | g *Glg 4047 | want LEVEL 4048 | }{ 4049 | { 4050 | name: "reset", 4051 | tag: "glg", 4052 | g: Reset(), 4053 | want: UNKNOWN, 4054 | }, 4055 | } 4056 | for _, tt := range tests { 4057 | t.Run(tt.name, func(t *testing.T) { 4058 | tt.g.AddStdLevel(tt.tag, NONE, false) 4059 | tt.g.Reset() 4060 | got := tt.g.TagStringToLevel(tt.tag) 4061 | if tt.want == got { 4062 | t.Errorf("Reset() = got %v want %v", got, tt.want) 4063 | } 4064 | }) 4065 | } 4066 | } 4067 | 4068 | func TestGlg_Reset(t *testing.T) { 4069 | tests := []struct { 4070 | name string 4071 | tag string 4072 | g *Glg 4073 | want LEVEL 4074 | }{ 4075 | { 4076 | name: "reset", 4077 | tag: "glg", 4078 | g: Get().Reset(), 4079 | want: UNKNOWN, 4080 | }, 4081 | } 4082 | for _, tt := range tests { 4083 | t.Run(tt.name, func(t *testing.T) { 4084 | tt.g.AddStdLevel(tt.tag, NONE, false) 4085 | tt.g.Reset() 4086 | got := tt.g.TagStringToLevel(tt.tag) 4087 | if tt.want == got { 4088 | t.Errorf("Reset() = got %v want %v", got, tt.want) 4089 | } 4090 | }) 4091 | } 4092 | } 4093 | 4094 | func Test_blankFormat(t *testing.T) { 4095 | tests := []struct { 4096 | name string 4097 | vals []interface{} 4098 | want string 4099 | }{ 4100 | { 4101 | name: "10 argument log", 4102 | vals: func() []interface{} { 4103 | var vals []interface{} 4104 | for i := 0; i < 10; i++ { 4105 | vals = append(vals, i) 4106 | } 4107 | return vals 4108 | }(), 4109 | want: "%v %v %v %v %v %v %v %v %v %v", 4110 | }, 4111 | { 4112 | name: "too long argument log", 4113 | vals: func() []interface{} { 4114 | var vals []interface{} 4115 | for i := 0; i < 1000; i++ { 4116 | vals = append(vals, i) 4117 | } 4118 | return vals 4119 | }(), 4120 | want: func() string { 4121 | var str string 4122 | for i := 0; i < 1000; i++ { 4123 | str += "%v " 4124 | } 4125 | return str[:len(str)-1] 4126 | }(), 4127 | }, 4128 | } 4129 | for _, tt := range tests { 4130 | t.Run(tt.name, func(t *testing.T) { 4131 | if got := Get().blankFormat(len(tt.vals)); got != tt.want { 4132 | t.Errorf("blankFormat() = %v, want %v", got, tt.want) 4133 | } 4134 | }) 4135 | } 4136 | } 4137 | 4138 | func TestGlg_RawString(t *testing.T) { 4139 | tests := []struct { 4140 | name string 4141 | args []byte 4142 | want string 4143 | }{ 4144 | { 4145 | name: "trim", 4146 | args: []byte(time.Now().Format(timeFormat) + "\t[" + INFO.String() + sep + "Hello Glg" + rc), 4147 | want: "Hello Glg", 4148 | }, 4149 | { 4150 | name: "trim null", 4151 | args: []byte(time.Now().Format(timeFormat) + "\t[" + INFO.String() + sep + rc), 4152 | want: "", 4153 | }, 4154 | { 4155 | name: "trim hard", 4156 | args: []byte(time.Now().Format(timeFormat) + "\t[" + INFO.String() + sep + "Hello Glg" + sep + "Hello Again" + rc), 4157 | want: "Hello Glg" + sep + "Hello Again", 4158 | }, 4159 | } 4160 | for _, tt := range tests { 4161 | t.Run(tt.name, func(t *testing.T) { 4162 | g := New() 4163 | if got := g.RawString(tt.args); got != tt.want { 4164 | t.Errorf("Glg.RawString() = %v, want %v", got, tt.want) 4165 | } 4166 | }) 4167 | } 4168 | } 4169 | 4170 | func TestRawString(t *testing.T) { 4171 | tests := []struct { 4172 | name string 4173 | args []byte 4174 | want string 4175 | }{ 4176 | { 4177 | name: "trim", 4178 | args: []byte(time.Now().Format(timeFormat) + "\t[" + INFO.String() + sep + "Hello Glg" + rc), 4179 | want: "Hello Glg", 4180 | }, 4181 | { 4182 | name: "trim null", 4183 | args: []byte(time.Now().Format(timeFormat) + "\t[" + INFO.String() + sep + rc), 4184 | want: "", 4185 | }, 4186 | { 4187 | name: "trim hard", 4188 | args: []byte(time.Now().Format(timeFormat) + "\t[" + INFO.String() + sep + "Hello Glg" + sep + "Hello Again" + rc), 4189 | want: "Hello Glg" + sep + "Hello Again", 4190 | }, 4191 | } 4192 | for _, tt := range tests { 4193 | t.Run(tt.name, func(t *testing.T) { 4194 | if got := RawString(tt.args); got != tt.want { 4195 | t.Errorf("Glg.RawString() = %v, want %v", got, tt.want) 4196 | } 4197 | }) 4198 | } 4199 | } 4200 | 4201 | type dumpWriter struct { 4202 | body []byte 4203 | } 4204 | 4205 | func (d *dumpWriter) Write(b []byte) (int, error) { 4206 | d.body = append(d.body, b...) 4207 | return len(b), nil 4208 | } 4209 | 4210 | func (d dumpWriter) Read(p []byte) (n int, err error) { 4211 | copy(p, d.body) 4212 | return len(d.body), nil 4213 | } 4214 | 4215 | func TestGlg_EnableJSON(t *testing.T) { 4216 | if Get().EnableJSON().enableJSON != true { 4217 | t.Error("json mode is not enabled") 4218 | } 4219 | var d dumpWriter 4220 | g := New().SetWriter(&d).SetMode(WRITER).EnableJSON() 4221 | txt := "hello" 4222 | err := g.Info(txt) 4223 | if err != nil { 4224 | t.Error(err) 4225 | } 4226 | var dec JSONFormat 4227 | err = json.NewDecoder(d).Decode(&dec) 4228 | if err != nil { 4229 | t.Error(err) 4230 | } 4231 | if dec.Level != INFO.String() { 4232 | t.Error("invalid Level") 4233 | } 4234 | if i, ok := dec.Detail.(interface{}); !ok || i.(string) != txt { 4235 | t.Error("invalid json") 4236 | } 4237 | } 4238 | 4239 | func TestGlg_DisableJSON(t *testing.T) { 4240 | if Get().DisableJSON().enableJSON != false { 4241 | t.Error("json mode is not disables") 4242 | } 4243 | } 4244 | 4245 | func TestGlg_EnablePoolBuffer(t *testing.T) { 4246 | g := Get().EnablePoolBuffer(100) 4247 | _, ok := g.buffer.Get().(*bytes.Buffer) 4248 | if !ok { 4249 | t.Error("buffer is not bytes.Buffer") 4250 | } 4251 | } 4252 | 4253 | func Test_logger_updateMode(t *testing.T) { 4254 | type fields struct { 4255 | writer io.Writer 4256 | isColor bool 4257 | mode MODE 4258 | } 4259 | tests := []struct { 4260 | name string 4261 | fields fields 4262 | want wMode 4263 | }{ 4264 | { 4265 | name: "writeWriter mode", 4266 | fields: fields{ 4267 | mode: WRITER, 4268 | writer: new(bytes.Buffer), 4269 | }, 4270 | want: writeWriter, 4271 | }, 4272 | 4273 | { 4274 | name: "writeColorBoth mode", 4275 | fields: fields{ 4276 | mode: BOTH, 4277 | isColor: true, 4278 | writer: new(bytes.Buffer), 4279 | }, 4280 | want: writeColorBoth, 4281 | }, 4282 | { 4283 | name: "writeBoth mode", 4284 | fields: fields{ 4285 | mode: BOTH, 4286 | writer: new(bytes.Buffer), 4287 | }, 4288 | want: writeBoth, 4289 | }, 4290 | { 4291 | name: "writeColorStd mode due to nil writer", 4292 | fields: fields{ 4293 | mode: BOTH, 4294 | isColor: true, 4295 | }, 4296 | want: writeColorStd, 4297 | }, 4298 | { 4299 | name: "writeStd mode due to nil writer", 4300 | fields: fields{ 4301 | mode: BOTH, 4302 | }, 4303 | want: writeStd, 4304 | }, 4305 | { 4306 | name: "writeColorStd mode", 4307 | fields: fields{ 4308 | mode: STD, 4309 | isColor: true, 4310 | }, 4311 | want: writeColorStd, 4312 | }, 4313 | { 4314 | name: "writeStd mode", 4315 | fields: fields{ 4316 | mode: STD, 4317 | }, 4318 | want: writeStd, 4319 | }, 4320 | } 4321 | for _, tt := range tests { 4322 | t.Run(tt.name, func(t *testing.T) { 4323 | l := &logger{ 4324 | writer: tt.fields.writer, 4325 | isColor: tt.fields.isColor, 4326 | mode: tt.fields.mode, 4327 | } 4328 | if got := l.updateMode(); l.writeMode != tt.want { 4329 | t.Errorf("logger.updateMode() = %v, want %v", got, tt.want) 4330 | } 4331 | }) 4332 | } 4333 | } 4334 | 4335 | func TestGlg_EnableTimestamp(t *testing.T) { 4336 | type fields struct { 4337 | bs *uint64 4338 | logger loggers 4339 | levelCounter *uint32 4340 | levelMap levelMap 4341 | buffer sync.Pool 4342 | enableJSON bool 4343 | } 4344 | tests := []struct { 4345 | name string 4346 | fields fields 4347 | want *Glg 4348 | }{ 4349 | // TODO: Add test cases. 4350 | } 4351 | for _, tt := range tests { 4352 | t.Run(tt.name, func(t *testing.T) { 4353 | g := &Glg{ 4354 | bs: tt.fields.bs, 4355 | logger: tt.fields.logger, 4356 | levelCounter: tt.fields.levelCounter, 4357 | levelMap: tt.fields.levelMap, 4358 | buffer: tt.fields.buffer, 4359 | enableJSON: tt.fields.enableJSON, 4360 | } 4361 | if got := g.EnableTimestamp(); !reflect.DeepEqual(got, tt.want) { 4362 | t.Errorf("Glg.EnableTimestamp() = %v, want %v", got, tt.want) 4363 | } 4364 | }) 4365 | } 4366 | } 4367 | 4368 | func TestGlg_DisableTimestamp(t *testing.T) { 4369 | type fields struct { 4370 | bs *uint64 4371 | logger loggers 4372 | levelCounter *uint32 4373 | levelMap levelMap 4374 | buffer sync.Pool 4375 | enableJSON bool 4376 | } 4377 | tests := []struct { 4378 | name string 4379 | fields fields 4380 | want *Glg 4381 | }{ 4382 | // TODO: Add test cases. 4383 | } 4384 | for _, tt := range tests { 4385 | t.Run(tt.name, func(t *testing.T) { 4386 | g := &Glg{ 4387 | bs: tt.fields.bs, 4388 | logger: tt.fields.logger, 4389 | levelCounter: tt.fields.levelCounter, 4390 | levelMap: tt.fields.levelMap, 4391 | buffer: tt.fields.buffer, 4392 | enableJSON: tt.fields.enableJSON, 4393 | } 4394 | if got := g.DisableTimestamp(); !reflect.DeepEqual(got, tt.want) { 4395 | t.Errorf("Glg.DisableTimestamp() = %v, want %v", got, tt.want) 4396 | } 4397 | }) 4398 | } 4399 | } 4400 | 4401 | func TestGlg_EnableLevelTimestamp(t *testing.T) { 4402 | type fields struct { 4403 | bs *uint64 4404 | logger loggers 4405 | levelCounter *uint32 4406 | levelMap levelMap 4407 | buffer sync.Pool 4408 | enableJSON bool 4409 | } 4410 | type args struct { 4411 | lv LEVEL 4412 | } 4413 | tests := []struct { 4414 | name string 4415 | fields fields 4416 | args args 4417 | want *Glg 4418 | }{ 4419 | // TODO: Add test cases. 4420 | } 4421 | for _, tt := range tests { 4422 | t.Run(tt.name, func(t *testing.T) { 4423 | g := &Glg{ 4424 | bs: tt.fields.bs, 4425 | logger: tt.fields.logger, 4426 | levelCounter: tt.fields.levelCounter, 4427 | levelMap: tt.fields.levelMap, 4428 | buffer: tt.fields.buffer, 4429 | enableJSON: tt.fields.enableJSON, 4430 | } 4431 | if got := g.EnableLevelTimestamp(tt.args.lv); !reflect.DeepEqual(got, tt.want) { 4432 | t.Errorf("Glg.EnableLevelTimestamp() = %v, want %v", got, tt.want) 4433 | } 4434 | }) 4435 | } 4436 | } 4437 | 4438 | func TestGlg_DisableLevelTimestamp(t *testing.T) { 4439 | type fields struct { 4440 | bs *uint64 4441 | logger loggers 4442 | levelCounter *uint32 4443 | levelMap levelMap 4444 | buffer sync.Pool 4445 | enableJSON bool 4446 | } 4447 | type args struct { 4448 | lv LEVEL 4449 | } 4450 | tests := []struct { 4451 | name string 4452 | fields fields 4453 | args args 4454 | want *Glg 4455 | }{ 4456 | // TODO: Add test cases. 4457 | } 4458 | for _, tt := range tests { 4459 | t.Run(tt.name, func(t *testing.T) { 4460 | g := &Glg{ 4461 | bs: tt.fields.bs, 4462 | logger: tt.fields.logger, 4463 | levelCounter: tt.fields.levelCounter, 4464 | levelMap: tt.fields.levelMap, 4465 | buffer: tt.fields.buffer, 4466 | enableJSON: tt.fields.enableJSON, 4467 | } 4468 | if got := g.DisableLevelTimestamp(tt.args.lv); !reflect.DeepEqual(got, tt.want) { 4469 | t.Errorf("Glg.DisableLevelTimestamp() = %v, want %v", got, tt.want) 4470 | } 4471 | }) 4472 | } 4473 | } 4474 | 4475 | func TestGlg_blankFormat(t *testing.T) { 4476 | type fields struct { 4477 | bs *uint64 4478 | logger loggers 4479 | levelCounter *uint32 4480 | levelMap levelMap 4481 | buffer sync.Pool 4482 | enableJSON bool 4483 | } 4484 | type args struct { 4485 | l int 4486 | } 4487 | tests := []struct { 4488 | name string 4489 | fields fields 4490 | args args 4491 | want string 4492 | }{ 4493 | // TODO: Add test cases. 4494 | } 4495 | for _, tt := range tests { 4496 | t.Run(tt.name, func(t *testing.T) { 4497 | g := &Glg{ 4498 | bs: tt.fields.bs, 4499 | logger: tt.fields.logger, 4500 | levelCounter: tt.fields.levelCounter, 4501 | levelMap: tt.fields.levelMap, 4502 | buffer: tt.fields.buffer, 4503 | enableJSON: tt.fields.enableJSON, 4504 | } 4505 | if got := g.blankFormat(tt.args.l); got != tt.want { 4506 | t.Errorf("Glg.blankFormat() = %v, want %v", got, tt.want) 4507 | } 4508 | }) 4509 | } 4510 | } 4511 | 4512 | func Test_isModeEnable(t *testing.T) { 4513 | type args struct { 4514 | l LEVEL 4515 | } 4516 | tests := []struct { 4517 | name string 4518 | args args 4519 | want bool 4520 | }{ 4521 | // TODO: Add test cases. 4522 | } 4523 | for _, tt := range tests { 4524 | t.Run(tt.name, func(t *testing.T) { 4525 | if got := isModeEnable(tt.args.l); got != tt.want { 4526 | t.Errorf("isModeEnable() = %v, want %v", got, tt.want) 4527 | } 4528 | }) 4529 | } 4530 | } 4531 | 4532 | func TestGlg_isModeEnable(t *testing.T) { 4533 | type fields struct { 4534 | bs *uint64 4535 | logger loggers 4536 | levelCounter *uint32 4537 | levelMap levelMap 4538 | buffer sync.Pool 4539 | enableJSON bool 4540 | } 4541 | type args struct { 4542 | l LEVEL 4543 | } 4544 | tests := []struct { 4545 | name string 4546 | fields fields 4547 | args args 4548 | want bool 4549 | }{ 4550 | // TODO: Add test cases. 4551 | } 4552 | for _, tt := range tests { 4553 | t.Run(tt.name, func(t *testing.T) { 4554 | g := &Glg{ 4555 | bs: tt.fields.bs, 4556 | logger: tt.fields.logger, 4557 | levelCounter: tt.fields.levelCounter, 4558 | levelMap: tt.fields.levelMap, 4559 | buffer: tt.fields.buffer, 4560 | enableJSON: tt.fields.enableJSON, 4561 | } 4562 | if got := g.isModeEnable(tt.args.l); got != tt.want { 4563 | t.Errorf("Glg.isModeEnable() = %v, want %v", got, tt.want) 4564 | } 4565 | }) 4566 | } 4567 | } 4568 | 4569 | func TestAtol(t *testing.T) { 4570 | tests := []struct { 4571 | name string 4572 | g *Glg 4573 | tag string 4574 | want LEVEL 4575 | createFlg bool 4576 | }{ 4577 | { 4578 | name: "customTag", 4579 | g: Get().Reset(), 4580 | tag: "customTag", 4581 | want: Atol("customTag"), 4582 | createFlg: true, 4583 | }, 4584 | { 4585 | name: "D returns DEBG", 4586 | g: Get().Reset(), 4587 | tag: "D", 4588 | want: DEBG, 4589 | createFlg: false, 4590 | }, 4591 | { 4592 | name: "debug return DEBG", 4593 | g: Get().Reset(), 4594 | tag: "debug", 4595 | want: DEBG, 4596 | createFlg: false, 4597 | }, 4598 | { 4599 | name: "info return INFO", 4600 | g: Get().Reset(), 4601 | tag: "info", 4602 | want: INFO, 4603 | createFlg: false, 4604 | }, 4605 | { 4606 | name: "customTag No create", 4607 | g: Get(), 4608 | tag: "customTagFail", 4609 | want: UNKNOWN, 4610 | createFlg: false, 4611 | }, 4612 | } 4613 | for _, tt := range tests { 4614 | t.Run(tt.name, func(t *testing.T) { 4615 | if tt.createFlg { 4616 | tt.g.AddStdLevel(tt.tag, STD, false) 4617 | } 4618 | got := Atol(tt.tag) 4619 | if got != tt.want { 4620 | t.Errorf("Glg.Atol = %v, want %v", got, tt.want) 4621 | } 4622 | }) 4623 | } 4624 | } 4625 | 4626 | func TestGlg_Atol(t *testing.T) { 4627 | tests := []struct { 4628 | name string 4629 | g *Glg 4630 | tag string 4631 | want LEVEL 4632 | createFlg bool 4633 | }{ 4634 | { 4635 | name: "customTag", 4636 | g: Get().Reset(), 4637 | tag: "customTag", 4638 | want: Atol("customTag"), 4639 | createFlg: true, 4640 | }, 4641 | { 4642 | name: "D returns DEBG", 4643 | g: Get().Reset(), 4644 | tag: "D", 4645 | want: DEBG, 4646 | createFlg: false, 4647 | }, 4648 | { 4649 | name: "debug return DEBG", 4650 | g: Get().Reset(), 4651 | tag: "debug", 4652 | want: DEBG, 4653 | createFlg: false, 4654 | }, 4655 | { 4656 | name: "info return INFO", 4657 | g: Get().Reset(), 4658 | tag: "info", 4659 | want: INFO, 4660 | createFlg: false, 4661 | }, 4662 | { 4663 | name: "customTag No create", 4664 | g: Get(), 4665 | tag: "customTagFail", 4666 | want: UNKNOWN, 4667 | createFlg: false, 4668 | }, 4669 | } 4670 | for _, tt := range tests { 4671 | t.Run(tt.name, func(t *testing.T) { 4672 | if tt.createFlg { 4673 | tt.g.AddStdLevel(tt.tag, STD, false) 4674 | } 4675 | got := glg.Atol(tt.tag) 4676 | if got != tt.want { 4677 | t.Errorf("Glg.Atol = %v, want %v", got, tt.want) 4678 | } 4679 | }) 4680 | } 4681 | } 4682 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kpango/glg 2 | 3 | go 1.21.1 4 | 5 | require ( 6 | github.com/goccy/go-json v0.10.2 7 | github.com/kpango/fastime v1.1.9 8 | github.com/sirupsen/logrus v1.9.3 9 | go.uber.org/zap v1.26.0 10 | ) 11 | 12 | require ( 13 | go.uber.org/multierr v1.10.0 // indirect 14 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 5 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 6 | github.com/kpango/fastime v1.1.9 h1:xVQHcqyPt5M69DyFH7g1EPRns1YQNap9d5eLhl/Jy84= 7 | github.com/kpango/fastime v1.1.9/go.mod h1:vyD7FnUn08zxY4b/QFBZVG+9EWMYsNl+QF0uE46urD4= 8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 9 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 10 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= 11 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 12 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 13 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 14 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 15 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 16 | go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= 17 | go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= 18 | go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= 19 | go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 20 | go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= 21 | go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= 22 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= 23 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 24 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 25 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 26 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 27 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 28 | -------------------------------------------------------------------------------- /images/bench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kpango/glg/d303ca943b313ad990ded56f883cd8c1e67775cf/images/bench.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kpango/glg/d303ca943b313ad990ded56f883cd8c1e67775cf/images/logo.png -------------------------------------------------------------------------------- /images/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kpango/glg/d303ca943b313ad990ded56f883cd8c1e67775cf/images/sample.png -------------------------------------------------------------------------------- /levelmap.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2019 kpango (Yusuke Kato) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | // Package glg can quickly output that are colored and leveled logs with simple syntax 24 | package glg 25 | 26 | import ( 27 | "sync" 28 | "sync/atomic" 29 | "unsafe" 30 | ) 31 | 32 | type levelMap struct { 33 | mu sync.Mutex 34 | read atomic.Value 35 | dirty map[string]*entryLevelMap 36 | misses int 37 | } 38 | 39 | type readOnlyLevelMap struct { 40 | m map[string]*entryLevelMap 41 | amended bool 42 | } 43 | 44 | var expungedLevelMap = unsafe.Pointer(new(LEVEL)) 45 | 46 | type entryLevelMap struct { 47 | p unsafe.Pointer 48 | } 49 | 50 | func newEntryLevelMap(i LEVEL) *entryLevelMap { 51 | return &entryLevelMap{p: unsafe.Pointer(&i)} 52 | } 53 | 54 | func (m *levelMap) Load(key string) (value LEVEL, ok bool) { 55 | read, _ := m.read.Load().(readOnlyLevelMap) 56 | e, ok := read.m[key] 57 | if !ok && read.amended { 58 | m.mu.Lock() 59 | read, _ = m.read.Load().(readOnlyLevelMap) 60 | e, ok = read.m[key] 61 | if !ok && read.amended { 62 | e, ok = m.dirty[key] 63 | m.missLocked() 64 | } 65 | m.mu.Unlock() 66 | } 67 | if !ok { 68 | return value, false 69 | } 70 | return e.load() 71 | } 72 | 73 | func (e *entryLevelMap) load() (value LEVEL, ok bool) { 74 | p := atomic.LoadPointer(&e.p) 75 | if p == nil || p == expungedLevelMap { 76 | return value, false 77 | } 78 | return *(*LEVEL)(p), true 79 | } 80 | 81 | func (m *levelMap) Store(key string, value LEVEL) { 82 | read, _ := m.read.Load().(readOnlyLevelMap) 83 | if e, ok := read.m[key]; ok && e.tryStore(&value) { 84 | return 85 | } 86 | 87 | m.mu.Lock() 88 | read, _ = m.read.Load().(readOnlyLevelMap) 89 | if e, ok := read.m[key]; ok { 90 | if e.unexpungeLocked() { 91 | m.dirty[key] = e 92 | } 93 | e.storeLocked(&value) 94 | } else if e, ok := m.dirty[key]; ok { 95 | e.storeLocked(&value) 96 | } else { 97 | if !read.amended { 98 | m.dirtyLocked() 99 | m.read.Store(readOnlyLevelMap{m: read.m, amended: true}) 100 | } 101 | m.dirty[key] = newEntryLevelMap(value) 102 | } 103 | m.mu.Unlock() 104 | } 105 | 106 | func (e *entryLevelMap) tryStore(i *LEVEL) bool { 107 | for { 108 | p := atomic.LoadPointer(&e.p) 109 | if p == expungedLevelMap { 110 | return false 111 | } 112 | if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { 113 | return true 114 | } 115 | } 116 | } 117 | 118 | func (e *entryLevelMap) unexpungeLocked() (wasExpunged bool) { 119 | return atomic.CompareAndSwapPointer(&e.p, expungedLevelMap, nil) 120 | } 121 | 122 | func (e *entryLevelMap) storeLocked(i *LEVEL) { 123 | atomic.StorePointer(&e.p, unsafe.Pointer(i)) 124 | } 125 | 126 | func (m *levelMap) missLocked() { 127 | m.misses++ 128 | if m.misses < len(m.dirty) { 129 | return 130 | } 131 | m.read.Store(readOnlyLevelMap{m: m.dirty}) 132 | m.dirty = nil 133 | m.misses = 0 134 | } 135 | 136 | func (m *levelMap) dirtyLocked() { 137 | if m.dirty != nil { 138 | return 139 | } 140 | 141 | read, _ := m.read.Load().(readOnlyLevelMap) 142 | m.dirty = make(map[string]*entryLevelMap, len(read.m)) 143 | for k, e := range read.m { 144 | if !e.tryExpungeLocked() { 145 | m.dirty[k] = e 146 | } 147 | } 148 | } 149 | 150 | func (e *entryLevelMap) tryExpungeLocked() (isExpunged bool) { 151 | p := atomic.LoadPointer(&e.p) 152 | for p == nil { 153 | if atomic.CompareAndSwapPointer(&e.p, nil, expungedLevelMap) { 154 | return true 155 | } 156 | p = atomic.LoadPointer(&e.p) 157 | } 158 | return p == expungedLevelMap 159 | } 160 | -------------------------------------------------------------------------------- /loggers.go: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // 3 | // Copyright (c) 2019 kpango (Yusuke Kato) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | // Package glg can quickly output that are colored and leveled logs with simple syntax 24 | package glg 25 | 26 | import ( 27 | "sync" 28 | "sync/atomic" 29 | "unsafe" 30 | ) 31 | 32 | type loggers struct { 33 | mu sync.Mutex 34 | read atomic.Value 35 | dirty map[LEVEL]*entryLoggers 36 | misses int 37 | } 38 | 39 | type readOnlyLoggers struct { 40 | m map[LEVEL]*entryLoggers 41 | amended bool 42 | } 43 | 44 | var expungedLoggers = unsafe.Pointer(new(*logger)) 45 | 46 | type entryLoggers struct { 47 | p unsafe.Pointer 48 | } 49 | 50 | func newEntryLoggers(i *logger) *entryLoggers { 51 | return &entryLoggers{p: unsafe.Pointer(&i)} 52 | } 53 | 54 | func (m *loggers) Load(key LEVEL) (value *logger, ok bool) { 55 | read, _ := m.read.Load().(readOnlyLoggers) 56 | e, ok := read.m[key] 57 | if !ok && read.amended { 58 | m.mu.Lock() 59 | read, _ = m.read.Load().(readOnlyLoggers) 60 | e, ok = read.m[key] 61 | if !ok && read.amended { 62 | e, ok = m.dirty[key] 63 | m.missLocked() 64 | } 65 | m.mu.Unlock() 66 | } 67 | if !ok { 68 | return value, false 69 | } 70 | return e.load() 71 | } 72 | 73 | func (e *entryLoggers) load() (value *logger, ok bool) { 74 | p := atomic.LoadPointer(&e.p) 75 | if p == nil || p == expungedLoggers { 76 | return value, false 77 | } 78 | return *(**logger)(p), true 79 | } 80 | 81 | func (m *loggers) Store(key LEVEL, value *logger) { 82 | read, _ := m.read.Load().(readOnlyLoggers) 83 | if e, ok := read.m[key]; ok && e.tryStore(&value) { 84 | return 85 | } 86 | 87 | m.mu.Lock() 88 | read, _ = m.read.Load().(readOnlyLoggers) 89 | if e, ok := read.m[key]; ok { 90 | if e.unexpungeLocked() { 91 | m.dirty[key] = e 92 | } 93 | e.storeLocked(&value) 94 | } else if e, ok := m.dirty[key]; ok { 95 | e.storeLocked(&value) 96 | } else { 97 | if !read.amended { 98 | m.dirtyLocked() 99 | m.read.Store(readOnlyLoggers{m: read.m, amended: true}) 100 | } 101 | m.dirty[key] = newEntryLoggers(value) 102 | } 103 | m.mu.Unlock() 104 | } 105 | 106 | func (e *entryLoggers) tryStore(i **logger) bool { 107 | for { 108 | p := atomic.LoadPointer(&e.p) 109 | if p == expungedLoggers { 110 | return false 111 | } 112 | if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { 113 | return true 114 | } 115 | } 116 | } 117 | 118 | func (e *entryLoggers) unexpungeLocked() (wasExpunged bool) { 119 | return atomic.CompareAndSwapPointer(&e.p, expungedLoggers, nil) 120 | } 121 | 122 | func (e *entryLoggers) storeLocked(i **logger) { 123 | atomic.StorePointer(&e.p, unsafe.Pointer(i)) 124 | } 125 | 126 | func (m *loggers) Range(f func(key LEVEL, value *logger) bool) { 127 | read, _ := m.read.Load().(readOnlyLoggers) 128 | if read.amended { 129 | m.mu.Lock() 130 | read, _ = m.read.Load().(readOnlyLoggers) 131 | if read.amended { 132 | read = readOnlyLoggers{m: m.dirty} 133 | m.read.Store(read) 134 | m.dirty = nil 135 | m.misses = 0 136 | } 137 | m.mu.Unlock() 138 | } 139 | 140 | for k, e := range read.m { 141 | v, ok := e.load() 142 | if !ok { 143 | continue 144 | } 145 | if !f(k, v) { 146 | break 147 | } 148 | } 149 | } 150 | 151 | func (m *loggers) missLocked() { 152 | m.misses++ 153 | if m.misses < len(m.dirty) { 154 | return 155 | } 156 | m.read.Store(readOnlyLoggers{m: m.dirty}) 157 | m.dirty = nil 158 | m.misses = 0 159 | } 160 | 161 | func (m *loggers) dirtyLocked() { 162 | if m.dirty != nil { 163 | return 164 | } 165 | 166 | read, _ := m.read.Load().(readOnlyLoggers) 167 | m.dirty = make(map[LEVEL]*entryLoggers, len(read.m)) 168 | for k, e := range read.m { 169 | if !e.tryExpungeLocked() { 170 | m.dirty[k] = e 171 | } 172 | } 173 | } 174 | 175 | func (e *entryLoggers) tryExpungeLocked() (isExpunged bool) { 176 | p := atomic.LoadPointer(&e.p) 177 | for p == nil { 178 | if atomic.CompareAndSwapPointer(&e.p, nil, expungedLoggers) { 179 | return true 180 | } 181 | p = atomic.LoadPointer(&e.p) 182 | } 183 | return p == expungedLoggers 184 | } 185 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | --------------------------------------------------------------------------------