李伟乐 12 months ago
parent d2ef5ae759
commit d031cbb7b9
  1. 2
      api/user_http.pb.go
  2. 2
      cmd/mysql-kit/core/template.go
  3. 1
      constants/middleware.go
  4. 0
      core/mapping/mapping.go
  5. 24
      core/mathx/entropy.go
  6. 15
      core/mathx/int.go
  7. 25
      core/mathx/proba.go
  8. 39
      core/mathx/unstable.go
  9. 12
      core/rescue/recover.go
  10. 0
      core/stringx/stringx.go
  11. 0
      core/stringx/stringx_test.go
  12. 34
      core/syncx/atomicbool.go
  13. 0
      core/syncx/atomicduration.go
  14. 0
      core/syncx/resourcemanager.go
  15. 0
      core/syncx/singleflight.go
  16. 8
      core/sysx/automaxprocs.go
  17. 22
      core/sysx/host.go
  18. 11
      core/sysx/host_test.go
  19. 29
      core/threading/routinegroup.go
  20. 24
      core/threading/routines.go
  21. 26
      core/threading/taskrunner.go
  22. 20
      core/threading/workergroup.go
  23. 0
      core/timex/relativetime.go
  24. 11
      core/timex/repr.go
  25. 73
      core/timex/ticker.go
  26. 117
      core/trace/agent.go
  27. 76
      core/trace/agent_test.go
  28. 40
      core/trace/attributes.go
  29. 12
      core/trace/attributes_test.go
  30. 12
      core/trace/config.go
  31. 38
      core/trace/message.go
  32. 73
      core/trace/message_test.go
  33. 11
      core/trace/propagation.go
  34. 56
      core/trace/tracer.go
  35. 356
      core/trace/tracer_test.go
  36. 90
      core/trace/utils.go
  37. 204
      core/trace/utils_test.go
  38. 8
      core/trace/vars.go
  39. 26
      example/main.go
  40. 60
      go.mod
  41. 134
      go.sum
  42. 11
      internal/devserver/config.go
  43. 73
      internal/devserver/server.go
  44. 65
      internal/encoding/encoding.go
  45. 109
      internal/health/health.go
  46. 7
      internal/matcher/matcher.go
  47. 21
      internal/trace/trace.go
  48. 4
      middleware/cors/cors.go
  49. 2
      mysql/builder/builder.go
  50. 2
      mysql/sqlx/orm.go
  51. 2
      mysql/sqlx/sqlmanager.go
  52. 2
      mysql/sqlx/utils.go
  53. 4
      transport/http/router.go

