add ability to work with protoset

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2024-11-16 15:21:52 +03:00
parent a2a241cd78
commit bac85a284d
8 changed files with 233 additions and 15 deletions

2
.gitignore vendored
View File

@ -22,3 +22,5 @@
go.work
config.yaml
servicechecker
*.protoset

View File

@ -1,2 +1,2 @@
all:
go build -o servicechecker ./cmd/servicechecker/*.go
GOWORK=off go build -x -v -o servicechecker ./cmd/servicechecker/*.go

View File

@ -2,22 +2,113 @@ package main
import (
"context"
"fmt"
"os"
"time"
grpccli "go.unistack.org/micro-client-grpc/v3"
jsonpbcodec "go.unistack.org/micro-codec-jsonpb/v3"
protocodec "go.unistack.org/micro-codec-proto/v3"
victoriametrics "go.unistack.org/micro-meter-victoriametrics/v3"
"go.unistack.org/micro/v3/client"
"go.unistack.org/micro/v3/logger/slog"
"go.unistack.org/micro/v3/semconv"
"go.unistack.org/servicechecker/pkg/config"
"go.unistack.org/servicechecker/pkg/grpcconn"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/dynamicpb"
)
func main() {
ctx := context.Background()
log := slog.NewLogger()
l := slog.NewLogger()
l.Init()
m := victoriametrics.NewMeter()
f, err := os.Open("config.yaml")
if err != nil {
log.Fatal(ctx, "failed to open config", err)
l.Fatal(ctx, "failed to open config", err)
}
defer f.Close()
cfg := &config.Config{}
if err = cfg.Parse(f); err != nil {
log.Fatal(ctx, "failed to open config", err)
l.Fatal(ctx, "failed to open config", err)
}
clients := make(map[string]client.Client)
gcli := grpccli.NewClient(
client.Codec("application/json", jsonpbcodec.NewCodec()),
client.Codec("application/grpc", protocodec.NewCodec()),
client.Codec("application/grpc+proto", protocodec.NewCodec()),
client.Codec("application/grpc+json", jsonpbcodec.NewCodec()),
client.ContentType("application/grpc"),
client.Retries(0),
// client.TLSConfig(&tls.Config{InsecureSkipVerify: true}),
)
protosetBuf, _ := os.ReadFile("card.protoset")
fdset := &descriptorpb.FileDescriptorSet{}
if err = protocodec.NewCodec().Unmarshal(protosetBuf, fdset); err != nil {
l.Fatal(ctx, "failed to unmarshal protoset file", err)
}
pfileoptions := protodesc.FileOptions{AllowUnresolvable: true}
pfiles, err := pfileoptions.NewFiles(fdset)
if err != nil {
l.Fatal(ctx, "failed to use protoset file", err)
}
gcli.Init()
clients["grpc"] = gcli
for _, svc := range cfg.Services {
c, ok := clients[svc.Type]
if !ok {
l.Error(ctx, fmt.Sprintf("unknown client %s", svc.Type))
continue
}
pdesc, err := pfiles.FindDescriptorByName("card_proto.CardService")
if err != nil {
l.Error(ctx, "failed to find service "+svc.Name)
continue
}
sdesc, ok := pdesc.(protoreflect.ServiceDescriptor)
if !ok {
l.Error(ctx, "failed to find service "+svc.Name)
continue
}
for _, check := range svc.Checks {
mdesc := sdesc.Methods().ByName(protoreflect.Name(check.Name))
if mdesc == nil {
l.Error(ctx, "failed to find method "+check.Name)
continue
}
req := dynamicpb.NewMessageType(mdesc.Input()).New()
rsp := dynamicpb.NewMessageType(mdesc.Output()).New()
if err = jsonpbcodec.NewCodec().Unmarshal([]byte(check.Data), req); err != nil {
l.Error(ctx, "failed to unmarshal", err)
continue
}
labels := []string{"service", svc.Name, "endpoint", check.Name}
m.Counter(semconv.ClientRequestInflight, labels...).Inc()
ts := time.Now()
err = grpcconn.Call(ctx, l, c, svc.Addr, time.Duration(check.Timeout),
c.NewRequest("card_proto", "CardService."+check.Name, req),
rsp)
te := time.Since(ts)
m.Summary(semconv.ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds())
m.Histogram(semconv.ClientRequestDurationSeconds, labels...).Update(te.Seconds())
m.Counter(semconv.ClientRequestInflight, labels...).Dec()
if err != nil {
m.Counter(semconv.ClientRequestTotal, append(labels, "status", "failure")...).Inc()
} else {
m.Counter(semconv.ClientRequestTotal, append(labels, "status", "success")...).Inc()
}
}
}
m.Write(os.Stdout)
}

25
go.mod
View File

@ -2,4 +2,27 @@ module go.unistack.org/servicechecker
go 1.23.3
require go.unistack.org/micro/v3 v3.10.100
require (
github.com/google/uuid v1.6.0
github.com/jhump/protoreflect/v2 v2.0.0-beta.2
go.unistack.org/micro-client-grpc/v3 v3.11.10
go.unistack.org/micro-codec-jsonpb/v3 v3.10.3
go.unistack.org/micro-codec-proto/v3 v3.10.2
go.unistack.org/micro-meter-victoriametrics/v3 v3.8.9
go.unistack.org/micro-proto/v3 v3.4.1
go.unistack.org/micro/v3 v3.10.100
google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/kr/text v0.2.0 // indirect
github.com/valyala/fastrand v1.1.0 // indirect
github.com/valyala/histogram v1.2.0 // indirect
go.unistack.org/metrics v0.0.1 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.18.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.0 // indirect
)

54
go.sum
View File

@ -1,4 +1,54 @@
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jhump/protoreflect/v2 v2.0.0-beta.2 h1:qZU+rEZUOYTz1Bnhi3xbwn+VxdXkLVeEpAeZzVXLY88=
github.com/jhump/protoreflect/v2 v2.0.0-beta.2/go.mod h1:4tnOYkB/mq7QTyS3YKtVtNrJv4Psqout8HA1U+hZtgM=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8=
github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ=
github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY=
go.unistack.org/metrics v0.0.1 h1:sCnGO059ZccGC/D34iRH121eSk+7ci5+OY9cl5K7GKY=
go.unistack.org/metrics v0.0.1/go.mod h1:1FY4R7EKJa9Oz2D6wlGScNerpl6igRs9Cx/3et4Rgs4=
go.unistack.org/micro-client-grpc/v3 v3.11.10 h1:hbqCL4JLbTtPN1ee16EK6LqTbeIr6HynJJjCRWAu2kk=
go.unistack.org/micro-client-grpc/v3 v3.11.10/go.mod h1:S1AIA2n3GZVxKdjpMcLJSXwBpC/OzAX91D6KxFzqjbc=
go.unistack.org/micro-codec-jsonpb/v3 v3.10.3 h1:4GTNrhpwPCRqSuimlOdgViE+95IE4YeBNeOCTawSTeM=
go.unistack.org/micro-codec-jsonpb/v3 v3.10.3/go.mod h1:6avGT/PKXgZFh2d4dhyUfkKRWXPwzL2CJHnRLqx9o3g=
go.unistack.org/micro-codec-proto/v3 v3.10.2 h1:9iUQjBjTsd/RgIqB5rAQMZE0CYWngoW9pbrnfcFtbXM=
go.unistack.org/micro-codec-proto/v3 v3.10.2/go.mod h1:54e1jb6aLL9obJUwJjtVupE5zY4PugTcMSqWDhz9aC4=
go.unistack.org/micro-meter-victoriametrics/v3 v3.8.9 h1:ZXCS0eFiSdvcFYxpxV2Q77gfwAjpIRydwAEI1QBrwuQ=
go.unistack.org/micro-meter-victoriametrics/v3 v3.8.9/go.mod h1:xODJQ0Nu/F8k34D/z2ITL91OskI/C674XCkugAxmc3Q=
go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q=
go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo=
go.unistack.org/micro/v3 v3.10.100 h1:yWOaU0ImCGm5k5MUzlIobJUOr+KLfrR/BoDZvcHyKxM=
go.unistack.org/micro/v3 v3.10.100/go.mod h1:YzMldzHN9Ei+zy5t/Psu7RUWDZwUfrNYiStSQtTz90g=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,6 +1,11 @@
package config
import "io"
import (
"io"
mtime "go.unistack.org/micro/v3/util/time"
yaml "gopkg.in/yaml.v3"
)
type Config struct {
Services []*Service `json:"services,omitempty" yaml:"services,omitempty"`
@ -9,14 +14,17 @@ type Config struct {
type Service struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
Checks []Check `json:"checks,omitempty" yaml:"checks,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Reflection bool `json:"reflection,omitempty" yaml:"reflection,omitempty"`
Protoset string `json:"protoset,omitempty" yaml:"protoset,omitempty"`
Checks []*Check `json:"checks,omitempty" yaml:"checks,omitempty"`
TLSVerify *bool `json:"tls_verify,omitempty" yaml:"tls_verify,omitempty"`
}
type Check struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"`
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
Timeout mtime.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
}
func (cfg *Config) Parse(r io.Reader) error {

30
pkg/grpcconn/grpcconn.go Normal file
View File

@ -0,0 +1,30 @@
package grpcconn
import (
"context"
"time"
"github.com/google/uuid"
"go.unistack.org/micro/v3/client"
"go.unistack.org/micro/v3/logger"
)
func Call(ctx context.Context, l logger.Logger, c client.Client, addr string, td time.Duration, req client.Request, rsp interface{}) error {
var err error
uid, err := uuid.NewRandom()
if err != nil {
l.Error(ctx, "failed to generate x-request-id", err)
return err
}
err = c.Call(ctx, req, rsp,
client.WithAddress(addr),
client.WithRequestTimeout(td),
// client.WithContentType("application/json"),
)
if err != nil {
l.Error(ctx, "call failed", "x-request-id", uid.String(), err)
return err
}
return nil
}

14
pkg/grpcconn/protoset.go Normal file
View File

@ -0,0 +1,14 @@
//go:build ignore
package grpcconn
import (
"github.com/emicklei/proto"
"github.com/jhump/protoreflect/desc"
)
var protoSets = map[string]*desc.FileDescriptor
func GetMessage(service string, method string) (proto.Message, error) {
return nil, nil
}