├── .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 | [](https://opensource.org/licenses/MIT)
6 | [](https://github.com/kpango/glg/releases/latest)
7 | [](https://circleci.com/gh/kpango/glg)
8 | [](https://codecov.io/gh/kpango/glg)
9 | [](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 | [](https://goreportcard.com/report/github.com/kpango/glg)
11 | [](https://golangci.com/r/github.com/kpango/glg)
12 | [](https://gowalker.org/github.com/kpango/glg)
13 | [](http://godoc.org/github.com/kpango/glg)
14 | [](https://depshield.github.io)
15 | [](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 | [](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 |
--------------------------------------------------------------------------------