@ -2,8 +2,8 @@ package user
import (
"context"
"git.diulo.com/mogfee/kit/middleware/jwt"
"git.diulo.com/mogfee/kit/transport/http"
"git.diulo.com/mogfee/kit/middleware/jwt"
)
type UserHTTPServer interface {

@ -2,8 +2,8 @@ package core
import (
"fmt"
"git.diulo.com/mogfee/kit/core/stringx"
"git.diulo.com/mogfee/kit/mysql/ddl"
"git.diulo.com/mogfee/kit/stringx"
"html/template"
"io"
"strings"

@ -1 +0,0 @@
package constants

@ -0,0 +1,24 @@
package mathx
import "math"
const epsilon = 1e-6
func CalcEntropy(m map[any]int) float64 {
if len(m) == 0 || len(m) == 1 {
return 1
}
var entropy float64
var total int
for _, v := range m {
total += v
}
for _, v := range m {
probe := float64(v) / float64(total)
if probe < epsilon {
probe = epsilon
}
entropy -= probe * math.Log2(probe)
}
return entropy / math.Log2(float64(len(m)))
}

@ -0,0 +1,15 @@
package mathx
func MaxInt(a, b int) int {
if a > b {
return a
}
return b
}
func MinInt(a, b int) int {
if a < b {
return a
}
return b
}

@ -0,0 +1,25 @@
package mathx
import (
"math/rand"
"sync"
"time"
)
type Probe struct {
r *rand.Rand
lock sync.Mutex
}
func NewProbe() *Probe {
return &Probe{
r: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
func (p *Probe) TrueOnProbe(probe float64) bool {
p.lock.Lock()
truth := p.r.Float64() < probe
p.lock.Unlock()
return truth
}

@ -0,0 +1,39 @@
package mathx
import (
"math/rand"
"sync"
"time"
)
type Unstable struct {
deviation float64
r *rand.Rand
lock *sync.Mutex
}
func NewUnstable(deviation float64) Unstable {
if deviation < 0 {
deviation = 0
}
if deviation > 1 {
deviation = 1
}
return Unstable{
deviation: deviation,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
lock: new(sync.Mutex),
}
}
func (u Unstable) AroundDuration(base time.Duration) time.Duration {
u.lock.Lock()
val := time.Duration((1 + u.deviation - 2*u.deviation*u.r.Float64()) * float64(base))
u.lock.Unlock()
return val
}
func (u Unstable) AroundInt(base int64) int64 {
u.lock.Lock()
val := int64((1 + u.deviation - 2*u.deviation*u.r.Float64()) * float64(base))
u.lock.Unlock()
return val
}

@ -0,0 +1,12 @@
package rescue
import "git.diulo.com/mogfee/kit/core/logx"
func Recover(cleanups ...func()) {
for _, cleanup := range cleanups {
cleanup()
}
if p := recover(); p != nil {
logx.ErrorStack(p)
}
}

@ -0,0 +1,34 @@
package syncx
import "sync/atomic"
type AtomicBool uint32
func NewAtomicBool() *AtomicBool {
return new(AtomicBool)
}
func ForAtomicBool(val bool) *AtomicBool {
b := NewAtomicBool()
b.Set(val)
return b
}
func (b *AtomicBool) CompareAndSwap(old, val bool) bool {
var ov, nv uint32
if old {
ov = 1
}
if val {
nv = 1
}
return atomic.CompareAndSwapUint32((*uint32)(b), ov, nv)
}
func (b *AtomicBool) Set(v bool) {
if v {
atomic.StoreUint32((*uint32)(b), 1)
} else {
atomic.StoreUint32((*uint32)(b), 0)
}
}
func (b *AtomicBool) True() bool {
return atomic.LoadUint32((*uint32)(b)) == 1
}

@ -0,0 +1,8 @@
package sysx
import "go.uber.org/automaxprocs/maxprocs"
// Automatically set GOMAXPROCS to match Linux container CPU quota.
func init() {
maxprocs.Set(maxprocs.Logger(nil))
}

@ -0,0 +1,22 @@
package sysx
import (
"os"
"github.com/zeromicro/go-zero/core/stringx"
)
var hostname string
func init() {
var err error
hostname, err = os.Hostname()
if err != nil {
hostname = stringx.RandId()
}
}
// Hostname returns the name of the host, if no hostname, a random id is returned.
func Hostname() string {
return hostname
}

@ -0,0 +1,11 @@
package sysx
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestHostname(t *testing.T) {
assert.True(t, len(Hostname()) > 0)
}

@ -0,0 +1,29 @@
package threading
import "sync"
type RoutineGroup struct {
waitGroup sync.WaitGroup
}
func NewRoutineGroup() *RoutineGroup {
return new(RoutineGroup)
}
func (g *RoutineGroup) Run(fn func()) {
g.waitGroup.Add(1)
go func() {
defer g.waitGroup.Done()
fn()
}()
}
func (g *RoutineGroup) RunSafe(fn func()) {
g.waitGroup.Add(1)
GoSafe(func() {
defer g.waitGroup.Done()
fn()
})
}
func (g *RoutineGroup) Wait() {
g.waitGroup.Wait()
}

@ -0,0 +1,24 @@
package threading
import (
"bytes"
"git.diulo.com/mogfee/kit/core/rescue"
"runtime"
"strconv"
)
func GoSafe(fn func()) {
go RunSafe(fn)
}
func RoutineId() uint64 {
b := make([]byte, 64)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, _ := strconv.ParseUint(string(b), 10, 64)
return n
}
func RunSafe(fn func()) {
defer rescue.Recover()
fn()
}

@ -0,0 +1,26 @@
package threading
import (
"git.diulo.com/mogfee/kit/core/rescue"
"git.diulo.com/mogfee/kit/lang"
)
type TaskRunner struct {
limitChan chan lang.PlaceholderType
}
func NewTaskRunner(concurrency int) *TaskRunner {
return &TaskRunner{
limitChan: make(chan lang.PlaceholderType, concurrency),
}
}
func (r *TaskRunner) Schedule(task func()) {
r.limitChan <- lang.Placeholder
go func() {
defer rescue.Recover(func() {
<-r.limitChan
})
task()
}()
}

@ -0,0 +1,20 @@
package threading
type WorkerGroup struct {
job func()
workers int
}
func NewWorkerGroup(job func(), works int) *WorkerGroup {
return &WorkerGroup{
job: job,
workers: works,
}
}
func (wg WorkerGroup) Start() {
group := NewRoutineGroup()
for i := 0; i < wg.workers; i++ {
group.RunSafe(wg.job)
}
group.Wait()
}

@ -0,0 +1,11 @@
package timex
import (
"fmt"
"time"
)
// ReprOfDuration returns the string representation of given duration in ms.
func ReprOfDuration(duration time.Duration) string {
return fmt.Sprintf("%.1fms", float32(duration)/float32(time.Millisecond))
}

@ -0,0 +1,73 @@
package timex
import (
"errors"
"git.diulo.com/mogfee/kit/lang"
"time"
)
var errTimeout = errors.New("timeout")
type (
Ticker interface {
Chan() <-chan time.Time
Stop()
}
FakeTicker interface {
Ticker
Done()
Tick()
Wait(d time.Duration) error
}
fakeTicker struct {
c chan time.Time
done chan lang.PlaceholderType
}
realTicker struct {
*time.Ticker
}
)
func NewTicker(d time.Duration) Ticker {
return &realTicker{
Ticker: time.NewTicker(d),
}
}
func (r *realTicker) Chan() <-chan time.Time {
return r.C
}
func NewFakeTicker() FakeTicker {
return &fakeTicker{
c: make(chan time.Time, 1),
done: make(chan lang.PlaceholderType, 1),
}
}
func (f *fakeTicker) Chan() <-chan time.Time {
return f.c
}
func (f *fakeTicker) Stop() {
close(f.c)
}
func (f *fakeTicker) Done() {
f.done <- lang.Placeholder
}
func (f *fakeTicker) Tick() {
f.c <- time.Now()
}
func (f *fakeTicker) Wait(d time.Duration) error {
select {
case <-time.After(d):
return errTimeout
case <-f.done:
return nil
}
}

@ -0,0 +1,117 @@
package trace
import (
"context"
"fmt"
"net/url"
"sync"
"github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/logx"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/jaeger"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/exporters/zipkin"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)
const (
kindJaeger = "jaeger"
kindZipkin = "zipkin"
kindOtlpGrpc = "otlpgrpc"
kindOtlpHttp = "otlphttp"
)
var (
agents = make(map[string]lang.PlaceholderType)
lock sync.Mutex
tp *sdktrace.TracerProvider
)
// StartAgent starts an opentelemetry agent.
func StartAgent(c Config) {
lock.Lock()
defer lock.Unlock()
_, ok := agents[c.Endpoint]
if ok {
return
}
// if error happens, let later calls run.
if err := startAgent(c); err != nil {
return
}
agents[c.Endpoint] = lang.Placeholder
}
// StopAgent shuts down the span processors in the order they were registered.
func StopAgent() {
_ = tp.Shutdown(context.Background())
}
func createExporter(c Config) (sdktrace.SpanExporter, error) {
// Just support jaeger and zipkin now, more for later
switch c.Batcher {
case kindJaeger:
u, _ := url.Parse(c.Endpoint)
if u.Scheme == "udp" {
return jaeger.New(jaeger.WithAgentEndpoint(jaeger.WithAgentHost(u.Hostname()), jaeger.WithAgentPort(u.Port())))
}
return jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(c.Endpoint)))
case kindZipkin:
return zipkin.New(c.Endpoint)
case kindOtlpGrpc:
// Always treat trace exporter as optional component, so we use nonblock here,
// otherwise this would slow down app start up even set a dial timeout here when
// endpoint can not reach.
// If the connection not dial success, the global otel ErrorHandler will catch error
// when reporting data like other exporters.
return otlptracegrpc.New(
context.Background(),
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint(c.Endpoint),
)
case kindOtlpHttp:
// Not support flexible configuration now.
return otlptracehttp.New(
context.Background(),
otlptracehttp.WithInsecure(),
otlptracehttp.WithEndpoint(c.Endpoint),
)
default:
return nil, fmt.Errorf("unknown exporter: %s", c.Batcher)
}
}
func startAgent(c Config) error {
opts := []sdktrace.TracerProviderOption{
// Set the sampling rate based on the parent span to 100%
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(c.Sampler))),
// Record information about this application in a Resource.
sdktrace.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String(c.Name))),
}
if len(c.Endpoint) > 0 {
exp, err := createExporter(c)
if err != nil {
logx.Error(err)
return err
}
// Always be sure to batch in production.
opts = append(opts, sdktrace.WithBatcher(exp))
}
tp = sdktrace.NewTracerProvider(opts...)
otel.SetTracerProvider(tp)
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
logx.Errorf("[otel] error: %v", err)
}))
return nil
}

