Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
3eebfb5b11 | |||
fa1427014c | |||
62074965ee | |||
9c8fbb2202 | |||
7c0a5f5e2a | |||
b08f5321b0 | |||
cc0f24e012 | |||
307a08f50c | |||
edc93e8c37 | |||
391813c260 |
@@ -88,6 +88,8 @@ type BatchHandler func(Events) error
|
|||||||
|
|
||||||
// Event is given to a subscription handler for processing
|
// Event is given to a subscription handler for processing
|
||||||
type Event interface {
|
type Event interface {
|
||||||
|
// Context return context.Context for event
|
||||||
|
Context() context.Context
|
||||||
// Topic returns event topic
|
// Topic returns event topic
|
||||||
Topic() string
|
Topic() string
|
||||||
// Message returns broker message
|
// Message returns broker message
|
||||||
|
@@ -4,6 +4,17 @@ import "context"
|
|||||||
|
|
||||||
type loggerKey struct{}
|
type loggerKey struct{}
|
||||||
|
|
||||||
|
// MustContext returns logger from passed context or DefaultLogger if empty
|
||||||
|
func MustContext(ctx context.Context) Logger {
|
||||||
|
if ctx == nil {
|
||||||
|
return DefaultLogger
|
||||||
|
}
|
||||||
|
if l, ok := ctx.Value(loggerKey{}).(Logger); ok && l != nil {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
return DefaultLogger
|
||||||
|
}
|
||||||
|
|
||||||
// FromContext returns logger from passed context
|
// FromContext returns logger from passed context
|
||||||
func FromContext(ctx context.Context) (Logger, bool) {
|
func FromContext(ctx context.Context) (Logger, bool) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
|
@@ -6,6 +6,8 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.unistack.org/micro/v3/meter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func signature
|
// Option func signature
|
||||||
@@ -45,6 +47,8 @@ type Options struct {
|
|||||||
Level Level
|
Level Level
|
||||||
// TimeFunc used to obtain current time
|
// TimeFunc used to obtain current time
|
||||||
TimeFunc func() time.Time
|
TimeFunc func() time.Time
|
||||||
|
// Meter used to count logs for specific level
|
||||||
|
Meter meter.Meter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions creates new options struct
|
// NewOptions creates new options struct
|
||||||
@@ -58,6 +62,7 @@ func NewOptions(opts ...Option) Options {
|
|||||||
ContextAttrFuncs: DefaultContextAttrFuncs,
|
ContextAttrFuncs: DefaultContextAttrFuncs,
|
||||||
AddSource: true,
|
AddSource: true,
|
||||||
TimeFunc: time.Now,
|
TimeFunc: time.Now,
|
||||||
|
Meter: meter.DefaultMeter,
|
||||||
}
|
}
|
||||||
|
|
||||||
WithMicroKeys()(&options)
|
WithMicroKeys()(&options)
|
||||||
|
@@ -11,6 +11,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v3/logger"
|
||||||
|
"go.unistack.org/micro/v3/semconv"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v3/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -150,6 +151,7 @@ func (s *slogLogger) Init(opts ...logger.Option) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, attrs ...interface{}) {
|
func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", lvl.String()).Inc()
|
||||||
if !s.V(lvl) {
|
if !s.V(lvl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -189,6 +191,7 @@ func (s *slogLogger) Log(ctx context.Context, lvl logger.Level, attrs ...interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Logf(ctx context.Context, lvl logger.Level, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Logf(ctx context.Context, lvl logger.Level, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", lvl.String()).Inc()
|
||||||
if !s.V(lvl) {
|
if !s.V(lvl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -228,6 +231,7 @@ func (s *slogLogger) Logf(ctx context.Context, lvl logger.Level, msg string, att
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Info(ctx context.Context, attrs ...interface{}) {
|
func (s *slogLogger) Info(ctx context.Context, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.InfoLevel.String()).Inc()
|
||||||
if !s.V(logger.InfoLevel) {
|
if !s.V(logger.InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -249,6 +253,7 @@ func (s *slogLogger) Info(ctx context.Context, attrs ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Infof(ctx context.Context, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Infof(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.InfoLevel.String()).Inc()
|
||||||
if !s.V(logger.InfoLevel) {
|
if !s.V(logger.InfoLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -270,6 +275,7 @@ func (s *slogLogger) Infof(ctx context.Context, msg string, attrs ...interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Debug(ctx context.Context, attrs ...interface{}) {
|
func (s *slogLogger) Debug(ctx context.Context, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.DebugLevel.String()).Inc()
|
||||||
if !s.V(logger.DebugLevel) {
|
if !s.V(logger.DebugLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -291,6 +297,7 @@ func (s *slogLogger) Debug(ctx context.Context, attrs ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Debugf(ctx context.Context, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Debugf(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.DebugLevel.String()).Inc()
|
||||||
if !s.V(logger.DebugLevel) {
|
if !s.V(logger.DebugLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -312,6 +319,7 @@ func (s *slogLogger) Debugf(ctx context.Context, msg string, attrs ...interface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Trace(ctx context.Context, attrs ...interface{}) {
|
func (s *slogLogger) Trace(ctx context.Context, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.TraceLevel.String()).Inc()
|
||||||
if !s.V(logger.TraceLevel) {
|
if !s.V(logger.TraceLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -333,6 +341,7 @@ func (s *slogLogger) Trace(ctx context.Context, attrs ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Tracef(ctx context.Context, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Tracef(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.TraceLevel.String()).Inc()
|
||||||
if !s.V(logger.TraceLevel) {
|
if !s.V(logger.TraceLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -354,6 +363,7 @@ func (s *slogLogger) Tracef(ctx context.Context, msg string, attrs ...interface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Error(ctx context.Context, attrs ...interface{}) {
|
func (s *slogLogger) Error(ctx context.Context, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.ErrorLevel.String()).Inc()
|
||||||
if !s.V(logger.ErrorLevel) {
|
if !s.V(logger.ErrorLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -393,6 +403,7 @@ func (s *slogLogger) Error(ctx context.Context, attrs ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Errorf(ctx context.Context, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Errorf(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.ErrorLevel.String()).Inc()
|
||||||
if !s.V(logger.ErrorLevel) {
|
if !s.V(logger.ErrorLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -432,6 +443,7 @@ func (s *slogLogger) Errorf(ctx context.Context, msg string, attrs ...interface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Fatal(ctx context.Context, attrs ...interface{}) {
|
func (s *slogLogger) Fatal(ctx context.Context, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.FatalLevel.String()).Inc()
|
||||||
if !s.V(logger.FatalLevel) {
|
if !s.V(logger.FatalLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -454,6 +466,7 @@ func (s *slogLogger) Fatal(ctx context.Context, attrs ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Fatalf(ctx context.Context, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Fatalf(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.FatalLevel.String()).Inc()
|
||||||
if !s.V(logger.FatalLevel) {
|
if !s.V(logger.FatalLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -476,6 +489,7 @@ func (s *slogLogger) Fatalf(ctx context.Context, msg string, attrs ...interface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Warn(ctx context.Context, attrs ...interface{}) {
|
func (s *slogLogger) Warn(ctx context.Context, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.WarnLevel.String()).Inc()
|
||||||
if !s.V(logger.WarnLevel) {
|
if !s.V(logger.WarnLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -497,6 +511,7 @@ func (s *slogLogger) Warn(ctx context.Context, attrs ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *slogLogger) Warnf(ctx context.Context, msg string, attrs ...interface{}) {
|
func (s *slogLogger) Warnf(ctx context.Context, msg string, attrs ...interface{}) {
|
||||||
|
s.opts.Meter.Counter(semconv.LoggerMessageTotal, "level", logger.WarnLevel.String()).Inc()
|
||||||
if !s.V(logger.WarnLevel) {
|
if !s.V(logger.WarnLevel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,13 @@ var (
|
|||||||
DefaultSummaryQuantiles = []float64{0.5, 0.9, 0.97, 0.99, 1}
|
DefaultSummaryQuantiles = []float64{0.5, 0.9, 0.97, 0.99, 1}
|
||||||
// DefaultSummaryWindow is the default window for summary
|
// DefaultSummaryWindow is the default window for summary
|
||||||
DefaultSummaryWindow = 5 * time.Minute
|
DefaultSummaryWindow = 5 * time.Minute
|
||||||
|
// DefaultSkipEndpoints is the slice of endpoint that must not be metered
|
||||||
|
DefaultSkipEndpoints = []string{
|
||||||
|
"MeterService.Metrics",
|
||||||
|
"HealthService.Live",
|
||||||
|
"HealthService.Ready",
|
||||||
|
"HealthService.Version",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Meter is an interface for collecting and instrumenting metrics
|
// Meter is an interface for collecting and instrumenting metrics
|
||||||
|
@@ -2,8 +2,6 @@ package meter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option powers the configuration for metrics implementations:
|
// Option powers the configuration for metrics implementations:
|
||||||
@@ -11,8 +9,6 @@ type Option func(*Options)
|
|||||||
|
|
||||||
// Options for metrics implementations
|
// Options for metrics implementations
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// Logger used for logging
|
|
||||||
Logger logger.Logger
|
|
||||||
// Context holds external options
|
// Context holds external options
|
||||||
Context context.Context
|
Context context.Context
|
||||||
// Name holds the meter name
|
// Name holds the meter name
|
||||||
@@ -39,7 +35,6 @@ func NewOptions(opt ...Option) Options {
|
|||||||
Address: DefaultAddress,
|
Address: DefaultAddress,
|
||||||
Path: DefaultPath,
|
Path: DefaultPath,
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
Logger: logger.DefaultLogger,
|
|
||||||
MetricPrefix: DefaultMetricPrefix,
|
MetricPrefix: DefaultMetricPrefix,
|
||||||
LabelPrefix: DefaultLabelPrefix,
|
LabelPrefix: DefaultLabelPrefix,
|
||||||
}
|
}
|
||||||
@@ -95,13 +90,6 @@ func TimingObjectives(value map[float64]float64) Option {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Logger sets the logger
|
|
||||||
func Logger(l logger.Logger) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Logger = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Labels sets the meter labels
|
// Labels sets the meter labels
|
||||||
func Labels(ls ...string) Option {
|
func Labels(ls ...string) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
|
10
options.go
10
options.go
@@ -269,15 +269,7 @@ func Logger(l logger.Logger, opts ...LoggerOption) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, mtr := range o.Meters {
|
|
||||||
for _, or := range lopts.meters {
|
|
||||||
if mtr.Name() == or || all {
|
|
||||||
if err = mtr.Init(meter.Logger(l)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, trc := range o.Tracers {
|
for _, trc := range o.Tracers {
|
||||||
for _, ot := range lopts.tracers {
|
for _, ot := range lopts.tracers {
|
||||||
if trc.Name() == ot || all {
|
if trc.Name() == ot || all {
|
||||||
|
4
semconv/logger.go
Normal file
4
semconv/logger.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
package semconv
|
||||||
|
|
||||||
|
// LoggerMessageTotal specifies meter metric name for logger messages
|
||||||
|
var LoggerMessageTotal = "logger_message_total"
|
@@ -83,8 +83,11 @@ func (sk SpanKind) String() string {
|
|||||||
|
|
||||||
// SpanOptions contains span option
|
// SpanOptions contains span option
|
||||||
type SpanOptions struct {
|
type SpanOptions struct {
|
||||||
Labels []interface{}
|
StatusMsg string
|
||||||
Kind SpanKind
|
Labels []interface{}
|
||||||
|
Status SpanStatus
|
||||||
|
Kind SpanKind
|
||||||
|
Record bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpanOption func signature
|
// SpanOption func signature
|
||||||
@@ -110,12 +113,25 @@ func WithSpanLabels(kv ...interface{}) SpanOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithSpanStatus(st SpanStatus, msg string) SpanOption {
|
||||||
|
return func(o *SpanOptions) {
|
||||||
|
o.Status = st
|
||||||
|
o.StatusMsg = msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WithSpanKind(k SpanKind) SpanOption {
|
func WithSpanKind(k SpanKind) SpanOption {
|
||||||
return func(o *SpanOptions) {
|
return func(o *SpanOptions) {
|
||||||
o.Kind = k
|
o.Kind = k
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithSpanRecord(b bool) SpanOption {
|
||||||
|
return func(o *SpanOptions) {
|
||||||
|
o.Record = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Options struct
|
// Options struct
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// Context used to store custome tracer options
|
// Context used to store custome tracer options
|
||||||
@@ -148,7 +164,8 @@ func NewEventOptions(opts ...EventOption) EventOptions {
|
|||||||
// NewSpanOptions returns default SpanOptions
|
// NewSpanOptions returns default SpanOptions
|
||||||
func NewSpanOptions(opts ...SpanOption) SpanOptions {
|
func NewSpanOptions(opts ...SpanOption) SpanOptions {
|
||||||
options := SpanOptions{
|
options := SpanOptions{
|
||||||
Kind: SpanKindInternal,
|
Kind: SpanKindInternal,
|
||||||
|
Record: true,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
|
@@ -7,14 +7,20 @@ import (
|
|||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v3/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultTracer is the global default tracer
|
|
||||||
var DefaultTracer Tracer = NewTracer()
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// DefaultTracer is the global default tracer
|
||||||
|
DefaultTracer Tracer = NewTracer() //nolint:revive
|
||||||
// TraceIDKey is the key used for the trace id in the log call
|
// TraceIDKey is the key used for the trace id in the log call
|
||||||
TraceIDKey = "trace-id"
|
TraceIDKey = "trace-id"
|
||||||
// SpanIDKey is the key used for the span id in the log call
|
// SpanIDKey is the key used for the span id in the log call
|
||||||
SpanIDKey = "span-id"
|
SpanIDKey = "span-id"
|
||||||
|
// DefaultSkipEndpoints is the slice of endpoint that must not be traced
|
||||||
|
DefaultSkipEndpoints = []string{
|
||||||
|
"MeterService.Metrics",
|
||||||
|
"HealthService.Live",
|
||||||
|
"HealthService.Ready",
|
||||||
|
"HealthService.Version",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -38,6 +44,8 @@ type Tracer interface {
|
|||||||
Init(...Option) error
|
Init(...Option) error
|
||||||
// Start a trace
|
// Start a trace
|
||||||
Start(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span)
|
Start(ctx context.Context, name string, opts ...SpanOption) (context.Context, Span)
|
||||||
|
// Extract get span metadata from context
|
||||||
|
// Extract(ctx context.Context)
|
||||||
// Flush flushes spans
|
// Flush flushes spans
|
||||||
Flush(ctx context.Context) error
|
Flush(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,48 @@ type StructField struct {
|
|||||||
Field reflect.StructField
|
Field reflect.StructField
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StructFieldNameByTag get struct field name by tag key and its value
|
||||||
|
func StructFieldNameByTag(src interface{}, tkey string, tval string) (string, interface{}, error) {
|
||||||
|
sv := reflect.ValueOf(src)
|
||||||
|
if sv.Kind() == reflect.Ptr {
|
||||||
|
sv = sv.Elem()
|
||||||
|
}
|
||||||
|
if sv.Kind() != reflect.Struct {
|
||||||
|
return "", nil, ErrInvalidStruct
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := sv.Type()
|
||||||
|
for idx := 0; idx < typ.NumField(); idx++ {
|
||||||
|
fld := typ.Field(idx)
|
||||||
|
val := sv.Field(idx)
|
||||||
|
if len(fld.PkgPath) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ts, ok := fld.Tag.Lookup(tkey); ok {
|
||||||
|
for _, p := range strings.Split(ts, ",") {
|
||||||
|
if p == tval {
|
||||||
|
return fld.Name, val.Interface(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if val = val.Elem(); val.Kind() == reflect.Struct {
|
||||||
|
if name, fld, err := StructFieldNameByTag(val.Interface(), tkey, tval); err == nil {
|
||||||
|
return name, fld, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
if name, fld, err := StructFieldNameByTag(val.Interface(), tkey, tval); err == nil {
|
||||||
|
return name, fld, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil, ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
// StructFieldByTag get struct field by tag key and its value
|
// StructFieldByTag get struct field by tag key and its value
|
||||||
func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, error) {
|
func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, error) {
|
||||||
sv := reflect.ValueOf(src)
|
sv := reflect.ValueOf(src)
|
||||||
@@ -69,10 +111,21 @@ func StructFieldByTag(src interface{}, tkey string, tval string) (interface{}, e
|
|||||||
|
|
||||||
// ZeroFieldByPath clean struct field by its path
|
// ZeroFieldByPath clean struct field by its path
|
||||||
func ZeroFieldByPath(src interface{}, path string) error {
|
func ZeroFieldByPath(src interface{}, path string) error {
|
||||||
|
if src == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
val := reflect.ValueOf(src)
|
val := reflect.ValueOf(src)
|
||||||
|
|
||||||
|
if IsEmpty(val) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range strings.Split(path, ".") {
|
for _, p := range strings.Split(path, ".") {
|
||||||
|
if IsEmpty(val) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
val, err = structValueByName(val, p)
|
val, err = structValueByName(val, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Reference in New Issue
Block a user