fix log field (#3)

pull/4/head
Felix Hao 6 years ago committed by GitHub
parent f98cd0a5c0
commit d0b98db00c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      README.md
  2. 58
      pkg/log/field.go
  3. 11
      pkg/log/handler.go
  4. 2
      pkg/log/internal/LICENSE.txt
  5. 0
      pkg/log/internal/core/buffer.go
  6. 0
      pkg/log/internal/core/buffer_test.go
  7. 0
      pkg/log/internal/core/bufferpool.go
  8. 0
      pkg/log/internal/core/encoder.go
  9. 122
      pkg/log/internal/core/field.go
  10. 0
      pkg/log/internal/core/json_encoder.go
  11. 0
      pkg/log/internal/core/pool.go
  12. 0
      pkg/log/internal/core/pool_test.go
  13. 6
      pkg/log/internal/field.go
  14. 2
      pkg/log/internal/filewriter/filewriter_test.go
  15. 90
      pkg/log/log.go
  16. 14
      pkg/log/util.go
  17. 2
      pkg/log/verbose.go
  18. 9
      pkg/naming/README.md
  19. 29
      pkg/naming/discovery/discovery.go
  20. 1
      pkg/naming/naming.go
  21. 15
      pkg/net/http/blademaster/client.go

@ -7,13 +7,15 @@ Kratos是[bilibili](https://www.bilibili.com)开源的一套Go微服务框架,
# TODOs # TODOs
- [ ] log&log-agent @围城 - [x] naming discovery
- [ ] config @志辉 - [x] log
- [ ] bm @佳辉 - [ ] log-agent
- [ ] warden @龙虾 - [ ] config
- [x] naming discovery @堂辉 - [ ] bm
- [ ] cache&database @小旭 - [ ] warden
- [ ] kratos tool @普余 - [ ] cache
- [ ] database
- [ ] kratos tool
# issues # issues

@ -0,0 +1,58 @@
package log
import (
"math"
"time"
"github.com/bilibili/Kratos/pkg/log/internal/core"
)
// D represents a map of entry level data used for structured logging.
// type D map[string]interface{}
type D = core.Field
// KVString construct Field with string value.
func KVString(key string, value string) D {
return D{Key: key, Type: core.StringType, StringVal: value}
}
// KVInt construct Field with int value.
func KVInt(key string, value int) D {
return D{Key: key, Type: core.IntTpye, Int64Val: int64(value)}
}
// KVInt64 construct D with int64 value.
func KVInt64(key string, value int64) D {
return D{Key: key, Type: core.Int64Type, Int64Val: value}
}
// KVUint construct Field with uint value.
func KVUint(key string, value uint) D {
return D{Key: key, Type: core.UintType, Int64Val: int64(value)}
}
// KVUint64 construct Field with uint64 value.
func KVUint64(key string, value uint64) D {
return D{Key: key, Type: core.Uint64Type, Int64Val: int64(value)}
}
// KVFloat32 construct Field with float32 value.
func KVFloat32(key string, value float32) D {
return D{Key: key, Type: core.Float32Type, Int64Val: int64(math.Float32bits(value))}
}
// KVFloat64 construct Field with float64 value.
func KVFloat64(key string, value float64) D {
return D{Key: key, Type: core.Float64Type, Int64Val: int64(math.Float64bits(value))}
}
// KVDuration construct Field with Duration value.
func KVDuration(key string, value time.Duration) D {
return D{Key: key, Type: core.DurationType, Int64Val: int64(value)}
}
// KV return a log kv for logging field.
// NOTE: use KV{type name} can avoid object alloc and get better performance. []~( ̄▽ ̄)~*干杯
func KV(key string, value interface{}) D {
return D{Key: key, Value: value}
}

@ -76,19 +76,20 @@ type Handlers struct {
// Log handlers logging. // Log handlers logging.
func (hs Handlers) Log(c context.Context, lv Level, d ...D) { func (hs Handlers) Log(c context.Context, lv Level, d ...D) {
var fn string var hasSource bool
for i := range d { for i := range d {
if _, ok := hs.filters[d[i].Key]; ok { if _, ok := hs.filters[d[i].Key]; ok {
d[i].Value = "***" d[i].Value = "***"
} }
if d[i].Key == _source { if d[i].Key == _source {
fn = d[i].Value.(string) hasSource = true
} }
} }
if fn == "" { if !hasSource {
fn = funcName(4) fn := funcName(3)
d = append(d, KVString(_source, fn))
} }
d = append(d, KV(_source, fn), KV(_time, time.Now()), KV(_levelValue, int(lv)), KV(_level, lv.String())) d = append(d, KV(_time, time.Now()), KVInt64(_levelValue, int64(lv)), KVString(_level, lv.String()))
for _, h := range hs.handlers { for _, h := range hs.handlers {
h.Log(c, lv, d...) h.Log(c, lv, d...)
} }

@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.

@ -0,0 +1,122 @@
package core
import (
"fmt"
"math"
"time"
xtime "github.com/bilibili/Kratos/pkg/time"
)
// FieldType represent D value type
type FieldType int32
// DType enum
const (
UnknownType FieldType = iota
StringType
IntTpye
Int64Type
UintType
Uint64Type
Float32Type
Float64Type
DurationType
)
// Field is for encoder
type Field struct {
Key string
Value interface{}
Type FieldType
StringVal string
Int64Val int64
}
// AddTo exports a field through the ObjectEncoder interface. It's primarily
// useful to library authors, and shouldn't be necessary in most applications.
func (f Field) AddTo(enc ObjectEncoder) {
if f.Type == UnknownType {
f.assertAddTo(enc)
return
}
switch f.Type {
case StringType:
enc.AddString(f.Key, f.StringVal)
case IntTpye:
enc.AddInt(f.Key, int(f.Int64Val))
case Int64Type:
enc.AddInt64(f.Key, f.Int64Val)
case UintType:
enc.AddUint(f.Key, uint(f.Int64Val))
case Uint64Type:
enc.AddUint64(f.Key, uint64(f.Int64Val))
case Float32Type:
enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Int64Val)))
case Float64Type:
enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Int64Val)))
case DurationType:
enc.AddDuration(f.Key, time.Duration(f.Int64Val))
default:
panic(fmt.Sprintf("unknown field type: %v", f))
}
}
func (f Field) assertAddTo(enc ObjectEncoder) {
// assert interface
switch val := f.Value.(type) {
case bool:
enc.AddBool(f.Key, val)
case complex128:
enc.AddComplex128(f.Key, val)
case complex64:
enc.AddComplex64(f.Key, val)
case float64:
enc.AddFloat64(f.Key, val)
case float32:
enc.AddFloat32(f.Key, val)
case int:
enc.AddInt(f.Key, val)
case int64:
enc.AddInt64(f.Key, val)
case int32:
enc.AddInt32(f.Key, val)
case int16:
enc.AddInt16(f.Key, val)
case int8:
enc.AddInt8(f.Key, val)
case string:
enc.AddString(f.Key, val)
case uint:
enc.AddUint(f.Key, val)
case uint64:
enc.AddUint64(f.Key, val)
case uint32:
enc.AddUint32(f.Key, val)
case uint16:
enc.AddUint16(f.Key, val)
case uint8:
enc.AddUint8(f.Key, val)
case []byte:
enc.AddByteString(f.Key, val)
case uintptr:
enc.AddUintptr(f.Key, val)
case time.Time:
enc.AddTime(f.Key, val)
case xtime.Time:
enc.AddTime(f.Key, val.Time())
case time.Duration:
enc.AddDuration(f.Key, val)
case xtime.Duration:
enc.AddDuration(f.Key, time.Duration(val))
case error:
enc.AddString(f.Key, val.Error())
case fmt.Stringer:
enc.AddString(f.Key, val.String())
default:
err := enc.AddReflected(f.Key, val)
if err != nil {
enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
}
}
}