@ -0,0 +1,76 @@
package trace
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
)
func TestStartAgent(t *testing.T) {
logx.Disable()
const (
endpoint1 = "localhost:1234"
endpoint2 = "remotehost:1234"
endpoint3 = "localhost:1235"
endpoint4 = "localhost:1236"
endpoint5 = "udp://localhost:6831"
)
c1 := Config{
Name: "foo",
}
c2 := Config{
Name: "bar",
Endpoint: endpoint1,
Batcher: kindJaeger,
}
c3 := Config{
Name: "any",
Endpoint: endpoint2,
Batcher: kindZipkin,
}
c4 := Config{
Name: "bla",
Endpoint: endpoint3,
Batcher: "otlp",
}
c5 := Config{
Name: "grpc",
Endpoint: endpoint3,
Batcher: kindOtlpGrpc,
}
c6 := Config{
Name: "otlphttp",
Endpoint: endpoint4,
Batcher: kindOtlpHttp,
}
c7 := Config{
Name: "UDP",
Endpoint: endpoint5,
Batcher: kindJaeger,
}
StartAgent(c1)
StartAgent(c1)
StartAgent(c2)
StartAgent(c3)
StartAgent(c4)
StartAgent(c5)
StartAgent(c6)
StartAgent(c7)
lock.Lock()
defer lock.Unlock()
// because remotehost cannot be resolved
assert.Equal(t, 5, len(agents))
_, ok := agents[""]
assert.True(t, ok)
_, ok = agents[endpoint1]
assert.True(t, ok)
_, ok = agents[endpoint2]
assert.False(t, ok)
_, ok = agents[endpoint5]
assert.True(t, ok)
}

@ -0,0 +1,40 @@
package trace
import (
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
gcodes "google.golang.org/grpc/codes"
)
const (
// GRPCStatusCodeKey is convention for numeric status code of a gRPC request.
GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code")
// RPCNameKey is the name of message transmitted or received.
RPCNameKey = attribute.Key("name")
// RPCMessageTypeKey is the type of message transmitted or received.
RPCMessageTypeKey = attribute.Key("message.type")
// RPCMessageIDKey is the identifier of message transmitted or received.
RPCMessageIDKey = attribute.Key("message.id")
// RPCMessageCompressedSizeKey is the compressed size of the message transmitted or received in bytes.
RPCMessageCompressedSizeKey = attribute.Key("message.compressed_size")
// RPCMessageUncompressedSizeKey is the uncompressed size of the message
// transmitted or received in bytes.
RPCMessageUncompressedSizeKey = attribute.Key("message.uncompressed_size")
)
// Semantic conventions for common RPC attributes.
var (
// RPCSystemGRPC is the semantic convention for gRPC as the remoting system.
RPCSystemGRPC = semconv.RPCSystemKey.String("grpc")
// RPCNameMessage is the semantic convention for a message named message.
RPCNameMessage = RPCNameKey.String("message")
// RPCMessageTypeSent is the semantic conventions for sent RPC message types.
RPCMessageTypeSent = RPCMessageTypeKey.String("SENT")
// RPCMessageTypeReceived is the semantic conventions for the received RPC message types.
RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED")
)
// StatusCodeAttr returns an attribute.KeyValue that represents the give c.
func StatusCodeAttr(c gcodes.Code) attribute.KeyValue {
return GRPCStatusCodeKey.Int64(int64(c))
}

@ -0,0 +1,12 @@
package trace
import (
"testing"
"github.com/stretchr/testify/assert"
gcodes "google.golang.org/grpc/codes"
)
func TestStatusCodeAttr(t *testing.T) {
assert.Equal(t, GRPCStatusCodeKey.Int(int(gcodes.DataLoss)), StatusCodeAttr(gcodes.DataLoss))
}

@ -0,0 +1,12 @@
package trace
// TraceName represents the tracing name.
const TraceName = "go-zero"
// A Config is an opentelemetry config.
type Config struct {
Name string `json:",optional"`
Endpoint string `json:",optional"`
Sampler float64 `json:",default=1.0"`
Batcher string `json:",default=jaeger,options=jaeger|zipkin|otlpgrpc|otlphttp"`
}

@ -0,0 +1,38 @@
package trace
import (
"context"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/proto"
)
const messageEvent = "message"
var (
// MessageSent is the type of sent messages.
MessageSent = messageType(RPCMessageTypeSent)
// MessageReceived is the type of received messages.
MessageReceived = messageType(RPCMessageTypeReceived)
)
type messageType attribute.KeyValue
// Event adds an event of the messageType to the span associated with the
// passed context with id and size (if message is a proto message).
func (m messageType) Event(ctx context.Context, id int, message any) {
span := trace.SpanFromContext(ctx)
if p, ok := message.(proto.Message); ok {
span.AddEvent(messageEvent, trace.WithAttributes(
attribute.KeyValue(m),
RPCMessageIDKey.Int(id),
RPCMessageUncompressedSizeKey.Int(proto.Size(p)),
))
} else {
span.AddEvent(messageEvent, trace.WithAttributes(
attribute.KeyValue(m),
RPCMessageIDKey.Int(id),
))
}
}

@ -0,0 +1,73 @@
package trace
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/dynamicpb"
)
func TestMessageType_Event(t *testing.T) {
var span mockSpan
ctx := trace.ContextWithSpan(context.Background(), &span)
MessageReceived.Event(ctx, 1, "foo")
assert.Equal(t, messageEvent, span.name)
assert.NotEmpty(t, span.options)
}
func TestMessageType_EventProtoMessage(t *testing.T) {
var span mockSpan
var message mockMessage
ctx := trace.ContextWithSpan(context.Background(), &span)
MessageReceived.Event(ctx, 1, message)
assert.Equal(t, messageEvent, span.name)
assert.NotEmpty(t, span.options)
}
type mockSpan struct {
name string
options []trace.EventOption
}
func (m *mockSpan) End(options ...trace.SpanEndOption) {
}
func (m *mockSpan) AddEvent(name string, options ...trace.EventOption) {
m.name = name
m.options = options
}
func (m *mockSpan) IsRecording() bool {
return false
}
func (m *mockSpan) RecordError(err error, options ...trace.EventOption) {
}
func (m *mockSpan) SpanContext() trace.SpanContext {
panic("implement me")
}
func (m *mockSpan) SetStatus(code codes.Code, description string) {
}
func (m *mockSpan) SetName(name string) {
}
func (m *mockSpan) SetAttributes(kv ...attribute.KeyValue) {
}
func (m *mockSpan) TracerProvider() trace.TracerProvider {
return nil
}
type mockMessage struct{}
func (m mockMessage) ProtoReflect() protoreflect.Message {
return new(dynamicpb.Message)
}

