mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:37:30 +00:00
blub
This commit is contained in:
@@ -1,35 +0,0 @@
|
|||||||
package builder
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
type builder interface {
|
|
||||||
reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Builder[T builder] struct {
|
|
||||||
*sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBuilder[T builder](creator func() T) *Builder[T] {
|
|
||||||
if creator == nil {
|
|
||||||
creator = func() T {
|
|
||||||
var x T
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &Builder[T]{
|
|
||||||
Pool: &sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return creator()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder[T]) Get() T {
|
|
||||||
return b.Pool.Get().(T)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder[T]) Put(x T) {
|
|
||||||
b.Pool.Put(x)
|
|
||||||
}
|
|
@@ -1,54 +0,0 @@
|
|||||||
package builder
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/cache"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InstanceBuilder struct {
|
|
||||||
*Builder[*InstanceBuilder]
|
|
||||||
|
|
||||||
tracer tracing.Tracer
|
|
||||||
logger *logging.Logger
|
|
||||||
cache *cache.Instance
|
|
||||||
db repository.InstanceRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInstanceBuilder() *InstanceBuilder {
|
|
||||||
return &InstanceBuilder{
|
|
||||||
Builder: NewBuilder(func() *InstanceBuilder {
|
|
||||||
return new(InstanceBuilder)
|
|
||||||
}),
|
|
||||||
cache: new(cache.Instance),
|
|
||||||
tracer: tracing.NewTracer("instance"),
|
|
||||||
logger: &logging.Logger{Logger: slog.Default().With("service", "instance")},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ builder = (*InstanceBuilder)(nil)
|
|
||||||
|
|
||||||
func (b *InstanceBuilder) reset() {
|
|
||||||
b.db = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ repository.InstanceRepository = (*InstanceBuilder)(nil)
|
|
||||||
|
|
||||||
// ByDomain implements repository.InstanceRepository.
|
|
||||||
func (b *InstanceBuilder) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByID implements repository.InstanceRepository.
|
|
||||||
func (b *InstanceBuilder) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetUp implements repository.InstanceRepository.
|
|
||||||
func (b *InstanceBuilder) SetUp(ctx context.Context, instance *repository.Instance) error {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
@@ -1,53 +0,0 @@
|
|||||||
package factory
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
|
||||||
)
|
|
||||||
|
|
||||||
// type Middleware[O any, H Handler[O]] interface {
|
|
||||||
// New() H
|
|
||||||
// NewWithNext(next Handler[O]) H
|
|
||||||
// }
|
|
||||||
type Middleware[Req, Res any] interface {
|
|
||||||
New() Handler[Req, Res]
|
|
||||||
NewWithNext(next Handler[Req, Res]) Handler[Req, Res]
|
|
||||||
}
|
|
||||||
|
|
||||||
type Handler[Req, Res any] interface {
|
|
||||||
Handle(ctx context.Context, request Req) (Res, error)
|
|
||||||
SetNext(next Handler[Req, Res])
|
|
||||||
|
|
||||||
Name() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// type InstanceBuilder struct {
|
|
||||||
// tracer *traced.Instance
|
|
||||||
// logger *logged.Instance
|
|
||||||
// cache *cache.Instance
|
|
||||||
// events *event.Instance
|
|
||||||
// db *sql.Instance
|
|
||||||
// }
|
|
||||||
|
|
||||||
type InstanceSetUpBuilder struct {
|
|
||||||
tracer Middleware[*repository.Instance, *repository.Instance]
|
|
||||||
logger Middleware[*repository.Instance, *repository.Instance]
|
|
||||||
cache Middleware[*repository.Instance, *repository.Instance]
|
|
||||||
events Middleware[*repository.Instance, *repository.Instance]
|
|
||||||
db Middleware[*repository.Instance, *repository.Instance]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *InstanceSetUpBuilder) Build() {
|
|
||||||
instance := i.tracer.NewWithNext(
|
|
||||||
i.logger.NewWithNext(
|
|
||||||
i.db.NewWithNext(
|
|
||||||
i.events.NewWithNext(
|
|
||||||
i.cache.New(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
_ = instance
|
|
||||||
// instance.
|
|
||||||
}
|
|
@@ -4,69 +4,39 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/repository/cache"
|
"github.com/zitadel/zitadel/backend/repository/orchestrate"
|
||||||
"github.com/zitadel/zitadel/backend/repository/event"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/sql"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/telemetry/logged"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/telemetry/traced"
|
|
||||||
"github.com/zitadel/zitadel/backend/storage/database"
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
db database.Pool
|
db database.Pool
|
||||||
tracer *tracing.Tracer
|
|
||||||
logger *logging.Logger
|
orchestrator instanceOrchestrator
|
||||||
cache *cache.Instance
|
}
|
||||||
|
|
||||||
|
type instanceOrchestrator interface {
|
||||||
|
ByID(ctx context.Context, querier database.Querier, id string) (*repository.Instance, error)
|
||||||
|
ByDomain(ctx context.Context, querier database.Querier, domain string) (*repository.Instance, error)
|
||||||
|
SetUp(ctx context.Context, tx database.Transaction, instance *repository.Instance) (*repository.Instance, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstance(db database.Pool, tracer *tracing.Tracer, logger *logging.Logger) *Instance {
|
func NewInstance(db database.Pool, tracer *tracing.Tracer, logger *logging.Logger) *Instance {
|
||||||
b := &Instance{
|
b := &Instance{
|
||||||
db: db,
|
db: db,
|
||||||
tracer: tracer,
|
orchestrator: orchestrate.Instance(),
|
||||||
logger: logger,
|
|
||||||
|
|
||||||
cache: &cache.Instance{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Instance) instanceCommandRepo(tx database.Transaction) repository.InstanceRepository {
|
|
||||||
return logged.NewInstance(
|
|
||||||
b.logger,
|
|
||||||
traced.NewInstance(
|
|
||||||
b.tracer,
|
|
||||||
event.NewInstance(
|
|
||||||
eventstore.New(tx),
|
|
||||||
b.cache.SetNext(
|
|
||||||
sql.NewInstance(tx),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Instance) instanceQueryRepo(tx database.QueryExecutor) repository.InstanceRepository {
|
|
||||||
return logged.NewInstance(
|
|
||||||
b.logger,
|
|
||||||
traced.NewInstance(
|
|
||||||
b.tracer,
|
|
||||||
b.cache.SetNext(
|
|
||||||
sql.NewInstance(tx),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
func (b *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
||||||
return b.instanceQueryRepo(b.db).ByID(ctx, id)
|
return b.orchestrator.ByID(ctx, b.db, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
func (b *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
||||||
return b.instanceQueryRepo(b.db).ByDomain(ctx, domain)
|
return b.orchestrator.ByDomain(ctx, b.db, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetUpInstance struct {
|
type SetUpInstance struct {
|
||||||
@@ -82,7 +52,7 @@ func (b *Instance) SetUp(ctx context.Context, request *SetUpInstance) (err error
|
|||||||
defer func() {
|
defer func() {
|
||||||
err = tx.End(ctx, err)
|
err = tx.End(ctx, err)
|
||||||
}()
|
}()
|
||||||
err = b.instanceCommandRepo(tx).SetUp(ctx, request.Instance)
|
_, err = b.orchestrator.SetUp(ctx, tx, request.Instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
118
backend/repository/cache/instance.go
vendored
118
backend/repository/cache/instance.go
vendored
@@ -5,6 +5,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
"github.com/zitadel/zitadel/backend/storage/cache"
|
"github.com/zitadel/zitadel/backend/storage/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,69 +13,88 @@ type Instance struct {
|
|||||||
mu *sync.RWMutex
|
mu *sync.RWMutex
|
||||||
byID cache.Cache[string, *repository.Instance]
|
byID cache.Cache[string, *repository.Instance]
|
||||||
byDomain cache.Cache[string, *repository.Instance]
|
byDomain cache.Cache[string, *repository.Instance]
|
||||||
|
|
||||||
next repository.InstanceRepository
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Instance) SetNext(next repository.InstanceRepository) *Instance {
|
func SetUpInstance(
|
||||||
return &Instance{
|
cache *Instance,
|
||||||
mu: i.mu,
|
handle handler.Handle[*repository.Instance, *repository.Instance],
|
||||||
byID: i.byID,
|
) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
byDomain: i.byDomain,
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
next: next,
|
instance, err := handle(ctx, instance)
|
||||||
}
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// ByDomain implements repository.InstanceRepository.
|
cache.set(instance, "")
|
||||||
func (i *Instance) ByDomain(ctx context.Context, domain string) (instance *repository.Instance, err error) {
|
|
||||||
i.mu.RLock()
|
|
||||||
defer i.mu.RUnlock()
|
|
||||||
|
|
||||||
if instance, ok := i.byDomain.Get(domain); ok {
|
|
||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
instance, err = i.next.ByDomain(ctx, domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
i.set(instance, domain)
|
|
||||||
|
|
||||||
return instance, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByID implements repository.InstanceRepository.
|
func SetUpInstanceWithout(cache *Instance) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
i.mu.RLock()
|
cache.set(instance, "")
|
||||||
defer i.mu.RUnlock()
|
|
||||||
|
|
||||||
if instance, ok := i.byID.Get(id); ok {
|
|
||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
instance, err := i.next.ByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
i.set(instance, "")
|
|
||||||
return instance, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUp implements repository.InstanceRepository.
|
func SetUpInstanceDecorated(
|
||||||
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
|
cache *Instance,
|
||||||
err := i.next.SetUp(ctx, instance)
|
handle handler.Handle[*repository.Instance, *repository.Instance],
|
||||||
if err != nil {
|
decorator handler.Decorate[*repository.Instance, *repository.Instance],
|
||||||
return err
|
) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
}
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
|
instance, err := handle(ctx, instance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
i.set(instance, "")
|
return decorator(ctx, instance, func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
return nil
|
cache.set(instance, "")
|
||||||
|
return instance, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ repository.InstanceRepository = (*Instance)(nil)
|
func ForInstanceByID(cache *Instance, handle handler.Handle[string, *repository.Instance]) handler.Handle[string, *repository.Instance] {
|
||||||
|
return func(ctx context.Context, id string) (*repository.Instance, error) {
|
||||||
|
cache.mu.RLock()
|
||||||
|
|
||||||
|
instance, ok := cache.byID.Get(id)
|
||||||
|
cache.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
instance, err := handle(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.set(instance, "")
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ForInstanceByDomain(cache *Instance, handle handler.Handle[string, *repository.Instance]) handler.Handle[string, *repository.Instance] {
|
||||||
|
return func(ctx context.Context, domain string) (*repository.Instance, error) {
|
||||||
|
cache.mu.RLock()
|
||||||
|
|
||||||
|
instance, ok := cache.byDomain.Get(domain)
|
||||||
|
cache.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
instance, err := handle(ctx, domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.set(instance, domain)
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Instance) set(instance *repository.Instance, domain string) {
|
func (i *Instance) set(instance *repository.Instance, domain string) {
|
||||||
i.mu.Lock()
|
i.mu.Lock()
|
||||||
|
@@ -4,34 +4,59 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ repository.InstanceRepository = (*Instance)(nil)
|
func SetUpInstance(
|
||||||
|
client database.Executor,
|
||||||
|
next handler.Handle[*repository.Instance, *repository.Instance],
|
||||||
|
) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
|
es := eventstore.New(client)
|
||||||
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
|
instance, err := next(ctx, instance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
type Instance struct {
|
err = es.Push(ctx, instance)
|
||||||
*eventstore.Eventstore
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
next repository.InstanceRepository
|
}
|
||||||
}
|
return instance, nil
|
||||||
|
}
|
||||||
func NewInstance(eventstore *eventstore.Eventstore, next repository.InstanceRepository) *Instance {
|
}
|
||||||
return &Instance{next: next, Eventstore: eventstore}
|
|
||||||
}
|
func SetUpInstanceWithout(client database.Executor) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
|
es := eventstore.New(client)
|
||||||
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
return i.next.ByID(ctx, id)
|
err := es.Push(ctx, instance)
|
||||||
}
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
func (i *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
}
|
||||||
return i.next.ByDomain(ctx, domain)
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
|
|
||||||
err := i.next.SetUp(ctx, instance)
|
func SetUpInstanceDecorated(
|
||||||
if err != nil {
|
client database.Executor,
|
||||||
return err
|
next handler.Handle[*repository.Instance, *repository.Instance],
|
||||||
|
decorate handler.Decorate[*repository.Instance, *repository.Instance],
|
||||||
|
) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
|
es := eventstore.New(client)
|
||||||
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
|
instance, err := next(ctx, instance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decorate(ctx, instance, func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
|
err = es.Push(ctx, instance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return instance, nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return i.Push(ctx, instance)
|
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
package repository
|
|
||||||
|
|
||||||
type Handler interface {
|
|
||||||
SetNext(next Handler) Handler
|
|
||||||
}
|
|
@@ -1,38 +1,10 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type InstanceRepository interface {
|
|
||||||
InstanceSetuper
|
|
||||||
instanceByIDQuerier
|
|
||||||
instanceByDomainQuerier
|
|
||||||
}
|
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetUpInstance func(ctx context.Context, instance *Instance) error
|
type ListRequest struct {
|
||||||
|
Limit uint16
|
||||||
type InstanceSetuper interface {
|
|
||||||
SetUp(ctx context.Context, instance *Instance) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstanceByID func(ctx context.Context, id string) (*Instance, error)
|
|
||||||
|
|
||||||
type instanceByIDQuerier interface {
|
|
||||||
ByID(ctx context.Context, id string) (*Instance, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type InstanceByDomain func(ctx context.Context, domain string) (*Instance, error)
|
|
||||||
|
|
||||||
type instanceByDomainQuerier interface {
|
|
||||||
ByDomain(ctx context.Context, domain string) (*Instance, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListInstances func(ctx context.Context) ([]*Instance, error)
|
|
||||||
|
|
||||||
type InstanceLister interface {
|
|
||||||
List(ctx context.Context) ([]*Instance, error)
|
|
||||||
}
|
}
|
||||||
|
26
backend/repository/orchestrate/handler/request_handler.go
Normal file
26
backend/repository/orchestrate/handler/request_handler.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type Handle[Req, Res any] func(ctx context.Context, request Req) (res Res, err error)
|
||||||
|
|
||||||
|
type Decorate[Req, Res any] func(ctx context.Context, request Req, handle Handle[Req, Res]) (res Res, err error)
|
||||||
|
|
||||||
|
func NewChained[Req, Res any](handle Handle[Req, Res], next Handle[Res, Res]) Handle[Req, Res] {
|
||||||
|
return func(ctx context.Context, request Req) (res Res, err error) {
|
||||||
|
res, err = handle(ctx, request)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if next == nil {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
return next(ctx, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDecorated[Req, Res any](decorate Decorate[Req, Res], handle Handle[Req, Res]) Handle[Req, Res] {
|
||||||
|
return func(ctx context.Context, request Req) (res Res, err error) {
|
||||||
|
return decorate(ctx, request, handle)
|
||||||
|
}
|
||||||
|
}
|
72
backend/repository/orchestrate/instance.go
Normal file
72
backend/repository/orchestrate/instance.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package orchestrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/cache"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/event"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/sql"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/telemetry/logged"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/telemetry/traced"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type instance struct {
|
||||||
|
options
|
||||||
|
|
||||||
|
cache *cache.Instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func Instance(opts ...Option) *instance {
|
||||||
|
i := new(instance)
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&i.options)
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instance) apply(o Option) {
|
||||||
|
o(&i.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instance) SetUp(ctx context.Context, tx database.Transaction, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
|
return handler.NewChained(
|
||||||
|
handler.NewDecorated(
|
||||||
|
traced.DecorateHandle[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.SetUp")),
|
||||||
|
sql.SetUpInstance(tx),
|
||||||
|
),
|
||||||
|
handler.NewChained(
|
||||||
|
handler.NewDecorated(
|
||||||
|
traced.DecorateHandle[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.event.SetUp")),
|
||||||
|
event.SetUpInstanceWithout(tx),
|
||||||
|
),
|
||||||
|
handler.NewDecorated(
|
||||||
|
traced.DecorateHandle[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.cache.SetUp")),
|
||||||
|
cache.SetUpInstanceWithout(i.cache),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)(ctx, instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instance) ByID(ctx context.Context, querier database.Querier, id string) (*repository.Instance, error) {
|
||||||
|
return traced.Wrap(i.tracer, "instance.byID",
|
||||||
|
logged.Wrap(i.logger, "instance.byID",
|
||||||
|
cache.ForInstanceByID(i.cache,
|
||||||
|
sql.InstanceByID(querier),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *instance) ByDomain(ctx context.Context, querier database.Querier, domain string) (*repository.Instance, error) {
|
||||||
|
return traced.Wrap(i.tracer, "instance.byDomain",
|
||||||
|
logged.Wrap(i.logger, "instance.byDomain",
|
||||||
|
cache.ForInstanceByDomain(i.cache,
|
||||||
|
sql.InstanceByDomain(querier),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)(ctx, domain)
|
||||||
|
}
|
25
backend/repository/orchestrate/option.go
Normal file
25
backend/repository/orchestrate/option.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package orchestrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
tracer *tracing.Tracer
|
||||||
|
logger *logging.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*options)
|
||||||
|
|
||||||
|
func WithTracer(tracer *tracing.Tracer) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.tracer = tracer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithLogger(logger *logging.Logger) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.logger = logger
|
||||||
|
}
|
||||||
|
}
|
@@ -4,42 +4,42 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
"github.com/zitadel/zitadel/backend/storage/database"
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewInstance(client database.QueryExecutor) repository.InstanceRepository {
|
|
||||||
return &Instance{client: client}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Instance struct {
|
|
||||||
client database.QueryExecutor
|
|
||||||
}
|
|
||||||
|
|
||||||
const instanceByDomainQuery = `SELECT i.id, i.name FROM instances i JOIN instance_domains id ON i.id = id.instance_id WHERE id.domain = $1`
|
const instanceByDomainQuery = `SELECT i.id, i.name FROM instances i JOIN instance_domains id ON i.id = id.instance_id WHERE id.domain = $1`
|
||||||
|
|
||||||
// ByDomain implements [InstanceRepository].
|
func InstanceByDomain(client database.Querier) handler.Handle[string, *repository.Instance] {
|
||||||
func (r *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
return func(ctx context.Context, domain string) (*repository.Instance, error) {
|
||||||
row := r.client.QueryRow(ctx, instanceByDomainQuery, domain)
|
row := client.QueryRow(ctx, instanceByDomainQuery, domain)
|
||||||
var instance repository.Instance
|
var instance repository.Instance
|
||||||
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
|
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}
|
||||||
|
return &instance, nil
|
||||||
}
|
}
|
||||||
return &instance, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const instanceByIDQuery = `SELECT id, name FROM instances WHERE id = $1`
|
const instanceByIDQuery = `SELECT id, name FROM instances WHERE id = $1`
|
||||||
|
|
||||||
// ByID implements [InstanceRepository].
|
func InstanceByID(client database.Querier) handler.Handle[string, *repository.Instance] {
|
||||||
func (r *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
return func(ctx context.Context, id string) (*repository.Instance, error) {
|
||||||
row := r.client.QueryRow(ctx, instanceByIDQuery, id)
|
row := client.QueryRow(ctx, instanceByIDQuery, id)
|
||||||
var instance repository.Instance
|
var instance repository.Instance
|
||||||
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
|
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}
|
||||||
|
return &instance, nil
|
||||||
}
|
}
|
||||||
return &instance, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUp implements [InstanceRepository].
|
func SetUpInstance(tx database.Transaction) handler.Handle[*repository.Instance, *repository.Instance] {
|
||||||
func (r *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
|
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
return r.client.Exec(ctx, "INSERT INTO instances (id, name) VALUES ($1, $2)", instance.ID, instance.Name)
|
err := tx.Exec(ctx, "INSERT INTO instances (id, name) VALUES ($1, $2)", instance.ID, instance.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return instance, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
68
backend/repository/telemetry/logged/global.go
Normal file
68
backend/repository/telemetry/logged/global.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package logged
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wrap decorates the given handle function with logging.
|
||||||
|
// The function is safe to call with nil logger.
|
||||||
|
func Wrap[Req, Res any](logger *logging.Logger, name string, handle handler.Handle[Req, Res]) handler.Handle[Req, Res] {
|
||||||
|
if logger == nil {
|
||||||
|
return handle
|
||||||
|
}
|
||||||
|
return func(ctx context.Context, r Req) (_ Res, err error) {
|
||||||
|
logger.Debug("execute", slog.String("handler", name))
|
||||||
|
defer logger.Debug("done", slog.String("handler", name))
|
||||||
|
return handle(ctx, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapInside(logger *logging.Logger, name string) func(ctx context.Context, fn func(context.Context) error) {
|
||||||
|
logger = logger.With(slog.String("handler", name))
|
||||||
|
return func(ctx context.Context, fn func(context.Context) error) {
|
||||||
|
logger.Debug("execute")
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed", slog.String("cause", err.Error()))
|
||||||
|
}
|
||||||
|
logger.Debug("done")
|
||||||
|
}()
|
||||||
|
err = fn(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecorateHandle[Req, Res any](logger *logging.Logger, handle func(context.Context, Req) (Res, error)) func(ctx context.Context, r Req) (_ Res, err error) {
|
||||||
|
return func(ctx context.Context, r Req) (_ Res, err error) {
|
||||||
|
logger.DebugContext(ctx, "execute")
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, "failed", slog.String("cause", err.Error()))
|
||||||
|
}
|
||||||
|
logger.DebugContext(ctx, "done")
|
||||||
|
}()
|
||||||
|
return handle(ctx, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Handler wraps the given handle function with logging.
|
||||||
|
// // The function is safe to call with nil logger.
|
||||||
|
// func Handler[Req, Res any, H handler.Handle[Req, Res]](logger *logging.Logger, name string, handle H) *handler.Handler[Req, Res, H] {
|
||||||
|
// return &handler.Handler[Req, Res, H]{
|
||||||
|
// Handle: Wrap(logger, name, handle),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Chained wraps the given handle function with logging.
|
||||||
|
// // The function is safe to call with nil logger.
|
||||||
|
// // The next handler is called after the handle function.
|
||||||
|
// func Chained[Req, Res any, H, N handler.Handle[Req, Res]](logger *logging.Logger, name string, handle H, next N) *handler.Chained[Req, Res, H, N] {
|
||||||
|
// return handler.NewChained(
|
||||||
|
// Wrap(logger, name, handle),
|
||||||
|
// next,
|
||||||
|
// )
|
||||||
|
// }
|
@@ -1,41 +0,0 @@
|
|||||||
package logged
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Instance struct {
|
|
||||||
*logging.Logger
|
|
||||||
|
|
||||||
next repository.InstanceRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInstance(logger *logging.Logger, next repository.InstanceRepository) *Instance {
|
|
||||||
return &Instance{Logger: logger, next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ repository.InstanceRepository = (*Instance)(nil)
|
|
||||||
|
|
||||||
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
|
||||||
i.Logger.InfoContext(ctx, "By ID Query", slog.String("id", id))
|
|
||||||
return i.next.ByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
|
||||||
i.Logger.InfoContext(ctx, "By Domain Query", slog.String("domain", domain))
|
|
||||||
return i.next.ByDomain(ctx, domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
|
|
||||||
err := i.next.SetUp(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
i.Logger.ErrorContext(ctx, "Failed to set up instance", slog.Any("instance", instance), slog.Any("cause", err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i.Logger.InfoContext(ctx, "Instance set up", slog.Any("instance", instance))
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
package logged
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
logger *logging.Logger
|
|
||||||
|
|
||||||
next repository.UserRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUser(logger *logging.Logger, next repository.UserRepository) *User {
|
|
||||||
return &User{logger: logger, next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ repository.UserRepository = (*User)(nil)
|
|
||||||
|
|
||||||
func (i *User) ByID(ctx context.Context, id string) (*repository.User, error) {
|
|
||||||
i.logger.InfoContext(ctx, "By ID Query", slog.String("id", id))
|
|
||||||
return i.next.ByID(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *User) Create(ctx context.Context, user *repository.User) error {
|
|
||||||
err := i.next.Create(ctx, user)
|
|
||||||
if err != nil {
|
|
||||||
i.logger.ErrorContext(ctx, "Failed to create user", slog.Any("user", user), slog.Any("cause", err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i.logger.InfoContext(ctx, "User created successfully", slog.Any("user", user))
|
|
||||||
return nil
|
|
||||||
}
|
|
@@ -3,53 +3,75 @@ package traced
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/domain/factory"
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tracer[Req, Res any] struct {
|
// Wrap decorates the given handle function with tracing.
|
||||||
tracing.Tracer
|
// The function is safe to call with nil tracer.
|
||||||
next factory.Handler[Req, Res]
|
func Wrap[Req, Res any](tracer *tracing.Tracer, name string, handle handler.Handle[Req, Res]) handler.Handle[Req, Res] {
|
||||||
}
|
if tracer == nil {
|
||||||
|
return handle
|
||||||
func (*Tracer[Req, Res]) Name() string {
|
|
||||||
return "Tracer"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle implements [factory.Handler].
|
|
||||||
func (t *Tracer[Req, Res]) Handle(ctx context.Context, request Req) (res Res, err error) {
|
|
||||||
if t.next == nil {
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
ctx, span := t.Tracer.Start(
|
return func(ctx context.Context, r Req) (_ Res, err error) {
|
||||||
ctx,
|
ctx, span := tracer.Start(
|
||||||
t.next.Name(),
|
ctx,
|
||||||
)
|
name,
|
||||||
defer func() {
|
)
|
||||||
if err != nil {
|
defer func() {
|
||||||
span.RecordError(err)
|
if err != nil {
|
||||||
|
span.RecordError(err)
|
||||||
|
}
|
||||||
|
span.End()
|
||||||
|
}()
|
||||||
|
return handle(ctx, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapInside(tracer *tracing.Tracer, name string) func(ctx context.Context, fn func() error) {
|
||||||
|
return func(ctx context.Context, fn func() error) {
|
||||||
|
var err error
|
||||||
|
_, span := tracer.Start(
|
||||||
|
ctx,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
span.RecordError(err)
|
||||||
|
}
|
||||||
|
span.End()
|
||||||
|
}()
|
||||||
|
err = fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecorateHandle[Req, Res any](tracer *tracing.Tracer, opts ...tracing.DecorateOption) handler.Decorate[Req, Res] {
|
||||||
|
return func(ctx context.Context, r Req, handle handler.Handle[Req, Res]) (_ Res, err error) {
|
||||||
|
o := new(tracing.DecorateOptions)
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(o)
|
||||||
}
|
}
|
||||||
span.End()
|
|
||||||
}()
|
ctx = o.Start(ctx, tracer)
|
||||||
return t.next.Handle(ctx, request)
|
defer o.End(err)
|
||||||
|
return handle(ctx, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNext implements [factory.Handler].
|
// // Handler wraps the given handle function with tracing.
|
||||||
func (t *Tracer[Req, Res]) SetNext(next factory.Handler[Req, Res]) {
|
// // The function is safe to call with nil logger.
|
||||||
t.next = next
|
// func Handler[Req, Res any, H handler.Handle[Req, Res]](tracer *tracing.Tracer, name string, handle H) *handler.Handler[Req, Res, H] {
|
||||||
}
|
// return &handler.Handler[Req, Res, H]{
|
||||||
|
// Handle: Wrap(tracer, name, handle),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// New implements [factory.Middleware].
|
// // Chained wraps the given handle function with tracing.
|
||||||
func (t *Tracer[Req, Res]) New() factory.Handler[Req, Res] {
|
// // The function is safe to call with nil logger.
|
||||||
return t.NewWithNext(nil)
|
// // The next handler is called after the handle function.
|
||||||
}
|
// func Chained[Req, Res any, H, N handler.Handle[Req, Res]](tracer *tracing.Tracer, name string, handle H, next N) *handler.Chained[Req, Res, H, N] {
|
||||||
|
// return handler.NewChained(
|
||||||
// NewWithNext implements [factory.Middleware].
|
// Wrap(tracer, name, handle),
|
||||||
func (t *Tracer[Req, Res]) NewWithNext(next factory.Handler[Req, Res]) factory.Handler[Req, Res] {
|
// next,
|
||||||
return &Tracer[Req, Res]{Tracer: t.Tracer, next: next}
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
var (
|
|
||||||
_ factory.Middleware[any, any] = (*Tracer[any, any])(nil)
|
|
||||||
_ factory.Handler[any, any] = (*Tracer[any, any])(nil)
|
|
||||||
)
|
|
||||||
|
@@ -1,54 +0,0 @@
|
|||||||
package traced
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ repository.InstanceRepository = (*Instance)(nil)
|
|
||||||
|
|
||||||
type Instance struct {
|
|
||||||
*tracing.Tracer
|
|
||||||
|
|
||||||
next repository.InstanceRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInstance(tracer *tracing.Tracer, next repository.InstanceRepository) *Instance {
|
|
||||||
return &Instance{Tracer: tracer, next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Instance) SetNext(next repository.InstanceRepository) *Instance {
|
|
||||||
return &Instance{Tracer: i.Tracer, next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByDomain implements [repository.InstanceRepository].
|
|
||||||
func (i *Instance) ByDomain(ctx context.Context, domain string) (instance *repository.Instance, err error) {
|
|
||||||
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
|
|
||||||
instance, err = i.next.ByDomain(ctx, domain)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
return instance, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByID implements [repository.InstanceRepository].
|
|
||||||
func (i *Instance) ByID(ctx context.Context, id string) (instance *repository.Instance, err error) {
|
|
||||||
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
|
|
||||||
instance, err = i.next.ByID(ctx, id)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
return instance, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetUp implements [repository.InstanceRepository].
|
|
||||||
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) (err error) {
|
|
||||||
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
|
|
||||||
err = i.next.SetUp(ctx, instance)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
@@ -1,44 +0,0 @@
|
|||||||
package traced
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ repository.UserRepository = (*User)(nil)
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
*tracing.Tracer
|
|
||||||
|
|
||||||
next repository.UserRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUser(tracer *tracing.Tracer, next repository.UserRepository) *User {
|
|
||||||
return &User{Tracer: tracer, next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *User) SetNext(next repository.UserRepository) *User {
|
|
||||||
return &User{Tracer: i.Tracer, next: next}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByID implements [repository.UserRepository].
|
|
||||||
func (i *User) ByID(ctx context.Context, id string) (user *repository.User, err error) {
|
|
||||||
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
|
|
||||||
user, err = i.next.ByID(ctx, id)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
return user, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create implements [repository.UserRepository].
|
|
||||||
func (i *User) Create(ctx context.Context, user *repository.User) (err error) {
|
|
||||||
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
|
|
||||||
err = i.next.Create(ctx, user)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
@@ -19,3 +19,7 @@ type Event interface{}
|
|||||||
func (e *Eventstore) Push(ctx context.Context, events ...Event) error {
|
func (e *Eventstore) Push(ctx context.Context, events ...Event) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Push(ctx context.Context, executor database.Executor, events ...Event) error {
|
||||||
|
return New(executor).Push(ctx, events...)
|
||||||
|
}
|
||||||
|
@@ -5,3 +5,7 @@ import "log/slog"
|
|||||||
type Logger struct {
|
type Logger struct {
|
||||||
*slog.Logger
|
*slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Logger) With(args ...any) *Logger {
|
||||||
|
return &Logger{l.Logger.With(args...)}
|
||||||
|
}
|
||||||
|
@@ -14,51 +14,65 @@ func NewTracer(name string) Tracer {
|
|||||||
return Tracer{otel.Tracer(name)}
|
return Tracer{otel.Tracer(name)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DecorateOption func(*decorateOptions)
|
type DecorateOption func(*DecorateOptions)
|
||||||
|
|
||||||
type decorateOptions struct {
|
type DecorateOptions struct {
|
||||||
startOpts []trace.SpanStartOption
|
startOpts []trace.SpanStartOption
|
||||||
endOpts []trace.SpanEndOption
|
endOpts []trace.SpanEndOption
|
||||||
|
|
||||||
spanName string
|
spanName string
|
||||||
|
|
||||||
|
span trace.Span
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithSpanName(name string) DecorateOption {
|
func WithSpanName(name string) DecorateOption {
|
||||||
return func(o *decorateOptions) {
|
return func(o *DecorateOptions) {
|
||||||
o.spanName = name
|
o.spanName = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithSpanStartOptions(opts ...trace.SpanStartOption) DecorateOption {
|
func WithSpanStartOptions(opts ...trace.SpanStartOption) DecorateOption {
|
||||||
return func(o *decorateOptions) {
|
return func(o *DecorateOptions) {
|
||||||
o.startOpts = append(o.startOpts, opts...)
|
o.startOpts = append(o.startOpts, opts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithSpanEndOptions(opts ...trace.SpanEndOption) DecorateOption {
|
func WithSpanEndOptions(opts ...trace.SpanEndOption) DecorateOption {
|
||||||
return func(o *decorateOptions) {
|
return func(o *DecorateOptions) {
|
||||||
o.endOpts = append(o.endOpts, opts...)
|
o.endOpts = append(o.endOpts, opts...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tracer) Decorate(ctx context.Context, fn func(ctx context.Context) error, opts ...DecorateOption) {
|
func (o *DecorateOptions) Start(ctx context.Context, tracer *Tracer) context.Context {
|
||||||
o := new(decorateOptions)
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.spanName == "" {
|
if o.spanName == "" {
|
||||||
o.spanName = functionName()
|
o.spanName = functionName()
|
||||||
}
|
}
|
||||||
|
ctx, o.span = tracer.Tracer.Start(ctx, o.spanName, o.startOpts...)
|
||||||
_, span := t.Tracer.Start(ctx, o.spanName, o.startOpts...)
|
return ctx
|
||||||
defer span.End(o.endOpts...)
|
|
||||||
|
|
||||||
if err := fn(ctx); err != nil {
|
|
||||||
span.RecordError(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *DecorateOptions) End(err error) {
|
||||||
|
o.span.RecordError(err)
|
||||||
|
o.span.End(o.endOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (t Tracer) Decorate(ctx context.Context, fn func(ctx context.Context) error, opts ...DecorateOption) {
|
||||||
|
// o := new(DecorateOptions)
|
||||||
|
// for _, opt := range opts {
|
||||||
|
// opt(o)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if o.spanName == "" {
|
||||||
|
// o.spanName = functionName()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ctx, span := t.Tracer.Start(ctx, o.spanName, o.startOpts...)
|
||||||
|
// defer span.End(o.endOpts...)
|
||||||
|
|
||||||
|
// err := fn(ctx)
|
||||||
|
// span.RecordError(err)
|
||||||
|
// }
|
||||||
|
|
||||||
func functionName() string {
|
func functionName() string {
|
||||||
counter, _, _, success := runtime.Caller(2)
|
counter, _, _, success := runtime.Caller(2)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user