@ -1,6 +0,0 @@
package core
// Field is for encoder
type Field interface {
AddTo(enc ObjectEncoder)
}

@ -24,7 +24,7 @@ func touch(dir, name string) {
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
ret := m.Run() ret := m.Run()
// os.RemoveAll(logdir) os.RemoveAll(logdir)
os.Exit(ret) os.Exit(ret)
} }

@ -7,7 +7,6 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/bilibili/Kratos/pkg/conf/env" "github.com/bilibili/Kratos/pkg/conf/env"
) )
@ -115,83 +114,6 @@ func Init(conf *Config) {
c = conf c = conf
} }
// D represents a map of entry level data used for structured logging.
// type D map[string]interface{}
type D struct {
Key string
Value interface{}
}
// AddTo exports a field through the ObjectEncoder interface. It's primarily
// useful to library authors, and shouldn't be necessary in most applications.
func (d D) AddTo(enc core.ObjectEncoder) {
var err error
switch val := d.Value.(type) {
case bool:
enc.AddBool(d.Key, val)
case complex128:
enc.AddComplex128(d.Key, val)
case complex64:
enc.AddComplex64(d.Key, val)
case float64:
enc.AddFloat64(d.Key, val)
case float32:
enc.AddFloat32(d.Key, val)
case int:
enc.AddInt(d.Key, val)
case int64:
enc.AddInt64(d.Key, val)
case int32:
enc.AddInt32(d.Key, val)
case int16:
enc.AddInt16(d.Key, val)
case int8:
enc.AddInt8(d.Key, val)
case string:
enc.AddString(d.Key, val)
case uint:
enc.AddUint(d.Key, val)
case uint64:
enc.AddUint64(d.Key, val)
case uint32:
enc.AddUint32(d.Key, val)
case uint16:
enc.AddUint16(d.Key, val)
case uint8:
enc.AddUint8(d.Key, val)
case []byte:
enc.AddByteString(d.Key, val)
case uintptr:
enc.AddUintptr(d.Key, val)
case time.Time:
enc.AddTime(d.Key, val)
case xtime.Time:
enc.AddTime(d.Key, val.Time())
case time.Duration:
enc.AddDuration(d.Key, val)
case xtime.Duration:
enc.AddDuration(d.Key, time.Duration(val))
case error:
enc.AddString(d.Key, val.Error())
case fmt.Stringer:
enc.AddString(d.Key, val.String())
default:
err = enc.AddReflected(d.Key, val)
}
if err != nil {
enc.AddString(fmt.Sprintf("%sError", d.Key), err.Error())
}
}
// KV return a log kv for logging field.
func KV(key string, value interface{}) D {
return D{
Key: key,
Value: value,
}
}
type logFilter []string type logFilter []string
func (f *logFilter) String() string { func (f *logFilter) String() string {
@ -209,32 +131,32 @@ func (f *logFilter) Set(value string) error {
// Info logs a message at the info log level. // Info logs a message at the info log level.
func Info(format string, args ...interface{}) { func Info(format string, args ...interface{}) {
h.Log(context.Background(), _infoLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(context.Background(), _infoLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
// Warn logs a message at the warning log level. // Warn logs a message at the warning log level.
func Warn(format string, args ...interface{}) { func Warn(format string, args ...interface{}) {
h.Log(context.Background(), _warnLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(context.Background(), _warnLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
// Error logs a message at the error log level. // Error logs a message at the error log level.
func Error(format string, args ...interface{}) { func Error(format string, args ...interface{}) {
h.Log(context.Background(), _errorLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(context.Background(), _errorLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
// Infoc logs a message at the info log level. // Infoc logs a message at the info log level.
func Infoc(ctx context.Context, format string, args ...interface{}) { func Infoc(ctx context.Context, format string, args ...interface{}) {
h.Log(ctx, _infoLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(ctx, _infoLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
// Errorc logs a message at the error log level. // Errorc logs a message at the error log level.
func Errorc(ctx context.Context, format string, args ...interface{}) { func Errorc(ctx context.Context, format string, args ...interface{}) {
h.Log(ctx, _errorLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(ctx, _errorLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
// Warnc logs a message at the warning log level. // Warnc logs a message at the warning log level.
func Warnc(ctx context.Context, format string, args ...interface{}) { func Warnc(ctx context.Context, format string, args ...interface{}) {
h.Log(ctx, _warnLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(ctx, _warnLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
// Infov logs a message at the info log level. // Infov logs a message at the info log level.

@ -5,15 +5,12 @@ import (
"fmt" "fmt"
"runtime" "runtime"
"strconv" "strconv"
"sync"
"github.com/bilibili/Kratos/pkg/conf/env" "github.com/bilibili/Kratos/pkg/conf/env"
"github.com/bilibili/Kratos/pkg/net/metadata" "github.com/bilibili/Kratos/pkg/net/metadata"
"github.com/bilibili/Kratos/pkg/net/trace" "github.com/bilibili/Kratos/pkg/net/trace"
) )
var fm sync.Map
func addExtraField(ctx context.Context, fields map[string]interface{}) { func addExtraField(ctx context.Context, fields map[string]interface{}) {
if t, ok := trace.FromContext(ctx); ok { if t, ok := trace.FromContext(ctx); ok {
if s, ok := t.(fmt.Stringer); ok { if s, ok := t.(fmt.Stringer); ok {
@ -42,13 +39,8 @@ func addExtraField(ctx context.Context, fields map[string]interface{}) {
// funcName get func name. // funcName get func name.
func funcName(skip int) (name string) { func funcName(skip int) (name string) {
if pc, _, lineNo, ok := runtime.Caller(skip); ok { if _, file, lineNo, ok := runtime.Caller(skip); ok {
if v, ok := fm.Load(pc); ok { return file + ":" + strconv.Itoa(lineNo)
name = v.(string)
} else {
name = runtime.FuncForPC(pc).Name() + ":" + strconv.FormatInt(int64(lineNo), 10)
fm.Store(pc, name)
}
} }
return return "unknown:0"
} }

@ -85,7 +85,7 @@ func V(v int32) Verbose {
// Info logs a message at the info log level. // Info logs a message at the info log level.
func (v Verbose) Info(format string, args ...interface{}) { func (v Verbose) Info(format string, args ...interface{}) {
if v { if v {
h.Log(context.Background(), _infoLevel, KV(_log, fmt.Sprintf(format, args...))) h.Log(context.Background(), _infoLevel, KVString(_log, fmt.Sprintf(format, args...)))
} }
} }

@ -3,3 +3,12 @@
## 项目简介 ## 项目简介
服务发现、服务注册相关的SDK集合 服务发现、服务注册相关的SDK集合
## 现状
目前默认实现了B站开源的[Discovery](https://github.com/bilibili/discovery)服务注册与发现SDK。
但在使用之前,请确认discovery服务部署完成,并将该discovery.go内`fixConfig`方法的默认配置进行完善。
## 使用
可实现`naming`内的`Builder`&`Resolver`&`Registry`接口用于服务注册与发现,比如B站内部还实现了zk的。

@ -21,7 +21,7 @@ import (
bm "github.com/bilibili/Kratos/pkg/net/http/blademaster" bm "github.com/bilibili/Kratos/pkg/net/http/blademaster"
"github.com/bilibili/Kratos/pkg/net/netutil" "github.com/bilibili/Kratos/pkg/net/netutil"
"github.com/bilibili/Kratos/pkg/net/netutil/breaker" "github.com/bilibili/Kratos/pkg/net/netutil/breaker"
"github.com/bilibili/Kratos/pkg/str" xstr "github.com/bilibili/Kratos/pkg/str"
xtime "github.com/bilibili/Kratos/pkg/time" xtime "github.com/bilibili/Kratos/pkg/time"
) )
@ -53,13 +53,10 @@ var (
// Config discovery configures. // Config discovery configures.
type Config struct { type Config struct {
Nodes []string Nodes []string
Key string Zone string
Secret string Env string
Region string Host string
Zone string
Env string
Host string
} }
// Discovery is discovery client. // Discovery is discovery client.
@ -88,10 +85,7 @@ type appInfo struct {
func fixConfig(c *Config) { func fixConfig(c *Config) {
if len(c.Nodes) == 0 { if len(c.Nodes) == 0 {
c.Nodes = []string{"api.bilibili.co"} c.Nodes = []string{"NOTE: please config a default HOST"}
}
if env.Region != "" {
c.Region = env.Region
} }
if env.Zone != "" { if env.Zone != "" {
c.Zone = env.Zone c.Zone = env.Zone
@ -136,11 +130,7 @@ func Build(id string) naming.Resolver {
// New new a discovery client. // New new a discovery client.
func New(c *Config) (d *Discovery) { func New(c *Config) (d *Discovery) {
if c == nil { if c == nil {
c = &Config{ c = &Config{}
Nodes: []string{"discovery.bilibili.co", "api.bilibili.co"},
Key: "discovery",
Secret: "discovery",
}
} }
fixConfig(c) fixConfig(c)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@ -154,10 +144,6 @@ func New(c *Config) (d *Discovery) {
} }
// httpClient // httpClient
cfg := &bm.ClientConfig{ cfg := &bm.ClientConfig{
App: &bm.App{
Key: c.Key,
Secret: c.Secret,
},
Dial: xtime.Duration(3 * time.Second), Dial: xtime.Duration(3 * time.Second),
Timeout: xtime.Duration(40 * time.Second), Timeout: xtime.Duration(40 * time.Second),
Breaker: &breaker.Config{ Breaker: &breaker.Config{
@ -676,7 +662,6 @@ func (d *Discovery) broadcast(apps map[string]naming.InstancesInfo) {
func (d *Discovery) newParams(conf *Config) url.Values { func (d *Discovery) newParams(conf *Config) url.Values {
params := url.Values{} params := url.Values{}
params.Set("region", conf.Region)
params.Set("zone", conf.Zone) params.Set("zone", conf.Zone)
params.Set("env", conf.Env) params.Set("env", conf.Env)
params.Set("hostname", conf.Host) params.Set("hostname", conf.Host)

@ -53,7 +53,6 @@ type Scheduler struct {
// Resolver resolve naming service // Resolver resolve naming service
type Resolver interface { type Resolver interface {
Fetch(context.Context) (*InstancesInfo, bool) Fetch(context.Context) (*InstancesInfo, bool)
//Unwatch(id string)
Watch() <-chan struct{} Watch() <-chan struct{}
Close() error Close() error
} }

@ -43,15 +43,8 @@ func init() {
} }
} }
// App bilibili intranet authorization.
type App struct {
Key string
Secret string
}
// ClientConfig is http client conf. // ClientConfig is http client conf.
type ClientConfig struct { type ClientConfig struct {
*App
Dial xtime.Duration Dial xtime.Duration
Timeout xtime.Duration Timeout xtime.Duration
KeepAlive xtime.Duration KeepAlive xtime.Duration
@ -95,10 +88,6 @@ func NewClient(c *ClientConfig) *Client {
client.urlConf = make(map[string]*ClientConfig) client.urlConf = make(map[string]*ClientConfig)
client.hostConf = make(map[string]*ClientConfig) client.hostConf = make(map[string]*ClientConfig)
client.breaker = breaker.NewGroup(c.Breaker) client.breaker = breaker.NewGroup(c.Breaker)
// check appkey
if c.Key == "" || c.Secret == "" {
panic("http client must config appkey and appsecret")
}
if c.Timeout <= 0 { if c.Timeout <= 0 {
panic("must config http timeout!!!") panic("must config http timeout!!!")
} }
@ -120,10 +109,6 @@ func (client *Client) SetTransport(t xhttp.RoundTripper) {
// SetConfig set client config. // SetConfig set client config.
func (client *Client) SetConfig(c *ClientConfig) { func (client *Client) SetConfig(c *ClientConfig) {
client.mutex.Lock() client.mutex.Lock()
if c.App != nil {
client.conf.App.Key = c.App.Key
client.conf.App.Secret = c.App.Secret
}
if c.Timeout > 0 { if c.Timeout > 0 {
client.conf.Timeout = c.Timeout client.conf.Timeout = c.Timeout
} }

Loading…
Cancel
Save