@ -0,0 +1,11 @@
package trace
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
func init() {
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))
}

@ -0,0 +1,56 @@
package trace
import (
"context"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/metadata"
)
// assert that metadataSupplier implements the TextMapCarrier interface
var _ propagation.TextMapCarrier = (*metadataSupplier)(nil)
type metadataSupplier struct {
metadata *metadata.MD
}
func (s *metadataSupplier) Get(key string) string {
values := s.metadata.Get(key)
if len(values) == 0 {
return ""
}
return values[0]
}
func (s *metadataSupplier) Set(key, value string) {
s.metadata.Set(key, value)
}
func (s *metadataSupplier) Keys() []string {
out := make([]string, 0, len(*s.metadata))
for key := range *s.metadata {
out = append(out, key)
}
return out
}
// Inject injects cross-cutting concerns from the ctx into the metadata.
func Inject(ctx context.Context, p propagation.TextMapPropagator, metadata *metadata.MD) {
p.Inject(ctx, &metadataSupplier{
metadata: metadata,
})
}
// Extract extracts the metadata from ctx.
func Extract(ctx context.Context, p propagation.TextMapPropagator, metadata *metadata.MD) (
baggage.Baggage, sdktrace.SpanContext) {
ctx = p.Extract(ctx, &metadataSupplier{
metadata: metadata,
})
return baggage.FromContext(ctx), sdktrace.SpanContextFromContext(ctx)
}

@ -0,0 +1,356 @@
package trace
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/metadata"
)
const (
traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736"
spanIDStr = "00f067aa0ba902b7"
)
var (
traceID = mustTraceIDFromHex(traceIDStr)
spanID = mustSpanIDFromHex(spanIDStr)
)
func mustTraceIDFromHex(s string) (t trace.TraceID) {
var err error
t, err = trace.TraceIDFromHex(s)
if err != nil {
panic(err)
}
return
}
func mustSpanIDFromHex(s string) (t trace.SpanID) {
var err error
t, err = trace.SpanIDFromHex(s)
if err != nil {
panic(err)
}
return
}
func TestExtractValidTraceContext(t *testing.T) {
stateStr := "key1=value1,key2=value2"
state, err := trace.ParseTraceState(stateStr)
require.NoError(t, err)
tests := []struct {
name string
traceparent string
tracestate string
sc trace.SpanContext
}{
{
name: "not sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "valid tracestate",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
tracestate: stateStr,
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceState: state,
Remote: true,
}),
},
{
name: "invalid tracestate perserves traceparent",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
tracestate: "invalid$@#=invalid",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version not sampled",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version sampled",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "future version sample bit set",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "future version sample bit not set",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version additional data",
traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-XYZxsf09",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "B3 format ending in dash",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "future version B3 format ending in dash",
traceparent: "03-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
md := metadata.MD{}
md.Set("traceparent", tt.traceparent)
md.Set("tracestate", tt.tracestate)
_, spanCtx := Extract(ctx, propagator, &md)
assert.Equal(t, tt.sc, spanCtx)
})
}
}
func TestExtractInvalidTraceContext(t *testing.T) {
tests := []struct {
name string
header string
}{
{
name: "wrong version length",
header: "0000-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "wrong trace ID length",
header: "00-ab00000000000000000000000000000000-cd00000000000000-01",
},
{
name: "wrong span ID length",
header: "00-ab000000000000000000000000000000-cd0000000000000000-01",
},
{
name: "wrong trace flag length",
header: "00-ab000000000000000000000000000000-cd00000000000000-0100",
},
{
name: "bogus version",
header: "qw-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "bogus trace ID",
header: "00-qw000000000000000000000000000000-cd00000000000000-01",
},
{
name: "bogus span ID",
header: "00-ab000000000000000000000000000000-qw00000000000000-01",
},
{
name: "bogus trace flag",
header: "00-ab000000000000000000000000000000-cd00000000000000-qw",
},
{
name: "upper case version",
header: "A0-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "upper case trace ID",
header: "00-AB000000000000000000000000000000-cd00000000000000-01",
},
{
name: "upper case span ID",
header: "00-ab000000000000000000000000000000-CD00000000000000-01",
},
{
name: "upper case trace flag",
header: "00-ab000000000000000000000000000000-cd00000000000000-A1",
},
{
name: "zero trace ID and span ID",
header: "00-00000000000000000000000000000000-0000000000000000-01",
},
{
name: "trace-flag unused bits set",
header: "00-ab000000000000000000000000000000-cd00000000000000-09",
},
{
name: "missing options",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
},
{
name: "empty options",
header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
},
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
md := metadata.MD{}
md.Set("traceparent", tt.header)
_, spanCtx := Extract(ctx, propagator, &md)
assert.Equal(t, trace.SpanContext{}, spanCtx)
})
}
}
func TestInjectValidTraceContext(t *testing.T) {
stateStr := "key1=value1,key2=value2"
state, err := trace.ParseTraceState(stateStr)
require.NoError(t, err)
tests := []struct {
name string
traceparent string
tracestate string
sc trace.SpanContext
}{
{
name: "not sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
Remote: true,
}),
},
{
name: "sampled",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
Remote: true,
}),
},
{
name: "unsupported trace flag bits dropped",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceFlags: 0xff,
Remote: true,
}),
},
{
name: "with tracestate",
traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
tracestate: stateStr,
sc: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceID,
SpanID: spanID,
TraceState: state,
Remote: true,
}),
},
}
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
want := metadata.MD{}
want.Set("traceparent", tt.traceparent)
if len(tt.tracestate) > 0 {
want.Set("tracestate", tt.tracestate)
}
md := metadata.MD{}
Inject(ctx, propagator, &md)
assert.Equal(t, want, md)
mm := &metadataSupplier{
metadata: &md,
}
assert.NotEmpty(t, mm.Keys())
})
}
}
func TestInvalidSpanContextDropped(t *testing.T) {
invalidSC := trace.SpanContext{}
require.False(t, invalidSC.IsValid())
ctx := trace.ContextWithRemoteSpanContext(context.Background(), invalidSC)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{}, propagation.Baggage{}))
propagator := otel.GetTextMapPropagator()
md := metadata.MD{}
Inject(ctx, propagator, &md)
mm := &metadataSupplier{
metadata: &md,
}
assert.Empty(t, mm.Keys())
assert.Equal(t, "", mm.Get("traceparent"), "injected invalid SpanContext")
}

