Compare commits

...

7 Commits

Author SHA1 Message Date
029a434a2b broker: pass broker content type if message options not pass it
All checks were successful
coverage / build (push) Successful in 1m44s
test / test (push) Successful in 3m5s
sync / sync (push) Successful in 7s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-05-09 13:51:35 +03:00
vtolstov
847259bc39 Apply Code Coverage Badge 2025-05-09 09:36:02 +00:00
a1ee8728ad broker: add Content-Type and DefaultContentType
All checks were successful
coverage / build (push) Successful in 1m58s
sync / sync (push) Successful in 1m37s
test / test (push) Successful in 3m47s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-05-09 12:34:46 +03:00
88a5875cfb switch yaml package to maintained one
All checks were successful
coverage / build (push) Successful in 2m16s
test / test (push) Successful in 4m37s
sync / sync (push) Successful in 8s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-05-09 12:18:49 +03:00
03ee33040c util/id: switch to default uuid package
All checks were successful
coverage / build (push) Successful in 2m21s
test / test (push) Successful in 4m50s
sync / sync (push) Successful in 6s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-05-08 19:07:00 +03:00
0144f175f0 add comment
All checks were successful
coverage / build (push) Successful in 1m33s
test / test (push) Successful in 3m41s
sync / sync (push) Successful in 8s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-05-06 23:00:15 +03:00
b3539a32ab logger: add none level
closes #399

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-05-06 23:00:15 +03:00
15 changed files with 89 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
# Micro # Micro
![Coverage](https://img.shields.io/badge/Coverage-33.6%25-yellow) ![Coverage](https://img.shields.io/badge/Coverage-33.7%25-yellow)
[![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Doc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/go.unistack.org/micro/v4?tab=overview) [![Doc](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/go.unistack.org/micro/v4?tab=overview)
[![Status](https://git.unistack.org/unistack-org/micro/actions/workflows/job_tests.yml/badge.svg?branch=v4)](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av4+event%3Apush) [![Status](https://git.unistack.org/unistack-org/micro/actions/workflows/job_tests.yml/badge.svg?branch=v4)](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av4+event%3Apush)

View File

@@ -159,6 +159,9 @@ func (b *Broker) Init(opts ...broker.Option) error {
func (b *Broker) NewMessage(ctx context.Context, hdr metadata.Metadata, body interface{}, opts ...broker.PublishOption) (broker.Message, error) { func (b *Broker) NewMessage(ctx context.Context, hdr metadata.Metadata, body interface{}, opts ...broker.PublishOption) (broker.Message, error) {
options := broker.NewPublishOptions(opts...) options := broker.NewPublishOptions(opts...)
if options.ContentType == "" {
options.ContentType = b.opts.ContentType
}
m := &memoryMessage{ctx: ctx, hdr: hdr, opts: options} m := &memoryMessage{ctx: ctx, hdr: hdr, opts: options}
c, err := b.newCodec(m.opts.ContentType) c, err := b.newCodec(m.opts.ContentType)
if err == nil { if err == nil {

View File

@@ -128,6 +128,9 @@ func (m *noopMessage) Unmarshal(dst interface{}, opts ...codec.Option) error {
func (b *NoopBroker) NewMessage(ctx context.Context, hdr metadata.Metadata, body interface{}, opts ...PublishOption) (Message, error) { func (b *NoopBroker) NewMessage(ctx context.Context, hdr metadata.Metadata, body interface{}, opts ...PublishOption) (Message, error) {
options := NewPublishOptions(opts...) options := NewPublishOptions(opts...)
if options.ContentType == "" {
options.ContentType = b.opts.ContentType
}
m := &noopMessage{ctx: ctx, hdr: hdr, opts: options} m := &noopMessage{ctx: ctx, hdr: hdr, opts: options}
c, err := b.newCodec(m.opts.ContentType) c, err := b.newCodec(m.opts.ContentType)
if err == nil { if err == nil {

View File

@@ -45,6 +45,9 @@ type Options struct {
// GracefulTimeout contains time to wait to finish in flight requests // GracefulTimeout contains time to wait to finish in flight requests
GracefulTimeout time.Duration GracefulTimeout time.Duration
// ContentType will be used if no content-type set when creating message
ContentType string
} }
// NewOptions create new Options // NewOptions create new Options
@@ -57,14 +60,19 @@ func NewOptions(opts ...Option) Options {
Codecs: make(map[string]codec.Codec), Codecs: make(map[string]codec.Codec),
Tracer: tracer.DefaultTracer, Tracer: tracer.DefaultTracer,
GracefulTimeout: DefaultGracefulTimeout, GracefulTimeout: DefaultGracefulTimeout,
ContentType: DefaultContentType,
} }
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
return options return options
} }
// DefaultContentType is the default content-type if not specified
var DefaultContentType = ""
// Context sets the context option // Context sets the context option
func Context(ctx context.Context) Option { func Context(ctx context.Context) Option {
return func(o *Options) { return func(o *Options) {
@@ -72,6 +80,13 @@ func Context(ctx context.Context) Option {
} }
} }
// ContentType used by default if not specified
func ContentType(ct string) Option {
return func(o *Options) {
o.ContentType = ct
}
}
// PublishOptions struct // PublishOptions struct
type PublishOptions struct { type PublishOptions struct {
// ContentType for message body // ContentType for message body

View File

@@ -3,8 +3,6 @@ package codec
import ( import (
"errors" "errors"
"gopkg.in/yaml.v3"
) )
var ( var (
@@ -68,10 +66,10 @@ func (m *RawMessage) MarshalYAML() ([]byte, error) {
} }
// UnmarshalYAML sets *m to a copy of data. // UnmarshalYAML sets *m to a copy of data.
func (m *RawMessage) UnmarshalYAML(n *yaml.Node) error { func (m *RawMessage) UnmarshalYAML(data []byte) error {
if m == nil { if m == nil {
return errors.New("RawMessage UnmarshalYAML on nil pointer") return errors.New("RawMessage UnmarshalYAML on nil pointer")
} }
*m = append((*m)[0:0], []byte(n.Value)...) *m = append((*m)[0:0], data...)
return nil return nil
} }

View File

@@ -1,7 +1,5 @@
package codec package codec
import "gopkg.in/yaml.v3"
// Frame gives us the ability to define raw data to send over the pipes // Frame gives us the ability to define raw data to send over the pipes
type Frame struct { type Frame struct {
Data []byte Data []byte
@@ -28,8 +26,8 @@ func (m *Frame) MarshalYAML() ([]byte, error) {
} }
// UnmarshalYAML set frame data // UnmarshalYAML set frame data
func (m *Frame) UnmarshalYAML(n *yaml.Node) error { func (m *Frame) UnmarshalYAML(data []byte) error {
m.Data = []byte(n.Value) m.Data = append((m.Data)[0:0], data...)
return nil return nil
} }

4
go.mod
View File

@@ -6,7 +6,7 @@ require (
dario.cat/mergo v1.0.1 dario.cat/mergo v1.0.1
github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/KimMachineGun/automemlimit v0.7.0 github.com/KimMachineGun/automemlimit v0.7.0
github.com/ash3in/uuidv8 v1.2.0 github.com/goccy/go-yaml v1.17.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/matoous/go-nanoid v1.5.1 github.com/matoous/go-nanoid v1.5.1
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
@@ -19,7 +19,6 @@ require (
golang.org/x/sync v0.10.0 golang.org/x/sync v0.10.0
google.golang.org/grpc v1.69.4 google.golang.org/grpc v1.69.4
google.golang.org/protobuf v1.36.3 google.golang.org/protobuf v1.36.3
gopkg.in/yaml.v3 v3.0.1
) )
require ( require (
@@ -31,4 +30,5 @@ require (
golang.org/x/sys v0.29.0 // indirect golang.org/x/sys v0.29.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

4
go.sum
View File

@@ -4,12 +4,12 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlDI/pBWK49u88= github.com/KimMachineGun/automemlimit v0.7.0 h1:7G06p/dMSf7G8E6oq+f2uOPuVncFyIlDI/pBWK49u88=
github.com/KimMachineGun/automemlimit v0.7.0/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/KimMachineGun/automemlimit v0.7.0/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=
github.com/ash3in/uuidv8 v1.2.0 h1:2oogGdtCPwaVtyvPPGin4TfZLtOGE5F+W++E880G6SI=
github.com/ash3in/uuidv8 v1.2.0/go.mod h1:BnU0wJBxnzdEKmVg4xckBkD+VZuecTFTUP3M0dWgyY4=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=

View File

@@ -4,18 +4,20 @@ package logger
type Level int8 type Level int8
const ( const (
// TraceLevel level usually used to find bugs, very verbose // TraceLevel usually used to find bugs, very verbose
TraceLevel Level = iota - 2 TraceLevel Level = iota - 2
// DebugLevel level used only when enabled debugging // DebugLevel used only when enabled debugging
DebugLevel DebugLevel
// InfoLevel level used for general info about what's going on inside the application // InfoLevel used for general info about what's going on inside the application
InfoLevel InfoLevel
// WarnLevel level used for non-critical entries // WarnLevel used for non-critical entries
WarnLevel WarnLevel
// ErrorLevel level used for errors that should definitely be noted // ErrorLevel used for errors that should definitely be noted
ErrorLevel ErrorLevel
// FatalLevel level used for critical errors and then calls `os.Exit(1)` // FatalLevel used for critical errors and then calls `os.Exit(1)`
FatalLevel FatalLevel
// NoneLevel used to disable logging
NoneLevel
) )
// String returns logger level string representation // String returns logger level string representation
@@ -33,6 +35,8 @@ func (l Level) String() string {
return "error" return "error"
case FatalLevel: case FatalLevel:
return "fatal" return "fatal"
case NoneLevel:
return "none"
} }
return "info" return "info"
} }
@@ -58,6 +62,8 @@ func ParseLevel(lvl string) Level {
return ErrorLevel return ErrorLevel
case FatalLevel.String(): case FatalLevel.String():
return FatalLevel return FatalLevel
case NoneLevel.String():
return NoneLevel
} }
return InfoLevel return InfoLevel
} }

View File

@@ -34,6 +34,7 @@ var (
warnValue = slog.StringValue("warn") warnValue = slog.StringValue("warn")
errorValue = slog.StringValue("error") errorValue = slog.StringValue("error")
fatalValue = slog.StringValue("fatal") fatalValue = slog.StringValue("fatal")
noneValue = slog.StringValue("none")
) )
type wrapper struct { type wrapper struct {
@@ -85,6 +86,8 @@ func (s *slogLogger) renameAttr(_ []string, a slog.Attr) slog.Attr {
a.Value = errorValue a.Value = errorValue
case lvl >= logger.FatalLevel: case lvl >= logger.FatalLevel:
a.Value = fatalValue a.Value = fatalValue
case lvl >= logger.NoneLevel:
a.Value = noneValue
default: default:
a.Value = infoValue a.Value = infoValue
} }
@@ -316,6 +319,8 @@ func loggerToSlogLevel(level logger.Level) slog.Level {
return slog.LevelDebug - 1 return slog.LevelDebug - 1
case logger.FatalLevel: case logger.FatalLevel:
return slog.LevelError + 1 return slog.LevelError + 1
case logger.NoneLevel:
return slog.LevelError + 2
default: default:
return slog.LevelInfo return slog.LevelInfo
} }
@@ -333,6 +338,8 @@ func slogToLoggerLevel(level slog.Level) logger.Level {
return logger.TraceLevel return logger.TraceLevel
case slog.LevelError + 1: case slog.LevelError + 1:
return logger.FatalLevel return logger.FatalLevel
case slog.LevelError + 2:
return logger.NoneLevel
default: default:
return logger.InfoLevel return logger.InfoLevel
} }

View File

@@ -36,6 +36,24 @@ func TestStacktrace(t *testing.T) {
} }
} }
func TestNoneLevel(t *testing.T) {
ctx := context.TODO()
buf := bytes.NewBuffer(nil)
l := NewLogger(logger.WithLevel(logger.NoneLevel), logger.WithOutput(buf),
WithHandlerFunc(slog.NewTextHandler),
logger.WithAddStacktrace(true),
)
if err := l.Init(logger.WithFields("key1", "val1")); err != nil {
t.Fatal(err)
}
l.Error(ctx, "msg1", errors.New("err"))
if buf.Len() != 0 {
t.Fatalf("logger none level not works, buf contains: %s", buf.Bytes())
}
}
func TestDelayedBuffer(t *testing.T) { func TestDelayedBuffer(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)

View File

@@ -69,6 +69,7 @@ type Service struct {
type Node struct { type Node struct {
Metadata metadata.Metadata `json:"metadata,omitempty"` Metadata metadata.Metadata `json:"metadata,omitempty"`
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
// Address also prefixed with scheme like grpc://xx.xx.xx.xx:1234
Address string `json:"address,omitempty"` Address string `json:"address,omitempty"`
} }

View File

@@ -2,12 +2,8 @@ package id
import ( import (
"crypto/rand" "crypto/rand"
"encoding/binary"
"errors" "errors"
"fmt"
"time"
uuidv8 "github.com/ash3in/uuidv8"
"github.com/google/uuid" "github.com/google/uuid"
nanoid "github.com/matoous/go-nanoid" nanoid "github.com/matoous/go-nanoid"
) )
@@ -25,6 +21,7 @@ type Type int
const ( const (
TypeUnspecified Type = iota TypeUnspecified Type = iota
TypeNanoid TypeNanoid
TypeUUIDv7
TypeUUIDv8 TypeUUIDv8
) )
@@ -58,14 +55,14 @@ func (g *Generator) New() (string, error) {
} }
return nanoid.Generate(g.opts.NanoidAlphabet, g.opts.NanoidSize) return nanoid.Generate(g.opts.NanoidAlphabet, g.opts.NanoidSize)
case TypeUUIDv8: case TypeUUIDv7:
timestamp := uint64(time.Now().UnixNano()) uid, err := uuid.NewV7()
clockSeq := make([]byte, 2) if err != nil {
if _, err := rand.Read(clockSeq); err != nil { return "", err
return "", fmt.Errorf("failed to generate random clock sequence: %w", err)
} }
clockSeqValue := binary.BigEndian.Uint16(clockSeq) & 0x0FFF // Mask to 12 bits return uid.String(), nil
return uuidv8.NewWithParams(timestamp, clockSeqValue, g.opts.UUIDNode[:], uuidv8.TimestampBits48) case TypeUUIDv8:
return "", errors.New("unsupported uuid version v8")
} }
return "", errors.New("invalid option, Type unspecified") return "", errors.New("invalid option, Type unspecified")
} }
@@ -82,16 +79,15 @@ func New(opts ...Option) (string, error) {
if options.NanoidSize <= 0 { if options.NanoidSize <= 0 {
return "", errors.New("invalid option, NanoidSize must be positive integer") return "", errors.New("invalid option, NanoidSize must be positive integer")
} }
return nanoid.Generate(options.NanoidAlphabet, options.NanoidSize) return nanoid.Generate(options.NanoidAlphabet, options.NanoidSize)
case TypeUUIDv8: case TypeUUIDv7:
timestamp := uint64(time.Now().UnixNano()) uid, err := uuid.NewV7()
clockSeq := make([]byte, 2) if err != nil {
if _, err := rand.Read(clockSeq); err != nil { return "", err
return "", fmt.Errorf("failed to generate random clock sequence: %w", err)
} }
clockSeqValue := binary.BigEndian.Uint16(clockSeq) & 0x0FFF // Mask to 12 bits return uid.String(), nil
return uuidv8.NewWithParams(timestamp, clockSeqValue, options.UUIDNode[:], uuidv8.TimestampBits48) case TypeUUIDv8:
return "", errors.New("unsupported uuid version v8")
} }
return "", errors.New("invalid option, Type unspecified") return "", errors.New("invalid option, Type unspecified")
@@ -145,7 +141,7 @@ func WithUUIDNode(node [6]byte) Option {
// NewOptions returns new Options struct filled by opts // NewOptions returns new Options struct filled by opts
func NewOptions(opts ...Option) Options { func NewOptions(opts ...Option) Options {
options := Options{ options := Options{
Type: TypeUUIDv8, Type: TypeUUIDv7,
NanoidAlphabet: DefaultNanoidAlphabet, NanoidAlphabet: DefaultNanoidAlphabet,
NanoidSize: DefaultNanoidSize, NanoidSize: DefaultNanoidSize,
UUIDNode: generatedNode, UUIDNode: generatedNode,

View File

@@ -6,7 +6,7 @@ import (
"strconv" "strconv"
"time" "time"
"gopkg.in/yaml.v3" "github.com/goccy/go-yaml"
) )
type Duration int64 type Duration int64
@@ -58,9 +58,9 @@ func (d Duration) MarshalYAML() (interface{}, error) {
return time.Duration(d).String(), nil return time.Duration(d).String(), nil
} }
func (d *Duration) UnmarshalYAML(n *yaml.Node) error { func (d *Duration) UnmarshalYAML(data []byte) error {
var v interface{} var v interface{}
if err := yaml.Unmarshal([]byte(n.Value), &v); err != nil { if err := yaml.Unmarshal(data, &v); err != nil {
return err return err
} }
switch value := v.(type) { switch value := v.(type) {

View File

@@ -6,7 +6,7 @@ import (
"testing" "testing"
"time" "time"
"gopkg.in/yaml.v3" "github.com/goccy/go-yaml"
) )
func TestMarshalYAML(t *testing.T) { func TestMarshalYAML(t *testing.T) {