add multi user config field, fixup request-id generation

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2024-11-17 18:54:44 +03:00
parent 09c107ac3e
commit 4d7bfa713a
4 changed files with 86 additions and 46 deletions

View File

@ -8,6 +8,7 @@ import (
"time" "time"
openapi_v3 "github.com/google/gnostic/openapiv3" openapi_v3 "github.com/google/gnostic/openapiv3"
"github.com/google/uuid"
grpccli "go.unistack.org/micro-client-grpc/v3" grpccli "go.unistack.org/micro-client-grpc/v3"
httpcli "go.unistack.org/micro-client-http/v3" httpcli "go.unistack.org/micro-client-http/v3"
jsoncodec "go.unistack.org/micro-codec-json/v3" jsoncodec "go.unistack.org/micro-codec-json/v3"
@ -156,7 +157,7 @@ func main() {
l.Info(ctx, "exiting") l.Info(ctx, "exiting")
} }
func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check string, task *config.Task) (any, []any, error) { func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check string, task *config.TaskConfig) (any, []any, error) {
var err error var err error
c, ok := clients["http"] c, ok := clients["http"]
@ -193,6 +194,7 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
httpcli.ErrorMap(errmap), httpcli.ErrorMap(errmap),
httpcli.Method(task.HTTP.Method), httpcli.Method(task.HTTP.Method),
httpcli.Path(task.HTTP.Endpoint), httpcli.Path(task.HTTP.Endpoint),
// client.WithContentType("application/json"), // client.WithContentType("application/json"),
} }
@ -205,18 +207,39 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
} }
fn := func() { fn := func() {
var cerr error
metadata := make(map[string]string, len(task.HTTP.Metadata))
var rquid string
for k, v := range task.HTTP.Metadata {
if k == "x-request-id" && v == "generate" {
uid, err := uuid.NewV7()
if err != nil {
l.Error(ctx, "failed to generate x-request-id", err)
uid = uuid.Nil
} else {
v = uid.String()
}
}
metadata[k] = v
rquid = v
}
l.Info(ctx, fmt.Sprintf("call %s.%s endpoint %s", treq.Service(), treq.Method(), treq.Endpoint()), "x-request-id", rquid)
m.Counter(semconv.ClientRequestInflight, labels...).Inc() m.Counter(semconv.ClientRequestInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
// l.Info(ctx, fmt.Sprintf("try to call %s.%s via %s", task.Name, task.Name, task.HTTP.Addr)) cerr = httpconn.Call(ctx, rquid, l, c, task.HTTP.Addr, time.Duration(task.Timeout),
err = httpconn.Call(ctx, l, c, task.HTTP.Addr, time.Duration(task.Timeout),
treq, treq,
rsp, rsp,
opts...) append(opts, client.WithRequestMetadata(metadata))...,
)
te := time.Since(ts) te := time.Since(ts)
m.Counter(semconv.ClientRequestInflight, labels...).Dec()
m.Summary(semconv.ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds()) m.Summary(semconv.ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds())
m.Histogram(semconv.ClientRequestDurationSeconds, labels...).Update(te.Seconds()) m.Histogram(semconv.ClientRequestDurationSeconds, labels...).Update(te.Seconds())
m.Counter(semconv.ClientRequestInflight, labels...).Dec()
if err != nil { if cerr != nil {
m.Counter(semconv.ClientRequestTotal, append(labels, "status", "failure")...).Inc() m.Counter(semconv.ClientRequestTotal, append(labels, "status", "failure")...).Inc()
} else { } else {
m.Counter(semconv.ClientRequestTotal, append(labels, "status", "success")...).Inc() m.Counter(semconv.ClientRequestTotal, append(labels, "status", "success")...).Inc()
@ -226,7 +249,7 @@ func newHTTPTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
return fn, nil, nil return fn, nil, nil
} }
func newGRPCTask(ctx context.Context, l logger.Logger, m meter.Meter, check string, task *config.Task) (any, []any, error) { func newGRPCTask(ctx context.Context, l logger.Logger, m meter.Meter, check string, task *config.TaskConfig) (any, []any, error) {
var err error var err error
c, ok := clients["grpc"] c, ok := clients["grpc"]
@ -296,17 +319,38 @@ func newGRPCTask(ctx context.Context, l logger.Logger, m meter.Meter, check stri
} }
fn := func() { fn := func() {
var cerr error
var rquid string
metadata := make(map[string]string, len(task.HTTP.Metadata))
for k, v := range task.GRPC.Metadata {
if k == "x-request-id" && v == "generate" {
uid, err := uuid.NewV7()
if err != nil {
l.Error(ctx, "failed to generate x-request-id", err)
uid = uuid.Nil
} else {
v = uid.String()
}
}
metadata[k] = v
rquid = v
}
l.Info(ctx, fmt.Sprintf("call %s.%s endpoint %s", treq.Service(), treq.Method(), treq.Endpoint()), "x-request-id", rquid)
m.Counter(semconv.ClientRequestInflight, labels...).Inc() m.Counter(semconv.ClientRequestInflight, labels...).Inc()
ts := time.Now() ts := time.Now()
cerr = grpcconn.Call(ctx, rquid, l, c, task.GRPC.Addr, time.Duration(task.Timeout),
err = grpcconn.Call(ctx, l, c, task.GRPC.Addr, time.Duration(task.Timeout),
treq, treq,
rsp) rsp,
client.WithRequestMetadata(metadata),
)
te := time.Since(ts) te := time.Since(ts)
m.Counter(semconv.ClientRequestInflight, labels...).Dec()
m.Summary(semconv.ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds()) m.Summary(semconv.ClientRequestLatencyMicroseconds, labels...).Update(te.Seconds())
m.Histogram(semconv.ClientRequestDurationSeconds, labels...).Update(te.Seconds()) m.Histogram(semconv.ClientRequestDurationSeconds, labels...).Update(te.Seconds())
m.Counter(semconv.ClientRequestInflight, labels...).Dec()
if err != nil { if cerr != nil {
m.Counter(semconv.ClientRequestTotal, append(labels, "status", "failure")...).Inc() m.Counter(semconv.ClientRequestTotal, append(labels, "status", "failure")...).Inc()
} else { } else {
m.Counter(semconv.ClientRequestTotal, append(labels, "status", "success")...).Inc() m.Counter(semconv.ClientRequestTotal, append(labels, "status", "success")...).Inc()

View File

@ -7,25 +7,30 @@ import (
mtime "go.unistack.org/micro/v3/util/time" mtime "go.unistack.org/micro/v3/util/time"
) )
type Meter struct { type AppConfig struct {
MultiUser bool `json:"multi_user,omitempty" yaml:"multi_user,omitempty"`
}
type MeterConfig struct {
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"` Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"` Path string `json:"path,omitempty" yaml:"path,omitempty"`
} }
type Config struct { type Config struct {
Meter *Meter `json:"meter,omitempty" yaml:"meter,omitempty"` Meter *MeterConfig `json:"meter,omitempty" yaml:"meter,omitempty"`
Checks []*Check `json:"checks,omitempty" yaml:"checks,omitempty"` Checks []*CheckConfig `json:"checks,omitempty" yaml:"checks,omitempty"`
} }
type Check struct { type CheckConfig struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"` Name string `json:"name,omitempty" yaml:"name,omitempty"`
Tasks []*Task `json:"tasks,omitempty" yaml:"tasks,omitempty"` Tasks []*TaskConfig `json:"tasks,omitempty" yaml:"tasks,omitempty"`
Timeout mtime.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"` Timeout mtime.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
Interval mtime.Duration `json:"interval,omitempty" yaml:"interval,omitempty"` Interval mtime.Duration `json:"interval,omitempty" yaml:"interval,omitempty"`
Active bool `json:"active,omitempty" yaml:"active,omitempty"` Active bool `json:"active,omitempty" yaml:"active,omitempty"`
} }
type HTTPConfig struct { type HTTPConfig struct {
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"` Data string `json:"data,omitempty" yaml:"data,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"` Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
@ -34,6 +39,7 @@ type HTTPConfig struct {
} }
type GRPCConfig struct { type GRPCConfig struct {
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"` Data string `json:"data,omitempty" yaml:"data,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"` Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
@ -41,12 +47,13 @@ type GRPCConfig struct {
} }
type GraphQLConfig struct { type GraphQLConfig struct {
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"` Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Data string `json:"data,omitempty" yaml:"data,omitempty"` Data string `json:"data,omitempty" yaml:"data,omitempty"`
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"` Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
} }
type Task struct { type TaskConfig struct {
HTTP *HTTPConfig `json:"http,omitempty" yaml:"http,omitempty"` HTTP *HTTPConfig `json:"http,omitempty" yaml:"http,omitempty"`
GRPC *GRPCConfig `json:"grpc,omitempty" yaml:"grpc,omitempty"` GRPC *GRPCConfig `json:"grpc,omitempty" yaml:"grpc,omitempty"`
GraphQL *GraphQLConfig `json:"graphql,omitempty" yaml:"graphql"` GraphQL *GraphQLConfig `json:"graphql,omitempty" yaml:"graphql"`

View File

@ -5,18 +5,12 @@ import (
"strings" "strings"
"time" "time"
"github.com/google/uuid"
"go.unistack.org/micro/v3/client" "go.unistack.org/micro/v3/client"
"go.unistack.org/micro/v3/logger" "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{}, opts ...client.CallOption) error { func Call(ctx context.Context, rquid string, l logger.Logger, c client.Client, addr string, td time.Duration, req client.Request, rsp interface{}, opts ...client.CallOption) error {
var err 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, err = c.Call(ctx, req, rsp,
client.WithAddress(addr), client.WithAddress(addr),
@ -24,7 +18,7 @@ func Call(ctx context.Context, l logger.Logger, c client.Client, addr string, td
// client.WithContentType("application/json"), // client.WithContentType("application/json"),
) )
if err != nil { if err != nil {
l.Error(ctx, "call failed", "x-request-id", uid.String(), err) l.Error(ctx, "call failed", "x-request-id", rquid, err)
return err return err
} }
return nil return nil

View File

@ -4,18 +4,12 @@ import (
"context" "context"
"time" "time"
"github.com/google/uuid"
"go.unistack.org/micro/v3/client" "go.unistack.org/micro/v3/client"
"go.unistack.org/micro/v3/logger" "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{}, opts ...client.CallOption) error { func Call(ctx context.Context, rquid string, l logger.Logger, c client.Client, addr string, td time.Duration, req client.Request, rsp interface{}, opts ...client.CallOption) error {
var err 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, err = c.Call(ctx, req, rsp,
client.WithAddress(addr), client.WithAddress(addr),
@ -23,7 +17,8 @@ func Call(ctx context.Context, l logger.Logger, c client.Client, addr string, td
// client.WithContentType("application/json"), // client.WithContentType("application/json"),
) )
if err != nil { if err != nil {
l.Error(ctx, "call failed", "x-request-id", uid.String(), err) // httpcli.GetError(err)
l.Error(ctx, "call failed", "x-request-id", rquid, err)
return err return err
} }
return nil return nil