@ -0,0 +1,90 @@
package trace
import (
"context"
"net"
"strings"
ztrace "github.com/zeromicro/go-zero/internal/trace"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/peer"
)
const localhost = "127.0.0.1"
var (
// SpanIDFromContext returns the span id from ctx.
SpanIDFromContext = ztrace.SpanIDFromContext
// TraceIDFromContext returns the trace id from ctx.
TraceIDFromContext = ztrace.TraceIDFromContext
)
// ParseFullMethod returns the method name and attributes.
func ParseFullMethod(fullMethod string) (string, []attribute.KeyValue) {
name := strings.TrimLeft(fullMethod, "/")
parts := strings.SplitN(name, "/", 2)
if len(parts) != 2 {
// Invalid format, does not follow `/package.service/method`.
return name, []attribute.KeyValue(nil)
}
var attrs []attribute.KeyValue
if service := parts[0]; service != "" {
attrs = append(attrs, semconv.RPCServiceKey.String(service))
}
if method := parts[1]; method != "" {
attrs = append(attrs, semconv.RPCMethodKey.String(method))
}
return name, attrs
}
// PeerAttr returns the peer attributes.
func PeerAttr(addr string) []attribute.KeyValue {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil
}
if len(host) == 0 {
host = localhost
}
return []attribute.KeyValue{
semconv.NetPeerIPKey.String(host),
semconv.NetPeerPortKey.String(port),
}
}
// PeerFromCtx returns the peer from ctx.
func PeerFromCtx(ctx context.Context) string {
p, ok := peer.FromContext(ctx)
if !ok || p == nil {
return ""
}
return p.Addr.String()
}
// SpanInfo returns the span info.
func SpanInfo(fullMethod, peerAddress string) (string, []attribute.KeyValue) {
attrs := []attribute.KeyValue{RPCSystemGRPC}
name, mAttrs := ParseFullMethod(fullMethod)
attrs = append(attrs, mAttrs...)
attrs = append(attrs, PeerAttr(peerAddress)...)
return name, attrs
}
// TracerFromContext returns a tracer in ctx, otherwise returns a global tracer.
func TracerFromContext(ctx context.Context) (tracer trace.Tracer) {
if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() {
tracer = span.TracerProvider().Tracer(TraceName)
} else {
tracer = otel.Tracer(TraceName)
}
return
}

@ -0,0 +1,204 @@
package trace
import (
"context"
"net"
"testing"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/peer"
)
func TestPeerFromContext(t *testing.T) {
addrs, err := net.InterfaceAddrs()
assert.Nil(t, err)
assert.NotEmpty(t, addrs)
tests := []struct {
name string
ctx context.Context
empty bool
}{
{
name: "empty",
ctx: context.Background(),
empty: true,
},
{
name: "nil",
ctx: peer.NewContext(context.Background(), nil),
empty: true,
},
{
name: "with value",
ctx: peer.NewContext(context.Background(), &peer.Peer{
Addr: addrs[0],
}),
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
addr := PeerFromCtx(test.ctx)
assert.Equal(t, test.empty, len(addr) == 0)
})
}
}
func TestParseFullMethod(t *testing.T) {
tests := []struct {
fullMethod string
name string
attr []attribute.KeyValue
}{
{
fullMethod: "/grpc.test.EchoService/Echo",
name: "grpc.test.EchoService/Echo",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("grpc.test.EchoService"),
semconv.RPCMethodKey.String("Echo"),
},
}, {
fullMethod: "/com.example.ExampleRmiService/exampleMethod",
name: "com.example.ExampleRmiService/exampleMethod",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("com.example.ExampleRmiService"),
semconv.RPCMethodKey.String("exampleMethod"),
},
}, {
fullMethod: "/MyCalcService.Calculator/Add",
name: "MyCalcService.Calculator/Add",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("MyCalcService.Calculator"),
semconv.RPCMethodKey.String("Add"),
},
}, {
fullMethod: "/MyServiceReference.ICalculator/Add",
name: "MyServiceReference.ICalculator/Add",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("MyServiceReference.ICalculator"),
semconv.RPCMethodKey.String("Add"),
},
}, {
fullMethod: "/MyServiceWithNoPackage/theMethod",
name: "MyServiceWithNoPackage/theMethod",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("MyServiceWithNoPackage"),
semconv.RPCMethodKey.String("theMethod"),
},
}, {
fullMethod: "/pkg.svr",
name: "pkg.svr",
attr: []attribute.KeyValue(nil),
}, {
fullMethod: "/pkg.svr/",
name: "pkg.svr/",
attr: []attribute.KeyValue{
semconv.RPCServiceKey.String("pkg.svr"),
},
},
}
for _, test := range tests {
n, a := ParseFullMethod(test.fullMethod)
assert.Equal(t, test.name, n)
assert.Equal(t, test.attr, a)
}
}
func TestSpanInfo(t *testing.T) {
val, kvs := SpanInfo("/fullMethod", "remote")
assert.Equal(t, "fullMethod", val)
assert.NotEmpty(t, kvs)
}
func TestPeerAttr(t *testing.T) {
tests := []struct {
name string
addr string
expect []attribute.KeyValue
}{
{
name: "empty",
},
{
name: "port only",
addr: ":8080",
expect: []attribute.KeyValue{
semconv.NetPeerIPKey.String(localhost),
semconv.NetPeerPortKey.String("8080"),
},
},
{
name: "port only",
addr: "192.168.0.2:8080",
expect: []attribute.KeyValue{
semconv.NetPeerIPKey.String("192.168.0.2"),
semconv.NetPeerPortKey.String("8080"),
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
kvs := PeerAttr(test.addr)
assert.EqualValues(t, test.expect, kvs)
})
}
}
func TestTracerFromContext(t *testing.T) {
traceFn := func(ctx context.Context, hasTraceId bool) {
spanContext := trace.SpanContextFromContext(ctx)
assert.Equal(t, spanContext.IsValid(), hasTraceId)
parentTraceId := spanContext.TraceID().String()
tracer := TracerFromContext(ctx)
_, span := tracer.Start(ctx, "b")
defer span.End()
spanContext = span.SpanContext()
assert.True(t, spanContext.IsValid())
if hasTraceId {
assert.Equal(t, parentTraceId, spanContext.TraceID().String())
}
}
t.Run("context", func(t *testing.T) {
opts := []sdktrace.TracerProviderOption{
// Set the sampling rate based on the parent span to 100%
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(1))),
// Record information about this application in a Resource.
sdktrace.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String("test"))),
}
tp = sdktrace.NewTracerProvider(opts...)
otel.SetTracerProvider(tp)
ctx, span := tp.Tracer(TraceName).Start(context.Background(), "a")
defer span.End()
traceFn(ctx, true)
})
t.Run("global", func(t *testing.T) {
opts := []sdktrace.TracerProviderOption{
// Set the sampling rate based on the parent span to 100%
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(1))),
// Record information about this application in a Resource.
sdktrace.WithResource(resource.NewSchemaless(semconv.ServiceNameKey.String("test"))),
}
tp = sdktrace.NewTracerProvider(opts...)
otel.SetTracerProvider(tp)
traceFn(context.Background(), false)
})
}

