Skip to content

Commit 3312f28

Browse files
committed
re-organize files & switch to go-logr/logr
1 parent d13006f commit 3312f28

File tree

10 files changed

+69
-26
lines changed

10 files changed

+69
-26
lines changed

Makefile

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,14 @@
1-
2-
GOFILES=$(wildcard *.go)
3-
BACKENDS=$(wildcard ./backend/*.go)
4-
EXAMPLE=./example/main.go
5-
GOBIN=./bin
6-
71
all: build test
82

3+
.PHONY: build
94
build:
10-
@echo " > formating file ..."
11-
go fmt $(GOFILES)
12-
go fmt $(BACKENDS)
13-
golangci-lint run $(GOFILES)
14-
golangci-lint run $(BACKENDS)
15-
@rm -rf $(GOBIN)
16-
@-mkdir $(GOBIN)
17-
go build -o $(patsubst %.go, $(GOBIN)/%, $(notdir $(EXAMPLE))) $(EXAMPLE)
5+
@scripts/go-build
186

7+
.PHONY: test
198
test:
209
@echo " > testing file ..."
2110

22-
.PHONY:clean
11+
.PHONY: clean
2312
clean:
2413
@echo " > cleaning file ..."
25-
rm -rf $(GOBIN)
14+
rm -rf ./bin/

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## 功能介绍
44

5-
[`go-coder/logr`](https://github.com/go-coder/logr) 的一个基础实现方案。`go-coder/logr`[`go-logr/logr`](https://github.com/go-logr/logr) 的一个分支,对于当前实现简单改动就能应用到 `go-logr/logr`
5+
[`go-logr/logr`](https://github.com/go-logr/logr) 的一个基础实现方案
66

77
## 设计思路
88

@@ -17,8 +17,9 @@
1717

1818
+ 远程日志:pubsub、 gRPC、HTTP网页 等形式
1919
+ AB测试:同时运行新旧版本的程序,自动对比日志不同,从中发现可能存在的问题
20+
+ 日志归集:将多个不同程序的日志汇总到一个地址进行分析
2021

21-
## 竞争问题
22+
## 前端的竞争问题
2223

2324
考虑两种使用场景:
2425

@@ -40,7 +41,7 @@ go func() {
4041
}()
4142
```
4243

43-
1. logr.V / logr.WithName / logr.WithFields
44+
1. logr.V / logr.WithName / logr.WithValues
4445

4546
实现的时候,都是在副本中进行的操作,只需要考虑 copy 函数是否有竞争问题即可。
4647

@@ -57,3 +58,7 @@ go func() {
5758
### 结论
5859

5960
logr 通过 log 对象只读的方式避免了竞争问题。所有对 log 进行改变的操作都是在新生成的副本之上进行的,从而保证了不会发生竞争。
61+
62+
## 后端竞争问题
63+
64+
由后端自行控制,stderr 的竞争问题分析参见 [README.md](./backend/README.md)

backend/README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
1-
# stderr 解决竞争的方案
1+
# logr 后端设计
2+
3+
logr 在设计的时候充分考虑了扩展性,可以添加多种不同的后端方案,方便日志打印和日志归集。只要实现了 [`types.go`](../types/types.go) 中定义的 [`EntryWriter`](../types/types.go#L15) 接口,就可以直接切换后端,而不必担心日志前端的兼容问题。
4+
5+
这里,我们默认提供了 `stderr`[后端实现](./stderr.go)
6+
7+
## stderr 解决竞争的方案
28

39
log 前端部分采用只读类型解决了竞争问题,后端的竞争问题由后端自行解决。这里的解决思路同样是两个:只读、加锁(包括 chan 也是用到了锁)。
410

511
我们注意到,可能存在的竞争发生在调用 os.Stderr.WriteString 的时候,由于这不是一个原子操作,也就存在着一条日志没打完,另一条日志混入的情况。只读的解决办法看样子不行,我们这里考虑加互斥锁、或者使用 channel,下面比较一下两种方案的优势和不足:
612

713
使用 channel 的好处在于直观,所有的 log 请求被组织成了一个队列的形式,所有的日志汇集到了一个 goroutine 中进行处理;可能存在的问题是,当日志请求过多的时候,这个负责处理日志的 goroutine 可能会成为性能瓶颈。
814

9-
加锁的话,日志请求在原来的 goroutine 中完成,避免了单个 goroutine 的性能我呢提,但是会影响当前 goroutine 的性能。
15+
加锁的话,日志请求在原来的 goroutine 中完成,避免了单个 goroutine 的性能问题,但是会影响当前 goroutine 的性能。
1016

1117
我们假定日志组织良好,不会达到 goroutine 性能瓶颈。这样,采用 channel 的方式排队处理请求,把日志处理从普通 goroutine 中提取出来,由专门的 goroutine 来处理,以期提高性能。
18+
19+
### 思考1
20+
21+
如果使用的是无缓冲chan的话,日志库性能并不高,因为阻塞队列必须每产生一条日志就打印下来,这其实是一个同步操作。带缓冲的chan能够提高性能。(这里其实是假设所有的 goroutine 是在一个线程内部了,被分配到一个核上执行)
22+
23+
ps: goroutine 是否能够充分利用多核CPU,把打印日志的 goroutine 单独放到另一个核中?这样的话就不存在阻塞问题了,性能会很好。
24+
25+
### 思考2
26+
27+
单独启动一个 goroutine 负责日志后端打印的话,存在一个问题:当主程序执行完一条打印日志命令后很快结束程序的时候,所有 goroutine 都会被杀死,但是这时候可能日志还没打印完毕,会有丢失日志的情况出现。我们需要一个同步的操作来等待日志打印完毕再结束进程。

bin/main

2.49 MB
Binary file not shown.

example/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func main() {
1111
log.Info("yes I can call it directly")
1212

13-
logr := log.NewLogger(backend.Stderr()).WithName("test").WithFields("key", "value")
13+
logr := log.NewLogger(backend.Stderr()).WithName("test").WithValues("key", "value")
1414

1515
logr.V(1).Info("msg", "uint", 112, "int", 211, "nil", nil)
1616
var typedNil *int

frontend/logr.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
"runtime/debug"
99
"time"
1010

11-
"github.com/go-coder/logr"
1211
"github.com/go-coder/log/types"
12+
"github.com/go-logr/logr"
1313
"github.com/spf13/pflag"
1414
)
1515

@@ -75,7 +75,7 @@ func (l *rlog) WithName(name string) logr.Logger {
7575
return out
7676
}
7777

78-
func (l *rlog) WithFields(kvList ...interface{}) logr.Logger {
78+
func (l *rlog) WithValues(kvList ...interface{}) logr.Logger {
7979
out := l.clone()
8080
out.fields = append(out.fields, kvList...)
8181
return out

go.mod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module github.com/go-coder/log
2+
3+
go 1.12
4+
5+
require (
6+
github.com/go-coder/logr v0.1.0
7+
github.com/go-logr/logr v0.1.0
8+
github.com/spf13/pflag v1.0.3
9+
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
github.com/go-coder/logr v0.1.0 h1:cKKbRhVJXz38rq0AG/QVIM6Atx14po8nL8It6wgi7+w=
2+
github.com/go-coder/logr v0.1.0/go.mod h1:Wb42XhUxL//12vqkxbdiqPP04fqnODPsXhd87jSiKqw=
3+
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
4+
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
5+
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
6+
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=

logr.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package log
33
import (
44
"github.com/go-coder/log/backend"
55
"github.com/go-coder/log/frontend"
6-
"github.com/go-coder/logr"
6+
"github.com/go-logr/logr"
77
)
88

99
var (
@@ -13,7 +13,7 @@ var (
1313

1414
V = syslog.V
1515
WithName = syslog.WithName
16-
WithFields = syslog.WithFields
16+
WithValues = syslog.WithValues
1717
Info = syslog.Info
1818
Error = syslog.Error
1919
)

scripts/go-build

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
3+
# Use the Unofficial Bash Strict Mode (Unless You Looove Debugging) | Aaron Maxwell
4+
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
5+
set -euo pipefail
6+
IFS=$'\n\t'
7+
8+
main() {
9+
echo " > formating file ..."
10+
for dir in . ./types ./frontend ./backend ./example; do
11+
go fmt $dir/...
12+
golangci-lint run $dir/...
13+
done
14+
echo " > building file ..."
15+
go build -o ./bin/main ./example/main.go
16+
}
17+
18+
main ${@:-}

0 commit comments

Comments
 (0)