@ -0,0 +1,8 @@
package trace
import "net/http"
// TraceIdKey is the trace id header.
// https://www.w3.org/TR/trace-context/#trace-id
// May change it to trace-id afterwards.
var TraceIdKey = http.CanonicalHeaderKey("x-trace-id")

@ -1,25 +1,39 @@
package main
import (
"context"
"flag"
"fmt"
"git.diulo.com/mogfee/kit"
user "git.diulo.com/mogfee/kit/api"
"git.diulo.com/mogfee/kit/example/service"
"git.diulo.com/mogfee/kit/middleware/jwt"
"git.diulo.com/mogfee/kit/middleware"
"git.diulo.com/mogfee/kit/transport/http"
)
func main() {
flag.Parse()
runApp("localhost:8080")
runApp("localhost:8998")
}
func runApp(host string) {
hs := http.NewServer(
http.Address(host),
http.Middleware(jwt.JWT(jwt.WithJwtKey("Jt6Zv!KTopXZ6S4C"))),
http.Middleware(func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, a any) (any, error) {
fmt.Println("middleare 1")
return handler(ctx, a)
}
}),
)
user.RegisterUserHTTPServer(hs, service.NewUserService("1234567890123456"))
hs.Use("/api/v2/user/me", func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, a any) (any, error) {
fmt.Println("use midd")
return handler(ctx, a)
}
})
r := hs.Route("")
r.GET("/api/v2/user/me", func(ctx http.Context) error {
fmt.Println("/api/v2/user/me")
return nil
})
app := kit.New(kit.Server(hs))
fmt.Println(app.Run())
fmt.Println(app.Stop())

@ -4,6 +4,8 @@ go 1.20
require (
github.com/antlr4-go/antlr/v4 v4.13.0
github.com/fatih/color v1.15.0
github.com/felixge/fgprof v0.9.3
github.com/gin-gonic/gin v1.9.0
github.com/go-playground/form v3.1.4+incompatible
github.com/go-sql-driver/mysql v1.7.1
@ -12,17 +14,27 @@ require (
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0
github.com/nsqio/go-nsq v1.1.0
github.com/pelletier/go-toml/v2 v2.0.9
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.16.0
github.com/spf13/cobra v1.7.0
go.etcd.io/etcd/client/v3 v3.5.7
go.opentelemetry.io/otel v1.17.0
github.com/stretchr/testify v1.8.4
github.com/zeromicro/go-zero v1.5.5
go.etcd.io/etcd/client/v3 v3.5.9
go.opentelemetry.io/otel v1.18.0
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.17.0
go.opentelemetry.io/otel/sdk v1.17.0
go.opentelemetry.io/otel/trace v1.17.0
golang.org/x/net v0.10.0
go.opentelemetry.io/otel/exporters/zipkin v1.18.0
go.opentelemetry.io/otel/sdk v1.18.0
go.opentelemetry.io/otel/trace v1.18.0
go.uber.org/automaxprocs v1.5.3
golang.org/x/net v0.14.0
golang.org/x/sync v0.3.0
google.golang.org/genproto v0.0.0-20230301171018-9ab4bdc49ad5
google.golang.org/grpc v1.53.0
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98
google.golang.org/grpc v1.58.0
google.golang.org/protobuf v1.31.0
gopkg.in/go-playground/assert.v1 v1.2.1
gopkg.in/yaml.v3 v3.0.1
@ -31,10 +43,12 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.8.3 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
@ -44,32 +58,38 @@ require (
github.com/goccy/go-json v0.10.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/openzipkin/zipkin-go v0.4.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.10 // indirect
go.etcd.io/etcd/api/v3 v3.5.7 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect
go.opentelemetry.io/otel/metric v1.17.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.17.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.9 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 // indirect
go.opentelemetry.io/otel/metric v1.18.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/arch v0.2.0 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/text v0.12.0 // indirect
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect
)

134
go.sum

@ -1,23 +1,33 @@
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.3 h1:pf6fGl5eqWYKkx1RcD4qpuX+BIUaduv/wTm5ekWJ80M=
github.com/bytedance/sonic v1.8.3/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
@ -45,10 +55,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.1 h1:tDQ1LjKga657layZ4JLsRdxgvupebc0xuPwRNuTfUgs=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@ -57,10 +66,15 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -70,10 +84,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
@ -85,13 +102,15 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=
github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA=
github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
@ -100,9 +119,11 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@ -118,44 +139,60 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.10 h1:eimT6Lsr+2lzmSZxPhLFoOWFmQqwk0fllJJ5hEbTXtQ=
github.com/ugorji/go/codec v1.2.10/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY=
go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA=
go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg=
go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY=
go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4=
go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw=
go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM=
go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0=
github.com/zeromicro/go-zero v1.5.5 h1:qEHnDuCBu/gDBmfWEZXYow6ZmWmzsrJTjtjSMVm4SiY=
github.com/zeromicro/go-zero v1.5.5/go.mod h1:AGCspTFitHzYjl5ddAmYWLfdt341+BrhefqlwO45UbU=
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4=
go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E=
go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA=
go.opentelemetry.io/otel v1.18.0 h1:TgVozPGZ01nHyDZxK5WGPFB9QexeTMXEH7+tIClWfzs=
go.opentelemetry.io/otel v1.18.0/go.mod h1:9lWqYO0Db579XzVuCKFNPDl4s73Voa+zEck3wHaAYQI=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0 h1:yE32ay7mJG2leczfREEhoW3VfSZIvHaB+gvVo1o8DQ8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.18.0/go.mod h1:G17FHPDLt74bCI7tJ4CMitEk4BXTYG4FW6XUpkPBXa4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 h1:6pu8ttx76BxHf+xz/H77AUZkPF3cwWzXqAUsXhVKI18=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0/go.mod h1:IOmXxPrxoxFMXdNy7lfDmE8MzE61YPcurbUm0SMjerI=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.17.0 h1:Ut6hgtYcASHwCzRHkXEtSsM251cXJPW+Z9DyLwEn6iI=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.17.0/go.mod h1:TYeE+8d5CjrgBa0ZuRaDeMpIC1xZ7atg4g+nInjuSjc=
go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc=
go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o=
go.opentelemetry.io/otel/sdk v1.17.0 h1:FLN2X66Ke/k5Sg3V623Q7h7nt3cHXaW1FOvKKrW0IpE=
go.opentelemetry.io/otel/sdk v1.17.0/go.mod h1:U87sE0f5vQB7hwUoW98pW5Rz4ZDuCFBZFNUBlSgmDFQ=
go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ=
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.opentelemetry.io/otel/exporters/zipkin v1.18.0 h1:ZqrHgvega5NIiScTiVrtpZSpEmjUdwzkhuuCEIMAp+s=
go.opentelemetry.io/otel/exporters/zipkin v1.18.0/go.mod h1:C80yIYcSceQipAZb4Ah11EE/yERlyc1MtqJG2xP7p+s=
go.opentelemetry.io/otel/metric v1.18.0 h1:JwVzw94UYmbx3ej++CwLUQZxEODDj/pOuTCvzhtRrSQ=
go.opentelemetry.io/otel/metric v1.18.0/go.mod h1:nNSpsVDjWGfb7chbRLUNW+PBNdcSTHD4Uu5pfFMOI0k=
go.opentelemetry.io/otel/sdk v1.18.0 h1:e3bAB0wB3MljH38sHzpV/qWrOTCFrdZF2ct9F8rBkcY=
go.opentelemetry.io/otel/sdk v1.18.0/go.mod h1:1RCygWV7plY2KmdskZEDDBs4tJeHG92MdHZIluiYs/M=
go.opentelemetry.io/otel/trace v1.18.0 h1:NY+czwbHbmndxojTEKiSMHkG2ClNH2PwmcHrdo0JY10=
go.opentelemetry.io/otel/trace v1.18.0/go.mod h1:T2+SGJGuYZY3bjj5rgh/hN7KIrlpWC5nS8Mjvzckz+0=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.2.0 h1:W1sUEHXiJTfjaFJ5SLo0N6lZn+0eO5gWD1MFeTGqQEY=
golang.org/x/arch v0.2.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -164,28 +201,26 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -194,24 +229,23 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230301171018-9ab4bdc49ad5 h1:/cadn7taPtPlCgiWNetEPsle7jgnlad2R7gR5MXB6dM=
google.golang.org/genproto v0.0.0-20230301171018-9ab4bdc49ad5/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g=
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o=
google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

@ -0,0 +1,11 @@
package devserver
type Config struct {
Enabled bool `json:",default=true"`
Host string `json:",optional"`
Port int `json:",default=6470"`
MetricsPath string `json:",default=/metrics"`
HealthPath string `json:",default=/healthz"`
EnableMetrics bool `json:",default=true"`
EnablePprof bool `json:",default=true"`
}

@ -0,0 +1,73 @@
package devserver
import (
"encoding/json"
"fmt"
"git.diulo.com/mogfee/kit/core/logx"
"git.diulo.com/mogfee/kit/internal/health"
"github.com/felixge/fgprof"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/zeromicro/go-zero/core/threading"
"net/http"
"net/http/pprof"
"sync"
)
var once sync.Once
type Server struct {
config Config
server *http.ServeMux
routes []string
}
func NewServer(cfg Config) *Server {
return &Server{
config: cfg,
server: http.NewServeMux(),
}
}
func (s *Server) addRoutes() {
s.handleFunc("/", func(writer http.ResponseWriter, r *http.Request) {
_ = json.NewEncoder(writer).Encode(s.routes)
})
//health
s.handleFunc(s.config.HealthPath, health.CreateHttpHandler())
//metrics
if s.config.EnableMetrics {
s.handleFunc(s.config.MetricsPath, promhttp.Handler().ServeHTTP)
}
if s.config.EnablePprof {
s.handleFunc("/debug/fgprof", fgprof.Handler().(http.HandlerFunc))
s.handleFunc("/debug/pprof/", pprof.Index)
s.handleFunc("/debug/pprof/cmdline", pprof.Cmdline)
s.handleFunc("/debug/pprof/profile", pprof.Profile)
s.handleFunc("/debug/pprof/symbol", pprof.Symbol)
s.handleFunc("/debug/pprof/trace", pprof.Trace)
}
}
func (s *Server) handleFunc(pattern string, handler http.HandlerFunc) {
s.server.HandleFunc(pattern, handler)
s.routes = append(s.routes, pattern)
}
func (s *Server) StartASync() {
s.addRoutes()
threading.GoSafe(func() {
addr := fmt.Sprintf("%s:%d", s.config.Host, s.config.Port)
logx.Infof("Starting dev http server at %s", addr)
if err := http.ListenAndServe(addr, s.server); err != nil {
logx.Error(err)
}
})
}
func StartAgent(c Config) {
once.Do(func() {
if c.Enabled {
s := NewServer(c)
s.StartASync()
}
})
}

@ -0,0 +1,65 @@
package encoding
import (
"bytes"
"encoding/json"
"git.diulo.com/mogfee/kit/lang"
"github.com/pelletier/go-toml/v2"
"gopkg.in/yaml.v3"
)
func TomlToJson(data []byte) ([]byte, error) {
var val any
if err := toml.NewDecoder(bytes.NewReader(data)).Decode(&val); err != nil {
return nil, err
}
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func YamlToJson(data []byte) ([]byte, error) {
var val any
if err := yaml.Unmarshal(data, &val); err != nil {
return nil, err
}
val = toStringKeyMap(val)
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(val); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func convertKeyToString(in map[any]any) map[string]any {
res := make(map[string]any)
for k, v := range in {
res[lang.Repr(k)] = toStringKeyMap(v)
}
return res
}
func convertNumberToJsonNumber(in any) json.Number {
return json.Number(lang.Repr(in))
}
func covertSlice(in []any) []any {
res := make([]any, len(in))
for i, v := range in {
res[i] = toStringKeyMap(v)
}
return res
}
func toStringKeyMap(v any) any {
switch v := v.(type) {
case []any:
return covertSlice(v)
case map[any]any:
return convertKeyToString(v)
case bool, string:
return v
case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64:
return convertNumberToJsonNumber(v)
default:
return lang.Repr(v)
}
}

@ -0,0 +1,109 @@
package health
import (
"fmt"
"github.com/zeromicro/go-zero/core/syncx"
"net/http"
"strings"
"sync"
)
var defaultHealthManager = newComboHealthManager()
type (
Probe interface {
MarkReady()
MarkNotReady()
IsReady() bool
Name() string
}
healthManager struct {
ready syncx.AtomicBool
name string
}
comboHealthManager struct {
mu sync.Mutex
probes []Probe
}
)
func AddProbe(probe Probe) {
defaultHealthManager.addProbe(probe)
}
func CreateHttpHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if defaultHealthManager.IsReady() {
_, _ = w.Write([]byte("OK"))
} else {
http.Error(w, "Service Unavailable\n"+defaultHealthManager.verboseInfo(),
http.StatusServiceUnavailable)
}
}
}
func NewHealthManager(name string) Probe {
return &healthManager{
name: name,
}
}
func (h *healthManager) MarkReady() {
h.ready.Set(true)
}
func (h *healthManager) MarkNotReady() {
h.ready.Set(false)
}
func (h *healthManager) IsReady() bool {
return h.ready.True()
}
func (h *healthManager) Name() string {
return h.name
}
func newComboHealthManager() *comboHealthManager {
return &comboHealthManager{}
}
func (p *comboHealthManager) MarkReady() {
p.mu.Lock()
defer p.mu.Unlock()
for _, probe := range p.probes {
probe.MarkReady()
}
}
func (p *comboHealthManager) MarkNotReady() {
p.mu.Lock()
defer p.mu.Unlock()
for _, probe := range p.probes {
probe.MarkNotReady()
}
}
func (p *comboHealthManager) IsReady() bool {
p.mu.Lock()
defer p.mu.Unlock()
for _, probe := range p.probes {
if !probe.IsReady() {
return false
}
}
return true
}
func (p *comboHealthManager) verboseInfo() string {
p.mu.Lock()
defer p.mu.Unlock()
var info strings.Builder
for _, probe := range p.probes {
if probe.IsReady() {
info.WriteString(fmt.Sprintf("%s is ready\n", probe.Name()))
} else {
info.WriteString(fmt.Sprintf("%s is not ready\n", probe.Name()))
}
}
return info.String()
}
func (p *comboHealthManager) addProbe(probe Probe) {
p.mu.Lock()
defer p.mu.Unlock()
p.probes = append(p.probes, probe)
}

@ -6,12 +6,14 @@ import (
"strings"
)
// Matcher is a middleware matcher.
type Matcher interface {
Use(ms ...middleware.Middleware)
Add(selector string, ms ...middleware.Middleware)
Match(operation string) []middleware.Middleware
}
// New new a middleware matcher.
func New() Matcher {
return &matcher{
matchs: make(map[string][]middleware.Middleware),
@ -32,6 +34,9 @@ func (m *matcher) Add(selector string, ms ...middleware.Middleware) {
if strings.HasSuffix(selector, "*") {
selector = strings.TrimSuffix(selector, "*")
m.prefix = append(m.prefix, selector)
// sort the prefix:
// - /foo/bar
// - /foo
sort.Slice(m.prefix, func(i, j int) bool {
return m.prefix[i] > m.prefix[j]
})
@ -45,7 +50,7 @@ func (m *matcher) Match(operation string) []middleware.Middleware {
ms = append(ms, m.defaults...)
}
if next, ok := m.matchs[operation]; ok {
ms = append(ms, next...)
return append(ms, next...)
}
for _, prefix := range m.prefix {
if strings.HasPrefix(operation, prefix) {

@ -0,0 +1,21 @@
package trace
import (
"context"
"go.opentelemetry.io/otel/trace"
)
func SpanIDFromContext(ctx context.Context) string {
spanCtx := trace.SpanContextFromContext(ctx)
if spanCtx.HasSpanID() {
return spanCtx.SpanID().String()
}
return ""
}
func TraceIDFromContext(ctx context.Context) string {
spanCtx := trace.SpanContextFromContext(ctx)
if spanCtx.HasTraceID() {
return spanCtx.TraceID().String()
}
return ""
}

@ -2,6 +2,7 @@ package cors
import (
"context"
"fmt"
"git.diulo.com/mogfee/kit/middleware"
"git.diulo.com/mogfee/kit/transport"
"net/http"
@ -68,6 +69,7 @@ type cors struct {
}
func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("cors start")
ch.h.ServeHTTP(w, r)
fmt.Println("cors end")
}

@ -2,7 +2,7 @@ package builder
import (
"fmt"
"git.diulo.com/mogfee/kit/stringx"
"git.diulo.com/mogfee/kit/core/stringx"
"reflect"
"strings"
)

@ -2,7 +2,7 @@ package sqlx
import (
"errors"
"git.diulo.com/mogfee/kit/mapping"
"git.diulo.com/mogfee/kit/core/mapping"
"reflect"
"strings"
)

@ -2,7 +2,7 @@ package sqlx
import (
"database/sql"
"git.diulo.com/mogfee/kit/syncx"
"git.diulo.com/mogfee/kit/core/syncx"
"io"
"time"
)

@ -4,7 +4,7 @@ import (
"context"
"errors"
"fmt"
"git.diulo.com/mogfee/kit/mapping"
"git.diulo.com/mogfee/kit/core/mapping"
"strconv"
"strings"
"time"

@ -1,6 +1,7 @@
package http
import (
"fmt"
"net/http"
"path"
"sync"
@ -16,7 +17,7 @@ type RouteInfo struct {
}
// HandlerFunc defines a function to serve HTTP requests.
type HandlerFunc func(ctx Context) error
type HandlerFunc func(Context) error
// Router is an HTTP router.
type Router struct {
@ -54,6 +55,7 @@ func (r *Router) Handle(method, relativePath string, h HandlerFunc, filters ...F
if err := h(ctx); err != nil {
r.srv.ene(res, req, err)
}
fmt.Println("=resp")
ctx.Reset(nil, nil)
r.pool.Put(ctx)
}))

Loading…
Cancel
Save