diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 83f34df990ff1e4a1a128755bcfe548b02aa41ec..e4f5e9be9098cd25885506576ca5ddcc317041d6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: golang:1.22
+image: golang:1.23.2
 
 stages:
   - test
@@ -18,7 +18,7 @@ run_tests:
       junit: report.xml
 
 lint:
-  image: golangci/golangci-lint:v1.56-alpine
+  image: golangci/golangci-lint:v1.61-alpine
   rules:
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
   stage: test
diff --git a/assets/templates/middleware/telemetry_content b/assets/templates/middleware/telemetry_content
new file mode 100644
index 0000000000000000000000000000000000000000..7adcd36c4aef3ea9f3077fcd0771d50c34d406fb
--- /dev/null
+++ b/assets/templates/middleware/telemetry_content
@@ -0,0 +1,121 @@
+import (
+    "context"
+    "time"
+
+    "git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
+    "go.opentelemetry.io/otel"
+    "go.opentelemetry.io/otel/attribute"
+    oid "git.perx.ru/perxis/perxis-go/id"
+    otelmetric "go.opentelemetry.io/otel/metric"
+    "go.opentelemetry.io/otel/trace"
+)
+
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
+{{ $decorator := (or .Vars.DecoratorName "telemetryMiddleware") }}
+{{ $funcName := (or .Vars.FuncName ("TelemetryMiddleware")) }}
+
+// {{$decorator}} implements {{.Interface.Type}} interface instrumented with opentracing spans
+type {{$decorator}} struct {
+  {{.Interface.Type}}
+  _instance string
+  requestMetrics *metrics.RequestMetrics
+  _spanDecorator func(span trace.Span, params, results map[string]interface{})
+}
+
+// {{$funcName}} returns {{$decorator}}
+func {{$funcName}} (base {{.Interface.Type}}, instance string, spanDecorator ...func(span trace.Span, params, results map[string]interface{})) {{$decorator}} {
+  requestMetrics, err := metrics.GetRequestMetrics()
+  if err != nil {
+    panic(err)
+  }
+
+  d := {{$decorator}} {
+    {{.Interface.Name}}: base,
+    _instance: instance,
+    requestMetrics: requestMetrics,
+  }
+
+  if len(spanDecorator) > 0 && spanDecorator[0] != nil {
+    d._spanDecorator = spanDecorator[0]
+  }
+
+  return d
+}
+{{range $method := .Interface.Methods}}
+  {{if $method.AcceptsContext}}
+
+// {{$method.Name}} implements {{$.Interface.Type}}
+func (_d {{$decorator}}) {{$method.Declaration}} {
+  var att = []attribute.KeyValue{
+      attribute.String("service", "{{ $.Interface.Name }}"),
+      attribute.String("method", "{{ $method.Name }}"),
+  }
+  attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
+
+  start := time.Now()
+  ctx, _span := otel.Tracer(_d._instance).Start(ctx, "{{$.Interface.Name}}.{{$method.Name}}")
+  defer _span.End()
+
+  {{ $method.ResultsNames }} = {{ (printf "_d.%s." $.Interface.Name) }}{{ $method.Call }}
+
+  _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+  var spID string
+    {{- $spaceID := "" -}}
+    {{- range $param := $method.Params -}}
+        {{- if (eq $param.Name "spaceId") -}}
+            {{- $spaceID = "spaceId" -}}
+        {{- end -}}
+    {{- end -}}
+    {{- if (eq $spaceID "") -}}
+        {{- $params := list -}}
+        {{- $params = append $params $method.ParamsNames -}}
+        {{- $params = append $params $method.ResultsNames -}}
+
+        {{- $length := len $params }}
+    params := []interface{}{
+        {{- range $index, $paramName := $params | toStrings }}
+            {{- $paramName }}{{- if (ne $index $length) }},{{- end -}}
+        {{- end -}}
+    }
+    for _, p := range params {
+        if p == nil {
+            continue
+        }
+        if sg, ok := p.(spaceGetter); ok {
+            spID = sg.GetSpaceID()
+            if spID != "" {
+                break
+            }
+        }
+    }
+    {{- else }}
+    spID = spaceId
+    {{- end }}
+    if spID != "" {
+        att = append(att, attribute.String("spaceID", spID))
+    }
+    caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+    if caller != nil {
+        att = append(att, attribute.String("caller", caller.String()))
+    }
+
+    _d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+    if _d._spanDecorator != nil {
+      _d._spanDecorator(_span, {{$method.ParamsMap}}, {{$method.ResultsMap}})
+    }{{- if $method.ReturnsError}} else if err != nil {
+      _d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+      _span.RecordError(err)
+      _span.SetAttributes(attribute.String("event", "error"))
+      _span.SetAttributes(attribute.String("message", err.Error()))
+    }
+    {{end}}
+  return {{$method.ResultsNames }}
+}
+  {{end}}
+{{end}}
\ No newline at end of file
diff --git a/assets/templates/middleware/telemetry b/assets/templates/middleware/telemetry_default
similarity index 67%
rename from assets/templates/middleware/telemetry
rename to assets/templates/middleware/telemetry_default
index f35cde213c9523050d863351757fb0ee560c73fe..6616504f1f5db9bd0126eba40dd5b7f8f4d718a0 100644
--- a/assets/templates/middleware/telemetry
+++ b/assets/templates/middleware/telemetry_default
@@ -1,5 +1,3 @@
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
-
 import (
     "context"
     "time"
@@ -7,10 +5,15 @@ import (
     "git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
     "go.opentelemetry.io/otel"
     "go.opentelemetry.io/otel/attribute"
+    oid "git.perx.ru/perxis/perxis-go/id"
     otelmetric "go.opentelemetry.io/otel/metric"
     "go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 {{ $decorator := (or .Vars.DecoratorName "telemetryMiddleware") }}
 {{ $funcName := (or .Vars.FuncName ("TelemetryMiddleware")) }}
 
@@ -41,25 +44,33 @@ func {{$funcName}} (base {{.Interface.Type}}, instance string, spanDecorator ...
 
   return d
 }
-
 {{range $method := .Interface.Methods}}
   {{if $method.AcceptsContext}}
-    // {{$method.Name}} implements {{$.Interface.Type}}
-func (_d {{$decorator}}) {{$method.Declaration}} {
-  attributes := otelmetric.WithAttributeSet(attribute.NewSet(
-    attribute.String("service", "{{ $.Interface.Name }}"),
-    attribute.String("method", "{{ $method.Name }}"),
-  ))
 
-  _d.requestMetrics.Total.Add(ctx, 1, attributes)
+// {{$method.Name}} implements {{$.Interface.Type}}
+func (_d {{$decorator}}) {{$method.Declaration}} {
+  var att = []attribute.KeyValue{
+      attribute.String("service", "{{ $.Interface.Name }}"),
+      attribute.String("method", "{{ $method.Name }}"),
+  }
+  attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
   start := time.Now()
   ctx, _span := otel.Tracer(_d._instance).Start(ctx, "{{$.Interface.Name}}.{{$method.Name}}")
+  defer _span.End()
+
+  {{ $method.ResultsNames }} = {{ (printf "_d.%s." $.Interface.Name) }}{{ $method.Call }}
+
+  _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+  caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+  if caller != nil {
+    att = append(att, attribute.String("caller", caller.String()))
+  }
 
-  defer func() {
-    _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+  _d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-    if _d._spanDecorator != nil {
+  if _d._spanDecorator != nil {
       _d._spanDecorator(_span, {{$method.ParamsMap}}, {{$method.ResultsMap}})
     }{{- if $method.ReturnsError}} else if err != nil {
       _d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
@@ -69,9 +80,7 @@ func (_d {{$decorator}}) {{$method.Declaration}} {
       _span.SetAttributes(attribute.String("message", err.Error()))
     }
     {{end}}
-    _span.End()
-  }()
-  {{$method.Pass (printf "_d.%s." $.Interface.Name) }}
+  return {{$method.ResultsNames }}
 }
   {{end}}
 {{end}}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 372a5f1f61d2f523d327d630e73fa21f0aad2eac..1f94424c686dc81bb80569395734cae6eeddfb2b 100644
--- a/go.mod
+++ b/go.mod
@@ -1,31 +1,31 @@
 module git.perx.ru/perxis/perxis-go
 
-go 1.22
+go 1.23.2
 
 require (
-	github.com/avast/retry-go/v4 v4.5.1
-	github.com/bep/gowebp v0.2.0
-	github.com/expr-lang/expr v1.15.8
+	github.com/avast/retry-go/v4 v4.6.0
+	github.com/bep/gowebp v0.4.0
+	github.com/expr-lang/expr v1.16.9
 	github.com/go-kit/kit v0.13.0
-	github.com/gosimple/slug v1.13.1
+	github.com/gosimple/slug v1.14.0
 	github.com/hashicorp/go-multierror v1.1.1
 	github.com/hashicorp/golang-lru/v2 v2.0.7
 	github.com/json-iterator/go v1.1.12
 	github.com/mitchellh/mapstructure v1.5.0
-	github.com/nats-io/nats.go v1.31.0
+	github.com/nats-io/nats.go v1.37.0
 	github.com/pkg/errors v0.9.1
-	github.com/rs/xid v1.5.0
-	github.com/stretchr/testify v1.8.4
-	go.mongodb.org/mongo-driver v1.13.0
-	go.opentelemetry.io/otel v1.24.0
-	go.opentelemetry.io/otel/trace v1.24.0
-	go.uber.org/zap v1.26.0
-	golang.org/x/crypto v0.23.0
-	golang.org/x/image v0.14.0
-	golang.org/x/net v0.25.0
-	golang.org/x/oauth2 v0.18.0
-	google.golang.org/grpc v1.64.0
-	google.golang.org/protobuf v1.34.1
+	github.com/rs/xid v1.6.0
+	github.com/stretchr/testify v1.9.0
+	go.mongodb.org/mongo-driver v1.17.1
+	go.opentelemetry.io/otel v1.30.0
+	go.opentelemetry.io/otel/trace v1.30.0
+	go.uber.org/zap v1.27.0
+	golang.org/x/crypto v0.27.0
+	golang.org/x/image v0.20.0
+	golang.org/x/net v0.29.0
+	golang.org/x/oauth2 v0.23.0
+	google.golang.org/grpc v1.67.1
+	google.golang.org/protobuf v1.34.2
 	gopkg.in/yaml.v3 v3.0.1
 )
 
@@ -35,36 +35,33 @@ require (
 )
 
 require (
-	cloud.google.com/go/compute v1.25.1 // indirect
-	cloud.google.com/go/compute/metadata v0.2.3 // indirect
-	github.com/brianvoe/gofakeit/v6 v6.26.3
+	cloud.google.com/go/compute/metadata v0.5.2 // indirect
+	github.com/brianvoe/gofakeit/v6 v6.28.0
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/go-kit/log v0.2.1 // indirect
 	github.com/go-logfmt/logfmt v0.6.0 // indirect
-	github.com/go-logr/logr v1.4.1 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
-	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/gosimple/unidecode v1.0.1 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
-	github.com/klauspost/compress v1.17.3 // indirect
+	github.com/klauspost/compress v1.17.10 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/montanaflynn/stats v0.7.1 // indirect
-	github.com/nats-io/nkeys v0.4.6 // indirect
+	github.com/nats-io/nkeys v0.4.7 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/stretchr/objx v0.5.1 // indirect
+	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.2 // indirect
 	github.com/xdg-go/stringprep v1.0.4 // indirect
-	github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
-	go.opentelemetry.io/otel/metric v1.24.0
+	github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
+	go.opentelemetry.io/otel/metric v1.30.0
 	go.uber.org/multierr v1.11.0 // indirect
-	golang.org/x/sync v0.6.0 // indirect
-	golang.org/x/sys v0.22.0 // indirect
-	golang.org/x/text v0.15.0
-	google.golang.org/appengine v1.6.8 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.25.0 // indirect
+	golang.org/x/text v0.18.0
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 )
diff --git a/go.sum b/go.sum
index 7f00103fa5b26228e50be943d05c23325cbdc38c..4b2f278b81ef6999417ee78fb77df8203b8073db 100644
--- a/go.sum
+++ b/go.sum
@@ -1,19 +1,17 @@
-cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
-cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
-cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
-cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
-github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
-github.com/bep/gowebp v0.2.0 h1:ZVfK8i9PpZqKHEmthQSt3qCnnHycbLzBPEsVtk2ch2Q=
-github.com/bep/gowebp v0.2.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2AgI=
-github.com/brianvoe/gofakeit/v6 v6.26.3 h1:3ljYrjPwsUNAUFdUIr2jVg5EhKdcke/ZLop7uVg1Er8=
-github.com/brianvoe/gofakeit/v6 v6.26.3/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
+cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
+cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
+github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
+github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
+github.com/bep/gowebp v0.4.0 h1:QihuVnvIKbRoeBNQkN0JPMM8ClLmD6V2jMftTFwSK3Q=
+github.com/bep/gowebp v0.4.0/go.mod h1:95gtYkAA8iIn1t3HkAPurRCVGV/6NhgaHJ1urz0iIwc=
+github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
+github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 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/expr-lang/expr v1.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI=
-github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
+github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
+github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
 github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
 github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
 github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
@@ -21,24 +19,17 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj
 github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
 github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
-github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q=
-github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
+github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es=
+github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
 github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
 github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -50,9 +41,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
 github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
-github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
+github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -67,13 +57,12 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
 github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
-github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E=
-github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8=
-github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
-github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
+github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
+github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
+github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
+github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
 github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -84,103 +73,82 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
-github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-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/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/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
 github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
 github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
 github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
-github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
-github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
-github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
+github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.mongodb.org/mongo-driver v1.13.0 h1:67DgFFjYOCMWdtTEmKFpV3ffWlFnh+CYZ8ZS/tXWUfY=
-go.mongodb.org/mongo-driver v1.13.0/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ=
-go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
-go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
-go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
-go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
-go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
-go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
-go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
-go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
+go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
+go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
+go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
+go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
+go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
+go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
+go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
+go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
-go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
-golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
-golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
+golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
+golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
+golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
-golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
+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/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
+golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
-google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e h1:Elxv5MwEkCI9f5SkoL6afed6NTdxaGoAo39eANBwHL8=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
-google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
-google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
-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.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
+google.golang.org/grpc v1.67.1/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.0-20200313102051-9f266ea9e77c/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=
diff --git a/id/object_id.go b/id/object_id.go
index e84ea1c0fff9960bfef7584fbd68699509cfa2a6..3a3ff12641fd9dfee4ac458a3677fad3a4f0a501 100644
--- a/id/object_id.go
+++ b/id/object_id.go
@@ -1,11 +1,12 @@
 package id
 
 import (
+	"strings"
+
 	jsoniter "github.com/json-iterator/go"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/bsonrw"
 	"go.mongodb.org/mongo-driver/bson/bsontype"
-	"strings"
 )
 
 const Separator = '/'
diff --git a/images/middleware/telemetry_middleware.go b/images/middleware/telemetry_middleware.go
index 72d38c2e1d91813383116398e5c41b9bb93004f4..36d09a320a2bd7fa92ceaa341fad44c89989942b 100644
--- a/images/middleware/telemetry_middleware.go
+++ b/images/middleware/telemetry_middleware.go
@@ -1,18 +1,18 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\assets\templates\middleware\telemetry
+// template: ../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/images -i Images -t ..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/images -i Images -t ../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
 	"git.perx.ru/perxis/perxis-go/images"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/files"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements images.Images interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	images.Images
@@ -51,35 +55,41 @@ func TelemetryMiddleware(base images.Images, instance string, spanDecorator ...f
 
 // Get implements images.Images
 func (_d telemetryMiddleware) Get(ctx context.Context, source *files.File, opts *images.GetOptions) (result *files.File, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Images"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Images.Get")
+	defer _span.End()
+
+	result, err = _d.Images.Get(ctx, source, opts)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"source": source,
+			"opts":   opts}, map[string]interface{}{
+			"result": result,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"source": source,
-				"opts":   opts}, map[string]interface{}{
-				"result": result,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Images.Get(ctx, source, opts)
+	return result, err
 }
diff --git a/logs/middleware/telemetry_middleware.go b/logs/middleware/telemetry_middleware.go
index 2aebc795b22d770c369f0445bfa543bde6828ac2..3731386368aeb9cdd4678a1e3bd65d892798c610 100644
--- a/logs/middleware/telemetry_middleware.go
+++ b/logs/middleware/telemetry_middleware.go
@@ -1,18 +1,18 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ../../assets/templates/middleware/telemetry
+// template: ../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/logs -i Service -t ../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/logs -i Service -t ../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
 	"git.perx.ru/perxis/perxis-go/logs"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/options"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements logs.Service interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	logs.Service
@@ -51,101 +55,119 @@ func TelemetryMiddleware(base logs.Service, instance string, spanDecorator ...fu
 
 // Delete implements logs.Service
 func (_d telemetryMiddleware) Delete(ctx context.Context, filter *logs.Filter) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Service"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Service.Delete")
+	defer _span.End()
+
+	err = _d.Service.Delete(ctx, filter)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"filter": filter}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"filter": filter}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Service.Delete(ctx, filter)
+	return err
 }
 
 // Find implements logs.Service
 func (_d telemetryMiddleware) Find(ctx context.Context, filter *logs.Filter, options *options.FindOptions) (fp1 *logs.FindResult, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Service"),
 		attribute.String("method", "Find"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Service.Find")
+	defer _span.End()
+
+	fp1, err = _d.Service.Find(ctx, filter, options)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"filter":  filter,
-				"options": options}, map[string]interface{}{
-				"fp1": fp1,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Service.Find(ctx, filter, options)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"filter":  filter,
+			"options": options}, map[string]interface{}{
+			"fp1": fp1,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return fp1, err
 }
 
 // Log implements logs.Service
 func (_d telemetryMiddleware) Log(ctx context.Context, entries []*logs.Entry) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Service"),
 		attribute.String("method", "Log"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Service.Log")
+	defer _span.End()
+
+	err = _d.Service.Log(ctx, entries)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"entries": entries}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"entries": entries}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Service.Log(ctx, entries)
+	return err
 }
diff --git a/pkg/clients/client.go b/pkg/clients/client.go
index 6c4c6735b8ec91f226ba5306b2649252390ffc67..447c523aaf5ae8692421e85567973f407007561a 100644
--- a/pkg/clients/client.go
+++ b/pkg/clients/client.go
@@ -50,6 +50,10 @@ func (c Client) GetID() string {
 	return c.ID
 }
 
+func (c Client) GetSpaceID() string {
+	return c.SpaceID
+}
+
 func (c *Client) SetDisabled(b bool) *Client {
 	c.Disabled = &b
 	return c
diff --git a/pkg/clients/middleware/telemetry_middleware.go b/pkg/clients/middleware/telemetry_middleware.go
index 22c604f2d5be413681ccdb933eb5c33a61517cc6..cbb217153db160631a1e71ebf9d48d68cd787ebc 100644
--- a/pkg/clients/middleware/telemetry_middleware.go
+++ b/pkg/clients/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/clients -i Clients -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/clients -i Clients -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/clients"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements clients.Clients interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	clients.Clients
@@ -50,240 +54,339 @@ func TelemetryMiddleware(base clients.Clients, instance string, spanDecorator ..
 
 // Create implements clients.Clients
 func (_d telemetryMiddleware) Create(ctx context.Context, client *clients.Client) (created *clients.Client, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Create")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"client": client}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	created, err = _d.Clients.Create(ctx, client)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, client, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"client": client}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Clients.Create(ctx, client)
+	return created, err
 }
 
 // Delete implements clients.Clients
 func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, id string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"id":      id}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Clients.Delete(ctx, spaceId, id)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-		_span.End()
-	}()
-	return _d.Clients.Delete(ctx, spaceId, id)
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"id":      id}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Enable implements clients.Clients
 func (_d telemetryMiddleware) Enable(ctx context.Context, spaceId string, id string, enable bool) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "Enable"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Enable")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"id":      id,
-				"enable":  enable}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Clients.Enable(ctx, spaceId, id, enable)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Clients.Enable(ctx, spaceId, id, enable)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"id":      id,
+			"enable":  enable}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Get implements clients.Clients
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, id string) (client *clients.Client, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"id":      id}, map[string]interface{}{
-				"client": client,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	client, err = _d.Clients.Get(ctx, spaceId, id)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Clients.Get(ctx, spaceId, id)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"id":      id}, map[string]interface{}{
+			"client": client,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return client, err
 }
 
 // GetBy implements clients.Clients
 func (_d telemetryMiddleware) GetBy(ctx context.Context, spaceId string, params *clients.GetByParams) (client *clients.Client, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "GetBy"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.GetBy")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"params":  params}, map[string]interface{}{
-				"client": client,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	client, err = _d.Clients.GetBy(ctx, spaceId, params)
 
-		_span.End()
-	}()
-	return _d.Clients.GetBy(ctx, spaceId, params)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"params":  params}, map[string]interface{}{
+			"client": client,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return client, err
 }
 
 // List implements clients.Clients
 func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (clients []*clients.Client, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "List"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.List")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"clients": clients,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	clients, err = _d.Clients.List(ctx, spaceId)
 
-		_span.End()
-	}()
-	return _d.Clients.List(ctx, spaceId)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"clients": clients,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return clients, err
 }
 
 // Update implements clients.Clients
 func (_d telemetryMiddleware) Update(ctx context.Context, client *clients.Client) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Clients"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Clients.Update")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Clients.Update(ctx, client)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"client": client}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, client, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"client": client}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Clients.Update(ctx, client)
+	return err
 }
diff --git a/pkg/collaborators/collaborator.go b/pkg/collaborators/collaborator.go
index 5fe1b481c231568af13b9c9e827eede723312576..b3406960b899f66ce498358d8a3199eb223e9de0 100644
--- a/pkg/collaborators/collaborator.go
+++ b/pkg/collaborators/collaborator.go
@@ -13,3 +13,7 @@ func (c Collaborator) Clone() *Collaborator {
 		Role:    c.Role,
 	}
 }
+
+func (c *Collaborator) GetSpaceID() string {
+	return c.SpaceID
+}
diff --git a/pkg/collaborators/middleware/telemetry_middleware.go b/pkg/collaborators/middleware/telemetry_middleware.go
index cd95016628ed34da1c6fdd5c951a14c766a8cabc..d4a6f56ccbc0d2b5334d596c8ca88932d677017b 100644
--- a/pkg/collaborators/middleware/telemetry_middleware.go
+++ b/pkg/collaborators/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/collaborators -i Collaborators -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/collaborators -i Collaborators -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/collaborators"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements collaborators.Collaborators interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	collaborators.Collaborators
@@ -50,172 +54,238 @@ func TelemetryMiddleware(base collaborators.Collaborators, instance string, span
 
 // Get implements collaborators.Collaborators
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, subject string) (role string, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collaborators"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"subject": subject}, map[string]interface{}{
-				"role": role,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	role, err = _d.Collaborators.Get(ctx, spaceId, subject)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-		_span.End()
-	}()
-	return _d.Collaborators.Get(ctx, spaceId, subject)
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"subject": subject}, map[string]interface{}{
+			"role": role,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return role, err
 }
 
 // ListCollaborators implements collaborators.Collaborators
 func (_d telemetryMiddleware) ListCollaborators(ctx context.Context, spaceId string) (collaborators []*collaborators.Collaborator, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collaborators"),
 		attribute.String("method", "ListCollaborators"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.ListCollaborators")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"collaborators": collaborators,
-				"err":           err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	collaborators, err = _d.Collaborators.ListCollaborators(ctx, spaceId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"collaborators": collaborators,
+			"err":           err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Collaborators.ListCollaborators(ctx, spaceId)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return collaborators, err
 }
 
 // ListSpaces implements collaborators.Collaborators
 func (_d telemetryMiddleware) ListSpaces(ctx context.Context, subject string) (spaces []*collaborators.Collaborator, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collaborators"),
 		attribute.String("method", "ListSpaces"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.ListSpaces")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"subject": subject}, map[string]interface{}{
-				"spaces": spaces,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	spaces, err = _d.Collaborators.ListSpaces(ctx, subject)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, subject, spaces, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"subject": subject}, map[string]interface{}{
+			"spaces": spaces,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collaborators.ListSpaces(ctx, subject)
+	return spaces, err
 }
 
 // Remove implements collaborators.Collaborators
 func (_d telemetryMiddleware) Remove(ctx context.Context, spaceId string, subject string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collaborators"),
 		attribute.String("method", "Remove"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.Remove")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"subject": subject}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Collaborators.Remove(ctx, spaceId, subject)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collaborators.Remove(ctx, spaceId, subject)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"subject": subject}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Set implements collaborators.Collaborators
 func (_d telemetryMiddleware) Set(ctx context.Context, spaceId string, subject string, role string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collaborators"),
 		attribute.String("method", "Set"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collaborators.Set")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"subject": subject,
-				"role":    role}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Collaborators.Set(ctx, spaceId, subject, role)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"subject": subject,
+			"role":    role}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collaborators.Set(ctx, spaceId, subject, role)
+	return err
 }
diff --git a/pkg/collections/collection.go b/pkg/collections/collection.go
index b5d2418aac40332c99b08b31a5df128007e1b7a6..2baeffc6b3f87b90c281aebd5dae85c57d93a5cd 100644
--- a/pkg/collections/collection.go
+++ b/pkg/collections/collection.go
@@ -97,6 +97,10 @@ func (c Collection) GetID() string {
 	return c.ID
 }
 
+func (c Collection) GetSpaceID() string {
+	return c.SpaceID
+}
+
 // Equal сравнивает две коллекции, за исключением Schema, Access, StateInfo и Config
 func (c Collection) Equal(other *Collection) bool {
 	if c.ID != other.ID ||
diff --git a/pkg/collections/middleware/telemetry_middleware.go b/pkg/collections/middleware/telemetry_middleware.go
index 306570dba01ac1d7faaf193d92f97820369a6ad2..c189a7bebaf727b818aa3f37ecb828ff89de6391 100644
--- a/pkg/collections/middleware/telemetry_middleware.go
+++ b/pkg/collections/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/collections -i Collections -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/collections -i Collections -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/collections"
 	"git.perx.ru/perxis/perxis-go/pkg/schema"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements collections.Collections interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	collections.Collections
@@ -51,247 +55,346 @@ func TelemetryMiddleware(base collections.Collections, instance string, spanDeco
 
 // Create implements collections.Collections
 func (_d telemetryMiddleware) Create(ctx context.Context, collection *collections.Collection) (created *collections.Collection, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Create")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":        ctx,
-				"collection": collection}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	created, err = _d.Collections.Create(ctx, collection)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, collection, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Collections.Create(ctx, collection)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":        ctx,
+			"collection": collection}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return created, err
 }
 
 // Delete implements collections.Collections
 func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId string, collectionId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Collections.Delete(ctx, spaceId, envId, collectionId)
 
-		_span.End()
-	}()
-	return _d.Collections.Delete(ctx, spaceId, envId, collectionId)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Get implements collections.Collections
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, options ...*collections.GetOptions) (collection *collections.Collection, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"options":      options}, map[string]interface{}{
-				"collection": collection,
-				"err":        err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	collection, err = _d.Collections.Get(ctx, spaceId, envId, collectionId, options...)
 
-		_span.End()
-	}()
-	return _d.Collections.Get(ctx, spaceId, envId, collectionId, options...)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"options":      options}, map[string]interface{}{
+			"collection": collection,
+			"err":        err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return collection, err
 }
 
 // List implements collections.Collections
 func (_d telemetryMiddleware) List(ctx context.Context, spaceId string, envId string, filter *collections.Filter) (collections []*collections.Collection, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "List"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.List")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId,
-				"filter":  filter}, map[string]interface{}{
-				"collections": collections,
-				"err":         err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	collections, err = _d.Collections.List(ctx, spaceId, envId, filter)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collections.List(ctx, spaceId, envId, filter)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId,
+			"filter":  filter}, map[string]interface{}{
+			"collections": collections,
+			"err":         err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return collections, err
 }
 
 // SetSchema implements collections.Collections
 func (_d telemetryMiddleware) SetSchema(ctx context.Context, spaceId string, envId string, collectionId string, schema *schema.Schema) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "SetSchema"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.SetSchema")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"schema":       schema}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Collections.SetSchema(ctx, spaceId, envId, collectionId, schema)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collections.SetSchema(ctx, spaceId, envId, collectionId, schema)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"schema":       schema}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // SetState implements collections.Collections
 func (_d telemetryMiddleware) SetState(ctx context.Context, spaceId string, envId string, collectionId string, state *collections.StateInfo) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "SetState"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.SetState")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"state":        state}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Collections.SetState(ctx, spaceId, envId, collectionId, state)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collections.SetState(ctx, spaceId, envId, collectionId, state)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"state":        state}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Update implements collections.Collections
 func (_d telemetryMiddleware) Update(ctx context.Context, coll *collections.Collection) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Collections"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Collections.Update")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Collections.Update(ctx, coll)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"coll": coll}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, coll, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"coll": coll}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Collections.Update(ctx, coll)
+	return err
 }
diff --git a/pkg/delivery/middleware/telemetry_middleware.go b/pkg/delivery/middleware/telemetry_middleware.go
index 05a017300c0b2d60c0cc03df333c62365babffa6..600b6a61caec8391507735e01d12d82ee822c8e3 100644
--- a/pkg/delivery/middleware/telemetry_middleware.go
+++ b/pkg/delivery/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/delivery -i Delivery -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/delivery -i Delivery -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/collections"
 	"git.perx.ru/perxis/perxis-go/pkg/delivery"
 	"git.perx.ru/perxis/perxis-go/pkg/environments"
@@ -24,6 +24,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements delivery.Delivery interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	delivery.Delivery
@@ -54,289 +58,377 @@ func TelemetryMiddleware(base delivery.Delivery, instance string, spanDecorator
 
 // Aggregate implements delivery.Delivery
 func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "Aggregate"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.Aggregate")
+	defer _span.End()
+
+	result, err = _d.Delivery.Aggregate(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"result": result,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.Aggregate(ctx, spaceId, envId, collectionId, filter, options...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"result": result,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return result, err
 }
 
 // FindItems implements delivery.Delivery
 func (_d telemetryMiddleware) FindItems(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "FindItems"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.FindItems")
+	defer _span.End()
+
+	items, total, err = _d.Delivery.FindItems(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"items": items,
+			"total": total,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"items": items,
-				"total": total,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.FindItems(ctx, spaceId, envId, collectionId, filter, options...)
+	return items, total, err
 }
 
 // GetCollection implements delivery.Delivery
 func (_d telemetryMiddleware) GetCollection(ctx context.Context, spaceId string, envId string, collectionId string) (collection *collections.Collection, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "GetCollection"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.GetCollection")
+	defer _span.End()
+
+	collection, err = _d.Delivery.GetCollection(ctx, spaceId, envId, collectionId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId}, map[string]interface{}{
+			"collection": collection,
+			"err":        err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId}, map[string]interface{}{
-				"collection": collection,
-				"err":        err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.GetCollection(ctx, spaceId, envId, collectionId)
+	return collection, err
 }
 
 // GetEnvironment implements delivery.Delivery
 func (_d telemetryMiddleware) GetEnvironment(ctx context.Context, spaceId string, envId string) (env *environments.Environment, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "GetEnvironment"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.GetEnvironment")
+	defer _span.End()
+
+	env, err = _d.Delivery.GetEnvironment(ctx, spaceId, envId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId}, map[string]interface{}{
-				"env": env,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.GetEnvironment(ctx, spaceId, envId)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId}, map[string]interface{}{
+			"env": env,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return env, err
 }
 
 // GetItem implements delivery.Delivery
 func (_d telemetryMiddleware) GetItem(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "GetItem"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.GetItem")
+	defer _span.End()
+
+	item, err = _d.Delivery.GetItem(ctx, spaceId, envId, collectionId, itemId, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"itemId":       itemId,
+			"options":      options}, map[string]interface{}{
+			"item": item,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"itemId":       itemId,
-				"options":      options}, map[string]interface{}{
-				"item": item,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.GetItem(ctx, spaceId, envId, collectionId, itemId, options...)
+	return item, err
 }
 
 // ListCollections implements delivery.Delivery
 func (_d telemetryMiddleware) ListCollections(ctx context.Context, spaceId string, envId string) (collections []*collections.Collection, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "ListCollections"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.ListCollections")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId}, map[string]interface{}{
-				"collections": collections,
-				"err":         err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.ListCollections(ctx, spaceId, envId)
+	collections, err = _d.Delivery.ListCollections(ctx, spaceId, envId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId}, map[string]interface{}{
+			"collections": collections,
+			"err":         err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return collections, err
 }
 
 // ListEnvironments implements delivery.Delivery
 func (_d telemetryMiddleware) ListEnvironments(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "ListEnvironments"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.ListEnvironments")
+	defer _span.End()
+
+	envs, err = _d.Delivery.ListEnvironments(ctx, spaceId)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"envs": envs,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.ListEnvironments(ctx, spaceId)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"envs": envs,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return envs, err
 }
 
 // ListLocales implements delivery.Delivery
 func (_d telemetryMiddleware) ListLocales(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Delivery"),
 		attribute.String("method", "ListLocales"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Delivery.ListLocales")
+	defer _span.End()
+
+	locales, err = _d.Delivery.ListLocales(ctx, spaceId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"locales": locales,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"locales": locales,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Delivery.ListLocales(ctx, spaceId)
+	return locales, err
 }
diff --git a/pkg/environments/environment.go b/pkg/environments/environment.go
index 3e0f7bb62a0be1d2fbef334322a6cb315060af8a..6ccfc2558e90e14c94925bdd29f56df71aac22b9 100644
--- a/pkg/environments/environment.go
+++ b/pkg/environments/environment.go
@@ -104,3 +104,7 @@ func (e Environment) Clone() *Environment {
 
 	return clone
 }
+
+func (e Environment) GetSpaceID() string {
+	return e.SpaceID
+}
diff --git a/pkg/environments/middleware/telemetry_middleware.go b/pkg/environments/middleware/telemetry_middleware.go
index 95b50dbc590f134386747a2fb4810455e7f2a800..f1fb94c767248ac3db42617e9f8c0475ddcece64 100644
--- a/pkg/environments/middleware/telemetry_middleware.go
+++ b/pkg/environments/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/environments -i Environments -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/environments -i Environments -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/environments"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements environments.Environments interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	environments.Environments
@@ -50,275 +54,385 @@ func TelemetryMiddleware(base environments.Environments, instance string, spanDe
 
 // Create implements environments.Environments
 func (_d telemetryMiddleware) Create(ctx context.Context, env *environments.Environment) (created *environments.Environment, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Create")
+	defer _span.End()
+
+	created, err = _d.Environments.Create(ctx, env)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"env": env}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, env, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Environments.Create(ctx, env)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"env": env}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return created, err
 }
 
 // Delete implements environments.Environments
 func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Environments.Delete(ctx, spaceId, envId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Environments.Delete(ctx, spaceId, envId)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Get implements environments.Environments
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string) (env *environments.Environment, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId}, map[string]interface{}{
-				"env": env,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	env, err = _d.Environments.Get(ctx, spaceId, envId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-		_span.End()
-	}()
-	return _d.Environments.Get(ctx, spaceId, envId)
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId}, map[string]interface{}{
+			"env": env,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return env, err
 }
 
 // List implements environments.Environments
 func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (envs []*environments.Environment, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "List"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.List")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"envs": envs,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	envs, err = _d.Environments.List(ctx, spaceId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Environments.List(ctx, spaceId)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"envs": envs,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return envs, err
 }
 
 // Migrate implements environments.Environments
 func (_d telemetryMiddleware) Migrate(ctx context.Context, spaceId string, envId string, options ...*environments.MigrateOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "Migrate"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Migrate")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Environments.Migrate(ctx, spaceId, envId, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Environments.Migrate(ctx, spaceId, envId, options...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // RemoveAlias implements environments.Environments
 func (_d telemetryMiddleware) RemoveAlias(ctx context.Context, spaceId string, envId string, alias string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "RemoveAlias"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.RemoveAlias")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId,
-				"alias":   alias}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Environments.RemoveAlias(ctx, spaceId, envId, alias)
 
-		_span.End()
-	}()
-	return _d.Environments.RemoveAlias(ctx, spaceId, envId, alias)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId,
+			"alias":   alias}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // SetAlias implements environments.Environments
 func (_d telemetryMiddleware) SetAlias(ctx context.Context, spaceId string, envId string, alias string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "SetAlias"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.SetAlias")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"envId":   envId,
-				"alias":   alias}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Environments.SetAlias(ctx, spaceId, envId, alias)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"envId":   envId,
+			"alias":   alias}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Environments.SetAlias(ctx, spaceId, envId, alias)
+	return err
 }
 
 // Update implements environments.Environments
 func (_d telemetryMiddleware) Update(ctx context.Context, env *environments.Environment) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Environments"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Environments.Update")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Environments.Update(ctx, env)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"env": env}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, env, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"env": env}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Environments.Update(ctx, env)
+	return err
 }
diff --git a/pkg/expr/config.go b/pkg/expr/config.go
index e6ba9d90b4f4e04c56c17b8591d4a92e30984e6c..130342b812b8798bd5d94b564fd5f27296facff5 100644
--- a/pkg/expr/config.go
+++ b/pkg/expr/config.go
@@ -16,7 +16,6 @@ func (c *ExprConfig) RegisterOption(opt ...expr.Option) {
 func (c *ExprConfig) GetConfig(e map[string]interface{}) *conf.Config {
 	cfg := conf.New(e)
 
-	cfg.Operators = make(map[string][]string)
 	for _, opt := range c.options {
 		opt(cfg)
 	}
@@ -38,9 +37,9 @@ func GetDefaultConfig(e map[string]interface{}) *conf.Config {
 	return defaultConfig.GetConfig(e)
 }
 
-//func GetDefaultEnv(e map[string]interface{}) map[string]interface{} {
+// func GetDefaultEnv(e map[string]interface{}) map[string]interface{} {
 //	return defaultConfig.GetEnv(e)
-//}
+// }
 
 func Extend(kv ...interface{}) expr.Option {
 	e := make(map[string]interface{})
diff --git a/pkg/extension/middleware/telemetry_middleware.go b/pkg/extension/middleware/telemetry_middleware.go
index 764e7cbd2de929e5550b8175a5ec7713b361f3cb..7302cab3b4ecf364f475b0dbe7d77a37c96cd784 100644
--- a/pkg/extension/middleware/telemetry_middleware.go
+++ b/pkg/extension/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ../../../assets/templates/middleware/telemetry
+// template: ../../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/extension -i Manager -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/extension -i Manager -t ../../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/extension"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements extension.Manager interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	extension.Manager
@@ -50,269 +54,317 @@ func TelemetryMiddleware(base extension.Manager, instance string, spanDecorator
 
 // Action implements extension.Manager
 func (_d telemetryMiddleware) Action(ctx context.Context, in *extension.ActionRequest) (ap1 *extension.ActionResponse, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "Action"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.Action")
+	defer _span.End()
+
+	ap1, err = _d.Manager.Action(ctx, in)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"in":  in}, map[string]interface{}{
+			"ap1": ap1,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"in":  in}, map[string]interface{}{
-				"ap1": ap1,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.Action(ctx, in)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return ap1, err
 }
 
 // Check implements extension.Manager
 func (_d telemetryMiddleware) Check(ctx context.Context, in *extension.CheckRequest) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "Check"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.Check")
+	defer _span.End()
+
+	err = _d.Manager.Check(ctx, in)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"in":  in}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"in":  in}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.Check(ctx, in)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Install implements extension.Manager
 func (_d telemetryMiddleware) Install(ctx context.Context, in *extension.InstallRequest) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "Install"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.Install")
+	defer _span.End()
+
+	err = _d.Manager.Install(ctx, in)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"in":  in}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"in":  in}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.Install(ctx, in)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // ListExtensions implements extension.Manager
 func (_d telemetryMiddleware) ListExtensions(ctx context.Context, space string, env string, filter *extension.ListExtensionsFilter) (ipa1 []*extension.Info, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "ListExtensions"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.ListExtensions")
+	defer _span.End()
+
+	ipa1, err = _d.Manager.ListExtensions(ctx, space, env, filter)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"space":  space,
+			"env":    env,
+			"filter": filter}, map[string]interface{}{
+			"ipa1": ipa1,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"space":  space,
-				"env":    env,
-				"filter": filter}, map[string]interface{}{
-				"ipa1": ipa1,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.ListExtensions(ctx, space, env, filter)
+	return ipa1, err
 }
 
 // ListRegisteredExtensions implements extension.Manager
 func (_d telemetryMiddleware) ListRegisteredExtensions(ctx context.Context, extensions ...string) (epa1 []*extension.ExtensionConnector, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "ListRegisteredExtensions"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.ListRegisteredExtensions")
+	defer _span.End()
+
+	epa1, err = _d.Manager.ListRegisteredExtensions(ctx, extensions...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":        ctx,
+			"extensions": extensions}, map[string]interface{}{
+			"epa1": epa1,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":        ctx,
-				"extensions": extensions}, map[string]interface{}{
-				"epa1": epa1,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.ListRegisteredExtensions(ctx, extensions...)
+	return epa1, err
 }
 
 // RegisterExtensions implements extension.Manager
 func (_d telemetryMiddleware) RegisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "RegisterExtensions"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.RegisterExtensions")
+	defer _span.End()
+
+	err = _d.Manager.RegisterExtensions(ctx, ext...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"ext": ext}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"ext": ext}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.RegisterExtensions(ctx, ext...)
+	return err
 }
 
 // Uninstall implements extension.Manager
 func (_d telemetryMiddleware) Uninstall(ctx context.Context, in *extension.UninstallRequest) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "Uninstall"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.Uninstall")
+	defer _span.End()
+
+	err = _d.Manager.Uninstall(ctx, in)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"in":  in}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"in":  in}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.Uninstall(ctx, in)
+	return err
 }
 
 // UnregisterExtensions implements extension.Manager
 func (_d telemetryMiddleware) UnregisterExtensions(ctx context.Context, ext ...*extension.ExtensionConnector) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Manager"),
 		attribute.String("method", "UnregisterExtensions"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Manager.UnregisterExtensions")
+	defer _span.End()
+
+	err = _d.Manager.UnregisterExtensions(ctx, ext...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"ext": ext}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"ext": ext}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Manager.UnregisterExtensions(ctx, ext...)
+	return err
 }
diff --git a/pkg/files/middleware/telemetry_middleware.go b/pkg/files/middleware/telemetry_middleware.go
index bed97ea15eba2acd026249d698195835ee6a9db1..e2e482a6af8f4ffde281120f35c17fae425202f6 100644
--- a/pkg/files/middleware/telemetry_middleware.go
+++ b/pkg/files/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/files -i Files -t ../../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/files"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements files.Files interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	files.Files
@@ -50,236 +54,278 @@ func TelemetryMiddleware(base files.Files, instance string, spanDecorator ...fun
 
 // AbortUpload implements files.Files
 func (_d telemetryMiddleware) AbortUpload(ctx context.Context, upload *files.MultipartUpload) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "AbortUpload"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.AbortUpload")
+	defer _span.End()
+
+	err = _d.Files.AbortUpload(ctx, upload)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"upload": upload}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.AbortUpload(ctx, upload)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"upload": upload}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // CompleteUpload implements files.Files
 func (_d telemetryMiddleware) CompleteUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "CompleteUpload"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.CompleteUpload")
+	defer _span.End()
+
+	u, err = _d.Files.CompleteUpload(ctx, upload)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"upload": upload}, map[string]interface{}{
-				"u":   u,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.CompleteUpload(ctx, upload)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"upload": upload}, map[string]interface{}{
+			"u":   u,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return u, err
 }
 
 // DeleteFile implements files.Files
 func (_d telemetryMiddleware) DeleteFile(ctx context.Context, file *files.File) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "DeleteFile"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.DeleteFile")
+	defer _span.End()
+
+	err = _d.Files.DeleteFile(ctx, file)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"file": file}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"file": file}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.DeleteFile(ctx, file)
+	return err
 }
 
 // GetFile implements files.Files
 func (_d telemetryMiddleware) GetFile(ctx context.Context, file *files.File) (f *files.File, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "GetFile"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.GetFile")
+	defer _span.End()
+
+	f, err = _d.Files.GetFile(ctx, file)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"file": file}, map[string]interface{}{
-				"f":   f,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.GetFile(ctx, file)
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"file": file}, map[string]interface{}{
+			"f":   f,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return f, err
 }
 
 // MoveUpload implements files.Files
 func (_d telemetryMiddleware) MoveUpload(ctx context.Context, upload *files.MultipartUpload) (file *files.File, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "MoveUpload"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.MoveUpload")
+	defer _span.End()
+
+	file, err = _d.Files.MoveUpload(ctx, upload)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"upload": upload}, map[string]interface{}{
-				"file": file,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.MoveUpload(ctx, upload)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"upload": upload}, map[string]interface{}{
+			"file": file,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return file, err
 }
 
 // StartUpload implements files.Files
 func (_d telemetryMiddleware) StartUpload(ctx context.Context, upload *files.MultipartUpload) (u *files.MultipartUpload, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "StartUpload"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.StartUpload")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"upload": upload}, map[string]interface{}{
-				"u":   u,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.StartUpload(ctx, upload)
+	u, err = _d.Files.StartUpload(ctx, upload)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"upload": upload}, map[string]interface{}{
+			"u":   u,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return u, err
 }
 
 // Upload implements files.Files
 func (_d telemetryMiddleware) Upload(ctx context.Context, file *files.File) (u *files.Upload, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Files"),
 		attribute.String("method", "Upload"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Files.Upload")
+	defer _span.End()
+
+	u, err = _d.Files.Upload(ctx, file)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"file": file}, map[string]interface{}{
+			"u":   u,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"file": file}, map[string]interface{}{
-				"u":   u,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Files.Upload(ctx, file)
+	return u, err
 }
diff --git a/pkg/invitations/invitation.go b/pkg/invitations/invitation.go
index a5b91ed006693748deb71877b8e555e485b0c6c8..86d0db29a4d77b0eb7e7533b706d4a299fbed388 100644
--- a/pkg/invitations/invitation.go
+++ b/pkg/invitations/invitation.go
@@ -27,3 +27,7 @@ func (i Invitation) Clone() *Invitation {
 		ValidUntil: i.ValidUntil,
 	}
 }
+
+func (i Invitation) GetSpaceID() string {
+	return i.SpaceID
+}
diff --git a/pkg/invitations/middleware/telemetry_middleware.go b/pkg/invitations/middleware/telemetry_middleware.go
index 44b7d2683137884f330946cce8d39a0eb3617d15..1696f81a9ada1457336e928ebb44c79aa6852bcd 100644
--- a/pkg/invitations/middleware/telemetry_middleware.go
+++ b/pkg/invitations/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/invitations -i Invitations -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/invitations -i Invitations -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/invitations"
 	"git.perx.ru/perxis/perxis-go/pkg/options"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements invitations.Invitations interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	invitations.Invitations
@@ -51,171 +55,281 @@ func TelemetryMiddleware(base invitations.Invitations, instance string, spanDeco
 
 // Accept implements invitations.Invitations
 func (_d telemetryMiddleware) Accept(ctx context.Context, invitationId string, userId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Invitations"),
 		attribute.String("method", "Accept"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Accept")
+	defer _span.End()
+
+	err = _d.Invitations.Accept(ctx, invitationId, userId)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"invitationId": invitationId,
-				"userId":       userId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, invitationId, userId, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"invitationId": invitationId,
+			"userId":       userId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Invitations.Accept(ctx, invitationId, userId)
+	return err
 }
 
 // Create implements invitations.Invitations
 func (_d telemetryMiddleware) Create(ctx context.Context, invitation *invitations.Invitation) (created *invitations.Invitation, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Invitations"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Create")
+	defer _span.End()
+
+	created, err = _d.Invitations.Create(ctx, invitation)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":        ctx,
-				"invitation": invitation}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, invitation, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Invitations.Create(ctx, invitation)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":        ctx,
+			"invitation": invitation}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return created, err
 }
 
 // Delete implements invitations.Invitations
 func (_d telemetryMiddleware) Delete(ctx context.Context, invitationId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Invitations"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Invitations.Delete(ctx, invitationId)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"invitationId": invitationId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, invitationId, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Invitations.Delete(ctx, invitationId)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"invitationId": invitationId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Find implements invitations.Invitations
 func (_d telemetryMiddleware) Find(ctx context.Context, filter *invitations.Filter, opts *options.FindOptions) (invitations []*invitations.Invitation, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Invitations"),
 		attribute.String("method", "Find"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Find")
+	defer _span.End()
+
+	invitations, total, err = _d.Invitations.Find(ctx, filter, opts)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"filter": filter,
-				"opts":   opts}, map[string]interface{}{
-				"invitations": invitations,
-				"total":       total,
-				"err":         err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, filter, opts, invitations, total, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Invitations.Find(ctx, filter, opts)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"filter": filter,
+			"opts":   opts}, map[string]interface{}{
+			"invitations": invitations,
+			"total":       total,
+			"err":         err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return invitations, total, err
 }
 
 // Get implements invitations.Invitations
 func (_d telemetryMiddleware) Get(ctx context.Context, invitationId string) (invitation *invitations.Invitation, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Invitations"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Invitations.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"invitationId": invitationId}, map[string]interface{}{
-				"invitation": invitation,
-				"err":        err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	invitation, err = _d.Invitations.Get(ctx, invitationId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, invitationId, invitation, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"invitationId": invitationId}, map[string]interface{}{
+			"invitation": invitation,
+			"err":        err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Invitations.Get(ctx, invitationId)
+	return invitation, err
 }
diff --git a/pkg/items/item.go b/pkg/items/item.go
index c37c4fc69c2829d511764afdb89b4db8fb8f7137..dc56fe63284be6885cf4560578df0bf77729e359 100644
--- a/pkg/items/item.go
+++ b/pkg/items/item.go
@@ -150,6 +150,10 @@ func (i *Item) GetID() string {
 	return i.ID
 }
 
+func (i *Item) GetSpaceID() string {
+	return i.SpaceID
+}
+
 func (i *Item) Clone() *Item {
 	itm := *i
 	itm.Data = data.CloneMap(i.Data)
diff --git a/pkg/items/middleware/telemetry_middleware.go b/pkg/items/middleware/telemetry_middleware.go
index 98891f9f4f957ffe12626150c58e8bb7df67389a..da626aa53ea846ce5747bd0deded09d300d48d95 100644
--- a/pkg/items/middleware/telemetry_middleware.go
+++ b/pkg/items/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/items -i Items -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/items -i Items -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/items"
 	"git.perx.ru/perxis/perxis-go/pkg/schema"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements items.Items interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	items.Items
@@ -51,655 +55,952 @@ func TelemetryMiddleware(base items.Items, instance string, spanDecorator ...fun
 
 // Aggregate implements items.Items
 func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregateOptions) (result map[string]interface{}, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Aggregate"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Aggregate")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"result": result,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	result, err = _d.Items.Aggregate(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"result": result,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.Aggregate(ctx, spaceId, envId, collectionId, filter, options...)
+	return result, err
 }
 
 // AggregatePublished implements items.Items
 func (_d telemetryMiddleware) AggregatePublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.AggregatePublishedOptions) (result map[string]interface{}, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "AggregatePublished"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.AggregatePublished")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"result": result,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	result, err = _d.Items.AggregatePublished(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"result": result,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.AggregatePublished(ctx, spaceId, envId, collectionId, filter, options...)
+	return result, err
 }
 
 // Archive implements items.Items
 func (_d telemetryMiddleware) Archive(ctx context.Context, item *items.Item, options ...*items.ArchiveOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Archive"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Archive")
+	defer _span.End()
+
+	err = _d.Items.Archive(ctx, item, options...)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Items.Archive(ctx, item, options...)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Create implements items.Items
 func (_d telemetryMiddleware) Create(ctx context.Context, item *items.Item, opts ...*items.CreateOptions) (created *items.Item, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Create")
+	defer _span.End()
+
+	created, err = _d.Items.Create(ctx, item, opts...)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"item": item,
-				"opts": opts}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, item, opts, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.Create(ctx, item, opts...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"item": item,
+			"opts": opts}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return created, err
 }
 
 // Delete implements items.Items
 func (_d telemetryMiddleware) Delete(ctx context.Context, item *items.Item, options ...*items.DeleteOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Delete")
+	defer _span.End()
+
+	err = _d.Items.Delete(ctx, item, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Items.Delete(ctx, item, options...)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Find implements items.Items
 func (_d telemetryMiddleware) Find(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindOptions) (items []*items.Item, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Find"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Find")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"items": items,
-				"total": total,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	items, total, err = _d.Items.Find(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-		_span.End()
-	}()
-	return _d.Items.Find(ctx, spaceId, envId, collectionId, filter, options...)
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"items": items,
+			"total": total,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return items, total, err
 }
 
 // FindArchived implements items.Items
 func (_d telemetryMiddleware) FindArchived(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindArchivedOptions) (items []*items.Item, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "FindArchived"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.FindArchived")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"items": items,
-				"total": total,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	items, total, err = _d.Items.FindArchived(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.FindArchived(ctx, spaceId, envId, collectionId, filter, options...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"items": items,
+			"total": total,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return items, total, err
 }
 
 // FindPublished implements items.Items
 func (_d telemetryMiddleware) FindPublished(ctx context.Context, spaceId string, envId string, collectionId string, filter *items.Filter, options ...*items.FindPublishedOptions) (items []*items.Item, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "FindPublished"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.FindPublished")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"filter":       filter,
-				"options":      options}, map[string]interface{}{
-				"items": items,
-				"total": total,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	items, total, err = _d.Items.FindPublished(ctx, spaceId, envId, collectionId, filter, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-		_span.End()
-	}()
-	return _d.Items.FindPublished(ctx, spaceId, envId, collectionId, filter, options...)
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"filter":       filter,
+			"options":      options}, map[string]interface{}{
+			"items": items,
+			"total": total,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return items, total, err
 }
 
 // Get implements items.Items
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetOptions) (item *items.Item, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"itemId":       itemId,
-				"options":      options}, map[string]interface{}{
-				"item": item,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	item, err = _d.Items.Get(ctx, spaceId, envId, collectionId, itemId, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.Get(ctx, spaceId, envId, collectionId, itemId, options...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"itemId":       itemId,
+			"options":      options}, map[string]interface{}{
+			"item": item,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return item, err
 }
 
 // GetPublished implements items.Items
 func (_d telemetryMiddleware) GetPublished(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.GetPublishedOptions) (item *items.Item, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "GetPublished"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.GetPublished")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"itemId":       itemId,
-				"options":      options}, map[string]interface{}{
-				"item": item,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	item, err = _d.Items.GetPublished(ctx, spaceId, envId, collectionId, itemId, options...)
 
-		_span.End()
-	}()
-	return _d.Items.GetPublished(ctx, spaceId, envId, collectionId, itemId, options...)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"itemId":       itemId,
+			"options":      options}, map[string]interface{}{
+			"item": item,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return item, err
 }
 
 // GetRevision implements items.Items
 func (_d telemetryMiddleware) GetRevision(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, revisionId string, options ...*items.GetRevisionOptions) (item *items.Item, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "GetRevision"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.GetRevision")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"itemId":       itemId,
-				"revisionId":   revisionId,
-				"options":      options}, map[string]interface{}{
-				"item": item,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	item, err = _d.Items.GetRevision(ctx, spaceId, envId, collectionId, itemId, revisionId, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"itemId":       itemId,
+			"revisionId":   revisionId,
+			"options":      options}, map[string]interface{}{
+			"item": item,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.GetRevision(ctx, spaceId, envId, collectionId, itemId, revisionId, options...)
+	return item, err
 }
 
 // Introspect implements items.Items
 func (_d telemetryMiddleware) Introspect(ctx context.Context, item *items.Item, opts ...*items.IntrospectOptions) (itm *items.Item, sch *schema.Schema, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Introspect"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Introspect")
+	defer _span.End()
+
+	itm, sch, err = _d.Items.Introspect(ctx, item, opts...)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"item": item,
-				"opts": opts}, map[string]interface{}{
-				"itm": itm,
-				"sch": sch,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, item, opts, itm, sch, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.Introspect(ctx, item, opts...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"item": item,
+			"opts": opts}, map[string]interface{}{
+			"itm": itm,
+			"sch": sch,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return itm, sch, err
 }
 
 // ListRevisions implements items.Items
 func (_d telemetryMiddleware) ListRevisions(ctx context.Context, spaceId string, envId string, collectionId string, itemId string, options ...*items.ListRevisionsOptions) (items []*items.Item, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "ListRevisions"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.ListRevisions")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":          ctx,
-				"spaceId":      spaceId,
-				"envId":        envId,
-				"collectionId": collectionId,
-				"itemId":       itemId,
-				"options":      options}, map[string]interface{}{
-				"items": items,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	items, err = _d.Items.ListRevisions(ctx, spaceId, envId, collectionId, itemId, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":          ctx,
+			"spaceId":      spaceId,
+			"envId":        envId,
+			"collectionId": collectionId,
+			"itemId":       itemId,
+			"options":      options}, map[string]interface{}{
+			"items": items,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.ListRevisions(ctx, spaceId, envId, collectionId, itemId, options...)
+	return items, err
 }
 
 // Publish implements items.Items
 func (_d telemetryMiddleware) Publish(ctx context.Context, item *items.Item, options ...*items.PublishOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Publish"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Publish")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	err = _d.Items.Publish(ctx, item, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.Publish(ctx, item, options...)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Unarchive implements items.Items
 func (_d telemetryMiddleware) Unarchive(ctx context.Context, item *items.Item, options ...*items.UnarchiveOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Unarchive"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Unarchive")
+	defer _span.End()
+
+	err = _d.Items.Unarchive(ctx, item, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Items.Unarchive(ctx, item, options...)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Undelete implements items.Items
 func (_d telemetryMiddleware) Undelete(ctx context.Context, item *items.Item, options ...*items.UndeleteOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Undelete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Undelete")
+	defer _span.End()
+
+	err = _d.Items.Undelete(ctx, item, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Items.Undelete(ctx, item, options...)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Unpublish implements items.Items
 func (_d telemetryMiddleware) Unpublish(ctx context.Context, item *items.Item, options ...*items.UnpublishOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Unpublish"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Unpublish")
+	defer _span.End()
+
+	err = _d.Items.Unpublish(ctx, item, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Items.Unpublish(ctx, item, options...)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Update implements items.Items
 func (_d telemetryMiddleware) Update(ctx context.Context, item *items.Item, options ...*items.UpdateOptions) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Items"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Items.Update")
+	defer _span.End()
+
+	err = _d.Items.Update(ctx, item, options...)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"item":    item,
-				"options": options}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, item, options, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"item":    item,
+			"options": options}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Items.Update(ctx, item, options...)
+	return err
 }
diff --git a/pkg/locales/locale.go b/pkg/locales/locale.go
index e0e32616ee4bd526c7d25c9cbab740e196529328..80cd2d60c884951206ccb3aad5113f0a369b68bf 100644
--- a/pkg/locales/locale.go
+++ b/pkg/locales/locale.go
@@ -55,6 +55,10 @@ func (locale *Locale) Key() string {
 	return locale.ID
 }
 
+func (locale *Locale) GetSpaceID() string {
+	return locale.SpaceID
+}
+
 // Возвращает язык локали, например "en", "ru"
 func (locale *Locale) GetLanguage() string {
 	lang, err := language.Parse(locale.Code)
diff --git a/pkg/locales/middleware/telemetry_middleware.go b/pkg/locales/middleware/telemetry_middleware.go
index 98fe346ea000409be27bfd21fccc6723ed09851b..709a6bab9a23210954ae0c756e6c10ac7fa2bd05 100644
--- a/pkg/locales/middleware/telemetry_middleware.go
+++ b/pkg/locales/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ../../../assets/templates/middleware/telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/locales -i Locales -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/locales -i Locales -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/locales"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements locales.Locales interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	locales.Locales
@@ -50,135 +54,201 @@ func TelemetryMiddleware(base locales.Locales, instance string, spanDecorator ..
 
 // Create implements locales.Locales
 func (_d telemetryMiddleware) Create(ctx context.Context, locale *locales.Locale) (created *locales.Locale, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Locales"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.Create")
+	defer _span.End()
+
+	created, err = _d.Locales.Create(ctx, locale)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"locale": locale}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, locale, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Locales.Create(ctx, locale)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"locale": locale}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return created, err
 }
 
 // Delete implements locales.Locales
 func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, localeId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Locales"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":      ctx,
-				"spaceId":  spaceId,
-				"localeId": localeId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Locales.Delete(ctx, spaceId, localeId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":      ctx,
+			"spaceId":  spaceId,
+			"localeId": localeId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Locales.Delete(ctx, spaceId, localeId)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // List implements locales.Locales
 func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (locales []*locales.Locale, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Locales"),
 		attribute.String("method", "List"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.List")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"locales": locales,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	locales, err = _d.Locales.List(ctx, spaceId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-		_span.End()
-	}()
-	return _d.Locales.List(ctx, spaceId)
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"locales": locales,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return locales, err
 }
 
 // Update implements locales.Locales
 func (_d telemetryMiddleware) Update(ctx context.Context, locale *locales.Locale) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Locales"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Locales.Update")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Locales.Update(ctx, locale)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"locale": locale}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, locale, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"locale": locale}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Locales.Update(ctx, locale)
+	return err
 }
diff --git a/pkg/members/middleware/middleware.go b/pkg/members/middleware/middleware.go
index 04626790010ac2da99f00e8501d1c4186683e6b7..bb491623865e21496adedb1e91987bc2205a3ce4 100644
--- a/pkg/members/middleware/middleware.go
+++ b/pkg/members/middleware/middleware.go
@@ -21,7 +21,7 @@ func WithLog(s members.Members, logger *zap.Logger, log_access bool) members.Mem
 	if log_access {
 		s = AccessLoggingMiddleware(logger)(s)
 	}
-	s = LoggingMiddleware(logger)(s)
+	s = ErrorLoggingMiddleware(logger)(s)
 
 	s = RecoveringMiddleware(logger)(s)
 	return s
diff --git a/pkg/members/middleware/telemetry_middleware.go b/pkg/members/middleware/telemetry_middleware.go
index 6193a4bacb41dcea61a1384e939bcdb2785f5e8a..bf339f3fd998e3e49d842a6b99612759743aced5 100644
--- a/pkg/members/middleware/telemetry_middleware.go
+++ b/pkg/members/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/members -i Members -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/members -i Members -t ../../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/members"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements members.Members interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	members.Members
@@ -50,205 +54,241 @@ func TelemetryMiddleware(base members.Members, instance string, spanDecorator ..
 
 // Get implements members.Members
 func (_d telemetryMiddleware) Get(ctx context.Context, orgId string, userId string) (role members.Role, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Members"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.Get")
+	defer _span.End()
+
+	role, err = _d.Members.Get(ctx, orgId, userId)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"orgId":  orgId,
-				"userId": userId}, map[string]interface{}{
-				"role": role,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Members.Get(ctx, orgId, userId)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"orgId":  orgId,
+			"userId": userId}, map[string]interface{}{
+			"role": role,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return role, err
 }
 
 // ListMembers implements members.Members
 func (_d telemetryMiddleware) ListMembers(ctx context.Context, orgId string) (members []*members.Member, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Members"),
 		attribute.String("method", "ListMembers"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.ListMembers")
+	defer _span.End()
+
+	members, err = _d.Members.ListMembers(ctx, orgId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"orgId": orgId}, map[string]interface{}{
-				"members": members,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Members.ListMembers(ctx, orgId)
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"orgId": orgId}, map[string]interface{}{
+			"members": members,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return members, err
 }
 
 // ListOrganizations implements members.Members
 func (_d telemetryMiddleware) ListOrganizations(ctx context.Context, userId string) (organizations []*members.Member, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Members"),
 		attribute.String("method", "ListOrganizations"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.ListOrganizations")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"userId": userId}, map[string]interface{}{
-				"organizations": organizations,
-				"err":           err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Members.ListOrganizations(ctx, userId)
+	organizations, err = _d.Members.ListOrganizations(ctx, userId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"userId": userId}, map[string]interface{}{
+			"organizations": organizations,
+			"err":           err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return organizations, err
 }
 
 // Remove implements members.Members
 func (_d telemetryMiddleware) Remove(ctx context.Context, orgId string, userId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Members"),
 		attribute.String("method", "Remove"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.Remove")
+	defer _span.End()
+
+	err = _d.Members.Remove(ctx, orgId, userId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"orgId":  orgId,
-				"userId": userId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Members.Remove(ctx, orgId, userId)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"orgId":  orgId,
+			"userId": userId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // RemoveAll implements members.Members
 func (_d telemetryMiddleware) RemoveAll(ctx context.Context, orgId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Members"),
 		attribute.String("method", "RemoveAll"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.RemoveAll")
+	defer _span.End()
+
+	err = _d.Members.RemoveAll(ctx, orgId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"orgId": orgId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Members.RemoveAll(ctx, orgId)
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"orgId": orgId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Set implements members.Members
 func (_d telemetryMiddleware) Set(ctx context.Context, orgId string, userId string, role members.Role) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Members"),
 		attribute.String("method", "Set"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Members.Set")
+	defer _span.End()
+
+	err = _d.Members.Set(ctx, orgId, userId, role)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"orgId":  orgId,
+			"userId": userId,
+			"role":   role}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"orgId":  orgId,
-				"userId": userId,
-				"role":   role}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Members.Set(ctx, orgId, userId, role)
+	return err
 }
diff --git a/pkg/organizations/middleware/telemetry_middleware.go b/pkg/organizations/middleware/telemetry_middleware.go
index d728b1f10f4ba303b6469d3a1b8bf63cb24a7283..1cb7932880080c617db6ccbf2f3d204682ca7c11 100644
--- a/pkg/organizations/middleware/telemetry_middleware.go
+++ b/pkg/organizations/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/organizations -i Organizations -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/organizations -i Organizations -t ../../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/options"
 	"git.perx.ru/perxis/perxis-go/pkg/organizations"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements organizations.Organizations interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	organizations.Organizations
@@ -51,170 +55,200 @@ func TelemetryMiddleware(base organizations.Organizations, instance string, span
 
 // Create implements organizations.Organizations
 func (_d telemetryMiddleware) Create(ctx context.Context, org *organizations.Organization) (created *organizations.Organization, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Create")
+	defer _span.End()
+
+	created, err = _d.Organizations.Create(ctx, org)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"org": org}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"org": org}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Organizations.Create(ctx, org)
+	return created, err
 }
 
 // Delete implements organizations.Organizations
 func (_d telemetryMiddleware) Delete(ctx context.Context, orgId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Delete")
+	defer _span.End()
+
+	err = _d.Organizations.Delete(ctx, orgId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"orgId": orgId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Organizations.Delete(ctx, orgId)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"orgId": orgId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Find implements organizations.Organizations
 func (_d telemetryMiddleware) Find(ctx context.Context, filter *organizations.Filter, opts *options.FindOptions) (orgs []*organizations.Organization, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Find"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Find")
+	defer _span.End()
+
+	orgs, total, err = _d.Organizations.Find(ctx, filter, opts)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"filter": filter,
-				"opts":   opts}, map[string]interface{}{
-				"orgs":  orgs,
-				"total": total,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Organizations.Find(ctx, filter, opts)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"filter": filter,
+			"opts":   opts}, map[string]interface{}{
+			"orgs":  orgs,
+			"total": total,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return orgs, total, err
 }
 
 // Get implements organizations.Organizations
 func (_d telemetryMiddleware) Get(ctx context.Context, orgId string) (org *organizations.Organization, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Get")
+	defer _span.End()
+
+	org, err = _d.Organizations.Get(ctx, orgId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"orgId": orgId}, map[string]interface{}{
+			"org": org,
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"orgId": orgId}, map[string]interface{}{
-				"org": org,
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Organizations.Get(ctx, orgId)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return org, err
 }
 
 // Update implements organizations.Organizations
 func (_d telemetryMiddleware) Update(ctx context.Context, org *organizations.Organization) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Organizations.Update")
+	defer _span.End()
+
+	err = _d.Organizations.Update(ctx, org)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx": ctx,
+			"org": org}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx": ctx,
-				"org": org}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Organizations.Update(ctx, org)
+	return err
 }
diff --git a/pkg/references/middleware/telemetry_middleware.go b/pkg/references/middleware/telemetry_middleware.go
index 71c51698bd9c015fdefd24e79b41ddcacda09eb2..3e8fbb773fd9bc548eed3f34f78a4f5adcbe1128 100644
--- a/pkg/references/middleware/telemetry_middleware.go
+++ b/pkg/references/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ../../../assets/templates/middleware/telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/references -i References -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/references -i References -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/items"
 	"git.perx.ru/perxis/perxis-go/pkg/references"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements references.References interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	references.References
@@ -51,78 +55,100 @@ func TelemetryMiddleware(base references.References, instance string, spanDecora
 
 // Get implements references.References
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId string, references []*references.Reference, options ...*references.GetOptions) (items []*items.Item, notfound []*references.Reference, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "References"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "References.Get")
+	defer _span.End()
+
+	items, notfound, err = _d.References.Get(ctx, spaceId, envId, references, options...)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":        ctx,
-				"spaceId":    spaceId,
-				"envId":      envId,
-				"references": references,
-				"options":    options}, map[string]interface{}{
-				"items":    items,
-				"notfound": notfound,
-				"err":      err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.References.Get(ctx, spaceId, envId, references, options...)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":        ctx,
+			"spaceId":    spaceId,
+			"envId":      envId,
+			"references": references,
+			"options":    options}, map[string]interface{}{
+			"items":    items,
+			"notfound": notfound,
+			"err":      err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return items, notfound, err
 }
 
 // Publish implements references.References
 func (_d telemetryMiddleware) Publish(ctx context.Context, spaceId string, envId string, references []*references.Reference, recursive bool, force bool) (published []*references.Reference, notfound []*references.Reference, unpublished []*references.Reference, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "References"),
 		attribute.String("method", "Publish"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "References.Publish")
+	defer _span.End()
+
+	published, notfound, unpublished, err = _d.References.Publish(ctx, spaceId, envId, references, recursive, force)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":        ctx,
+			"spaceId":    spaceId,
+			"envId":      envId,
+			"references": references,
+			"recursive":  recursive,
+			"force":      force}, map[string]interface{}{
+			"published":   published,
+			"notfound":    notfound,
+			"unpublished": unpublished,
+			"err":         err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":        ctx,
-				"spaceId":    spaceId,
-				"envId":      envId,
-				"references": references,
-				"recursive":  recursive,
-				"force":      force}, map[string]interface{}{
-				"published":   published,
-				"notfound":    notfound,
-				"unpublished": unpublished,
-				"err":         err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.References.Publish(ctx, spaceId, envId, references, recursive, force)
+	return published, notfound, unpublished, err
 }
diff --git a/pkg/roles/middleware/middleware.go b/pkg/roles/middleware/middleware.go
index 299199a40432f486d1020bb803f5bff18a95428e..aaeb2da895d5aa71768e577315e549daa6a247c4 100644
--- a/pkg/roles/middleware/middleware.go
+++ b/pkg/roles/middleware/middleware.go
@@ -21,7 +21,7 @@ func WithLog(s roles.Roles, logger *zap.Logger, log_access bool) roles.Roles {
 	if log_access {
 		s = AccessLoggingMiddleware(logger)(s)
 	}
-	s = LoggingMiddleware(logger)(s)
+	s = ErrorLoggingMiddleware(logger)(s)
 
 	s = RecoveringMiddleware(logger)(s)
 	return s
diff --git a/pkg/roles/middleware/telemetry_middleware.go b/pkg/roles/middleware/telemetry_middleware.go
index 5d9d5e35cee66af5e24fb5888d52907ce35aadde..7403575220d93fe24a00b0a8de749371e57904b0 100644
--- a/pkg/roles/middleware/telemetry_middleware.go
+++ b/pkg/roles/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/roles -i Roles -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/roles -i Roles -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/roles"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"go.opentelemetry.io/otel"
@@ -20,6 +20,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements roles.Roles interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	roles.Roles
@@ -50,170 +54,247 @@ func TelemetryMiddleware(base roles.Roles, instance string, spanDecorator ...fun
 
 // Create implements roles.Roles
 func (_d telemetryMiddleware) Create(ctx context.Context, role *roles.Role) (created *roles.Role, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Roles"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Create")
+	defer _span.End()
+
+	created, err = _d.Roles.Create(ctx, role)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"role": role}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, role, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"role": role}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Roles.Create(ctx, role)
+	return created, err
 }
 
 // Delete implements roles.Roles
 func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, roleId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Roles"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"roleId":  roleId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Roles.Delete(ctx, spaceId, roleId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Roles.Delete(ctx, spaceId, roleId)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"roleId":  roleId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Get implements roles.Roles
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, roleId string) (role *roles.Role, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Roles"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"roleId":  roleId}, map[string]interface{}{
-				"role": role,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	role, err = _d.Roles.Get(ctx, spaceId, roleId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"roleId":  roleId}, map[string]interface{}{
+			"role": role,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Roles.Get(ctx, spaceId, roleId)
+	return role, err
 }
 
 // List implements roles.Roles
 func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (roles []*roles.Role, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Roles"),
 		attribute.String("method", "List"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.List")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"roles": roles,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	roles, err = _d.Roles.List(ctx, spaceId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Roles.List(ctx, spaceId)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"roles": roles,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return roles, err
 }
 
 // Update implements roles.Roles
 func (_d telemetryMiddleware) Update(ctx context.Context, role *roles.Role) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Roles"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Roles.Update")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Roles.Update(ctx, role)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":  ctx,
-				"role": role}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, role, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":  ctx,
+			"role": role}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Roles.Update(ctx, role)
+	return err
 }
diff --git a/pkg/roles/role.go b/pkg/roles/role.go
index 76520f8fbf353c027ae782efb1bf79a1bfa453f5..81feb1e909f15d40a918309a25add9c420e25b35 100644
--- a/pkg/roles/role.go
+++ b/pkg/roles/role.go
@@ -40,6 +40,10 @@ func (r Role) GetID() string {
 	return r.ID
 }
 
+func (r Role) GetSpaceID() string {
+	return r.SpaceID
+}
+
 func (r Role) Clone() *Role {
 	return &Role{
 		ID:              r.ID,
diff --git a/pkg/spaces/middleware/access_logging_middleware.go b/pkg/spaces/middleware/access_logging_middleware.go
index 9596d7d4fc2daa611a0db631eef56fe6d5531488..d155ee1f0d95daad6b29c5961604cdc8b466fcd9 100644
--- a/pkg/spaces/middleware/access_logging_middleware.go
+++ b/pkg/spaces/middleware/access_logging_middleware.go
@@ -184,6 +184,25 @@ func (m *accessLoggingMiddleware) Move(ctx context.Context, spaceID string, orgI
 	return err
 }
 
+func (m *accessLoggingMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) {
+	begin := time.Now()
+
+	m.logger.Debug("SetState.Request",
+		zap.Reflect("principal", auth.GetPrincipal(ctx)),
+		zap.Reflect("spaceID", spaceID),
+		zap.Reflect("state", state),
+	)
+
+	err = m.next.SetState(ctx, spaceID, state)
+
+	m.logger.Debug("SetState.Response",
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	)
+
+	return err
+}
+
 func (m *accessLoggingMiddleware) Transfer(ctx context.Context, spaceID string, transferToOrg string) (err error) {
 	begin := time.Now()
 
@@ -239,22 +258,3 @@ func (m *accessLoggingMiddleware) UpdateConfig(ctx context.Context, spaceId stri
 
 	return err
 }
-
-func (m *accessLoggingMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) {
-	begin := time.Now()
-
-	m.logger.Debug("SetState.Request",
-		zap.Reflect("principal", auth.GetPrincipal(ctx)),
-		zap.Reflect("spaceID", spaceID),
-		zap.Reflect("state", state),
-	)
-
-	err = m.next.SetState(ctx, spaceID, state)
-
-	m.logger.Debug("SetState.Response",
-		zap.Duration("time", time.Since(begin)),
-		zap.Error(err),
-	)
-
-	return err
-}
diff --git a/pkg/spaces/middleware/telemetry_middleware.go b/pkg/spaces/middleware/telemetry_middleware.go
index e9623692afe644e58cb1b406b4b06a3208edc710..84c90bd6a74bd9bdce5479ae6d100e306916355d 100644
--- a/pkg/spaces/middleware/telemetry_middleware.go
+++ b/pkg/spaces/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ../../../assets/templates/middleware/telemetry
+// template: ../../../assets/templates/middleware/telemetry_content
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/spaces -i Spaces -t ../../../assets/templates/middleware/telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/spaces -i Spaces -t ../../../assets/templates/middleware/telemetry_content -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/options"
 	"git.perx.ru/perxis/perxis-go/pkg/spaces"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements spaces.Spaces interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	spaces.Spaces
@@ -51,407 +55,638 @@ func TelemetryMiddleware(base spaces.Spaces, instance string, spanDecorator ...f
 
 // AbortTransfer implements spaces.Spaces
 func (_d telemetryMiddleware) AbortTransfer(ctx context.Context, spaceID string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "AbortTransfer"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.AbortTransfer")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Spaces.AbortTransfer(ctx, spaceID)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceID": spaceID}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, spaceID, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.AbortTransfer(ctx, spaceID)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceID": spaceID}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Create implements spaces.Spaces
 func (_d telemetryMiddleware) Create(ctx context.Context, space *spaces.Space) (created *spaces.Space, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Create")
+	defer _span.End()
+
+	created, err = _d.Spaces.Create(ctx, space)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"space": space}, map[string]interface{}{
-				"created": created,
-				"err":     err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, space, created, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Spaces.Create(ctx, space)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"space": space}, map[string]interface{}{
+			"created": created,
+			"err":     err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return created, err
 }
 
 // Delete implements spaces.Spaces
 func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Delete")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Spaces.Delete(ctx, spaceId)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.Delete(ctx, spaceId)
+	return err
 }
 
 // Find implements spaces.Spaces
 func (_d telemetryMiddleware) Find(ctx context.Context, filter *spaces.Filter, fo *options.FindOptions) (spaces []*spaces.Space, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Find"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Find")
+	defer _span.End()
+
+	spaces, total, err = _d.Spaces.Find(ctx, filter, fo)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"filter": filter,
-				"fo":     fo}, map[string]interface{}{
-				"spaces": spaces,
-				"total":  total,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, filter, fo, spaces, total, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.Find(ctx, filter, fo)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"filter": filter,
+			"fo":     fo}, map[string]interface{}{
+			"spaces": spaces,
+			"total":  total,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return spaces, total, err
 }
 
 // Get implements spaces.Spaces
 func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string) (space *spaces.Space, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Get")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId}, map[string]interface{}{
-				"space": space,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	space, err = _d.Spaces.Get(ctx, spaceId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.Get(ctx, spaceId)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId}, map[string]interface{}{
+			"space": space,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return space, err
 }
 
 // List implements spaces.Spaces
 func (_d telemetryMiddleware) List(ctx context.Context, orgId string) (spaces []*spaces.Space, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "List"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.List")
+	defer _span.End()
+
+	spaces, err = _d.Spaces.List(ctx, orgId)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"orgId": orgId}, map[string]interface{}{
-				"spaces": spaces,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, orgId, spaces, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Spaces.List(ctx, orgId)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"orgId": orgId}, map[string]interface{}{
+			"spaces": spaces,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return spaces, err
 }
 
 // ListTransfers implements spaces.Spaces
 func (_d telemetryMiddleware) ListTransfers(ctx context.Context, orgID string) (spaces []*spaces.Space, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "ListTransfers"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.ListTransfers")
+	defer _span.End()
+
+	spaces, err = _d.Spaces.ListTransfers(ctx, orgID)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"orgID": orgID}, map[string]interface{}{
-				"spaces": spaces,
-				"err":    err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, orgID, spaces, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"orgID": orgID}, map[string]interface{}{
+			"spaces": spaces,
+			"err":    err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-		_span.End()
-	}()
-	return _d.Spaces.ListTransfers(ctx, orgID)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return spaces, err
 }
 
 // Move implements spaces.Spaces
 func (_d telemetryMiddleware) Move(ctx context.Context, spaceID string, orgID string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Move"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Move")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceID": spaceID,
-				"orgID":   orgID}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	err = _d.Spaces.Move(ctx, spaceID, orgID)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, spaceID, orgID, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Spaces.Move(ctx, spaceID, orgID)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceID": spaceID,
+			"orgID":   orgID}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // SetState implements spaces.Spaces
 func (_d telemetryMiddleware) SetState(ctx context.Context, spaceID string, state *spaces.StateInfo) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "SetState"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.SetState")
+	defer _span.End()
+
+	err = _d.Spaces.SetState(ctx, spaceID, state)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceID": spaceID,
-				"state":   state}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	params := []interface{}{ctx, spaceID, state, err}
+	for _, p := range params {
+		if p == nil {
+			continue
+		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
 		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceID": spaceID,
+			"state":   state}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.SetState(ctx, spaceID, state)
+	return err
 }
 
 // Transfer implements spaces.Spaces
 func (_d telemetryMiddleware) Transfer(ctx context.Context, spaceID string, transferToOrg string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Transfer"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Transfer")
+	defer _span.End()
+
+	err = _d.Spaces.Transfer(ctx, spaceID, transferToOrg)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":           ctx,
-				"spaceID":       spaceID,
-				"transferToOrg": transferToOrg}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, spaceID, transferToOrg, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.Transfer(ctx, spaceID, transferToOrg)
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":           ctx,
+			"spaceID":       spaceID,
+			"transferToOrg": transferToOrg}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Update implements spaces.Spaces
 func (_d telemetryMiddleware) Update(ctx context.Context, space *spaces.Space) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.Update")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+	err = _d.Spaces.Update(ctx, space)
 
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":   ctx,
-				"space": space}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
+	var spID string
+	params := []interface{}{ctx, space, err}
+	for _, p := range params {
+		if p == nil {
+			continue
 		}
+		if sg, ok := p.(spaceGetter); ok {
+			spID = sg.GetSpaceID()
+			if spID != "" {
+				break
+			}
+		}
+	}
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
 
-		_span.End()
-	}()
-	return _d.Spaces.Update(ctx, space)
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":   ctx,
+			"space": space}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // UpdateConfig implements spaces.Spaces
 func (_d telemetryMiddleware) UpdateConfig(ctx context.Context, spaceId string, config *spaces.Config) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Spaces"),
 		attribute.String("method", "UpdateConfig"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Spaces.UpdateConfig")
+	defer _span.End()
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"spaceId": spaceId,
-				"config":  config}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
+	err = _d.Spaces.UpdateConfig(ctx, spaceId, config)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	var spID string
+	spID = spaceId
+	if spID != "" {
+		att = append(att, attribute.String("spaceID", spID))
+	}
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"spaceId": spaceId,
+			"config":  config}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-		_span.End()
-	}()
-	return _d.Spaces.UpdateConfig(ctx, spaceId, config)
+	return err
 }
diff --git a/pkg/spaces/space.go b/pkg/spaces/space.go
index baa44124b6830aa8c4f666f0300661952eadbc9d..46edd87af1de695b639759bcddfacc3bb313353e 100644
--- a/pkg/spaces/space.go
+++ b/pkg/spaces/space.go
@@ -88,3 +88,10 @@ type StateInfo struct {
 func (s Space) Clone() *Space {
 	return &s
 }
+
+func (s *Space) GetSpaceID() string {
+	if s == nil {
+		return ""
+	}
+	return s.ID
+}
diff --git a/pkg/users/middleware/telemetry_middleware.go b/pkg/users/middleware/telemetry_middleware.go
index 698b4f6b4f2928e5f466e7855defa4c2df96ef36..8ad677e704656503e246943bf12d30e133d4c11f 100644
--- a/pkg/users/middleware/telemetry_middleware.go
+++ b/pkg/users/middleware/telemetry_middleware.go
@@ -1,17 +1,17 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_default
 // gowrap: http://github.com/hexdigest/gowrap
 
 package middleware
 
-//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ..\..\..\assets\templates\middleware\telemetry -o telemetry_middleware.go -l ""
-
-// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/telemetry_default -o telemetry_middleware.go -l ""
 
 import (
 	"context"
 	"time"
 
+	oid "git.perx.ru/perxis/perxis-go/id"
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
 	"git.perx.ru/perxis/perxis-go/pkg/options"
 	"git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
 	"git.perx.ru/perxis/perxis-go/pkg/users"
@@ -21,6 +21,10 @@ import (
 	"go.opentelemetry.io/otel/trace"
 )
 
+type spaceGetter interface {
+	GetSpaceID() string
+}
+
 // telemetryMiddleware implements users.Users interface instrumented with opentracing spans
 type telemetryMiddleware struct {
 	users.Users
@@ -51,204 +55,240 @@ func TelemetryMiddleware(base users.Users, instance string, spanDecorator ...fun
 
 // Create implements users.Users
 func (_d telemetryMiddleware) Create(ctx context.Context, create *users.User) (user *users.User, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Users"),
 		attribute.String("method", "Create"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Create")
+	defer _span.End()
+
+	user, err = _d.Users.Create(ctx, create)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"create": create}, map[string]interface{}{
+			"user": user,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"create": create}, map[string]interface{}{
-				"user": user,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Users.Create(ctx, create)
+	return user, err
 }
 
 // Delete implements users.Users
 func (_d telemetryMiddleware) Delete(ctx context.Context, userId string) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Users"),
 		attribute.String("method", "Delete"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Delete")
+	defer _span.End()
+
+	err = _d.Users.Delete(ctx, userId)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"userId": userId}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Users.Delete(ctx, userId)
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"userId": userId}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return err
 }
 
 // Find implements users.Users
 func (_d telemetryMiddleware) Find(ctx context.Context, filter *users.Filter, options *options.FindOptions) (users []*users.User, total int, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Users"),
 		attribute.String("method", "Find"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Find")
+	defer _span.End()
+
+	users, total, err = _d.Users.Find(ctx, filter, options)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":     ctx,
+			"filter":  filter,
+			"options": options}, map[string]interface{}{
+			"users": users,
+			"total": total,
+			"err":   err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":     ctx,
-				"filter":  filter,
-				"options": options}, map[string]interface{}{
-				"users": users,
-				"total": total,
-				"err":   err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Users.Find(ctx, filter, options)
+	return users, total, err
 }
 
 // Get implements users.Users
 func (_d telemetryMiddleware) Get(ctx context.Context, userId string) (user *users.User, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Users"),
 		attribute.String("method", "Get"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Get")
+	defer _span.End()
+
+	user, err = _d.Users.Get(ctx, userId)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"userId": userId}, map[string]interface{}{
+			"user": user,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"userId": userId}, map[string]interface{}{
-				"user": user,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Users.Get(ctx, userId)
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
+
+	return user, err
 }
 
 // GetByIdentity implements users.Users
 func (_d telemetryMiddleware) GetByIdentity(ctx context.Context, identity string) (user *users.User, err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Users"),
 		attribute.String("method", "GetByIdentity"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.GetByIdentity")
+	defer _span.End()
+
+	user, err = _d.Users.GetByIdentity(ctx, identity)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":      ctx,
+			"identity": identity}, map[string]interface{}{
+			"user": user,
+			"err":  err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":      ctx,
-				"identity": identity}, map[string]interface{}{
-				"user": user,
-				"err":  err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Users.GetByIdentity(ctx, identity)
+	return user, err
 }
 
 // Update implements users.Users
 func (_d telemetryMiddleware) Update(ctx context.Context, update *users.User) (err error) {
-	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+	var att = []attribute.KeyValue{
 		attribute.String("service", "Users"),
 		attribute.String("method", "Update"),
-	))
-
-	_d.requestMetrics.Total.Add(ctx, 1, attributes)
+	}
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	start := time.Now()
 	ctx, _span := otel.Tracer(_d._instance).Start(ctx, "Users.Update")
+	defer _span.End()
+
+	err = _d.Users.Update(ctx, update)
+
+	_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+	caller, _ := oid.NewObjectId(auth.GetPrincipal(ctx))
+	if caller != nil {
+		att = append(att, attribute.String("caller", caller.String()))
+	}
+
+	_d.requestMetrics.Total.Add(ctx, 1, otelmetric.WithAttributeSet(attribute.NewSet(att...)))
+
+	if _d._spanDecorator != nil {
+		_d._spanDecorator(_span, map[string]interface{}{
+			"ctx":    ctx,
+			"update": update}, map[string]interface{}{
+			"err": err})
+	} else if err != nil {
+		_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
+
+		_span.RecordError(err)
+		_span.SetAttributes(attribute.String("event", "error"))
+		_span.SetAttributes(attribute.String("message", err.Error()))
+	}
 
-	defer func() {
-		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
-
-		if _d._spanDecorator != nil {
-			_d._spanDecorator(_span, map[string]interface{}{
-				"ctx":    ctx,
-				"update": update}, map[string]interface{}{
-				"err": err})
-		} else if err != nil {
-			_d.requestMetrics.FailedTotal.Add(ctx, 1, attributes)
-
-			_span.RecordError(err)
-			_span.SetAttributes(attribute.String("event", "error"))
-			_span.SetAttributes(attribute.String("message", err.Error()))
-		}
-
-		_span.End()
-	}()
-	return _d.Users.Update(ctx, update)
+	return err
 }
diff --git a/yaml/file_resolver.go b/yaml/file_resolver.go
new file mode 100644
index 0000000000000000000000000000000000000000..03a795d9871571c1c5b640ed9c91877b8918de18
--- /dev/null
+++ b/yaml/file_resolver.go
@@ -0,0 +1,31 @@
+package yaml
+
+import (
+	"io"
+
+	"git.perx.ru/perxis/perxis-go/pkg/errors"
+	"gopkg.in/yaml.v3"
+)
+
+// FileResolver подключает содержимое целевого файла в качестве значения поля.
+func FileResolver(tp TagProcessor, node *yaml.Node) (*yaml.Node, error) {
+	if node.Kind != yaml.ScalarNode {
+		return nil, errors.New("!include on a non-scalar node")
+	}
+
+	file, err := tp.FS().Open(node.Value)
+	if err != nil {
+		return nil, err
+	}
+	defer func() { _ = file.Close() }()
+
+	bytes, err := io.ReadAll(file)
+	if err != nil {
+		return nil, err
+	}
+
+	out := new(yaml.Node)
+	out.SetString(string(bytes))
+
+	return out, err
+}
diff --git a/yaml/include_resolver.go b/yaml/include_resolver.go
new file mode 100644
index 0000000000000000000000000000000000000000..0f459c539ab2a244413eab46f2a67181cfce0a0a
--- /dev/null
+++ b/yaml/include_resolver.go
@@ -0,0 +1,33 @@
+package yaml
+
+import (
+	"path/filepath"
+
+	"git.perx.ru/perxis/perxis-go/pkg/errors"
+	"gopkg.in/yaml.v3"
+)
+
+// IncludeResolver включает содержимое целевого YAML-файла в поле.
+func IncludeResolver(tp TagProcessor, node *yaml.Node) (*yaml.Node, error) {
+	if node.Kind != yaml.ScalarNode {
+		return nil, errors.New("!include on a non-scalar node")
+	}
+
+	if ext := filepath.Ext(node.Value); ext != ".yaml" && ext != ".yml" {
+		return nil, errors.New("!include on file with unknown extension")
+	}
+
+	file, err := tp.FS().Open(node.Value)
+	if err != nil {
+		return nil, err
+	}
+	defer func() { _ = file.Close() }()
+
+	out := new(yaml.Node)
+	err = yaml.NewDecoder(file).Decode(WithTagProcessor(tp.FS())(out))
+	if err != nil {
+		return nil, err
+	}
+
+	return out, nil
+}
diff --git a/yaml/tag_processor.go b/yaml/tag_processor.go
new file mode 100644
index 0000000000000000000000000000000000000000..89678b93d8242fb15260193208d8445404570cc4
--- /dev/null
+++ b/yaml/tag_processor.go
@@ -0,0 +1,61 @@
+package yaml
+
+import (
+	"io/fs"
+
+	"gopkg.in/yaml.v3"
+)
+
+type TagProcessor interface {
+	yaml.Unmarshaler
+	FS() fs.FS
+}
+
+// tagProcessor обёртка для декодирования целевого значения.
+//
+// Перед декодированием значения обрабатываются все теги узла.
+type tagProcessor struct {
+	fsys   fs.FS
+	target any
+}
+
+// WithTagProcessor возвращает функцию, которая оборачивает декодируемые значения для поддержки обработки тегов YAML.
+//
+// Для путей к файлам, используемых в качестве значений тегов, пути должны быть указаны относительно переданной файловой системы.
+func WithTagProcessor(fsys fs.FS) func(any) *tagProcessor {
+	return func(v any) *tagProcessor {
+		return &tagProcessor{fsys: fsys, target: v}
+	}
+}
+
+func (tp *tagProcessor) FS() fs.FS {
+	return tp.fsys
+}
+
+func (tp *tagProcessor) UnmarshalYAML(value *yaml.Node) error {
+	resolved, err := resolveTags(tp, value)
+	if err != nil {
+		return err
+	}
+	return resolved.Decode(tp.target)
+}
+
+// resolveTags обрабатывает все теги YAML для переданного узла и возвращает исправленный узел.
+// Если узел представляет собой последовательность или словарь, то обрабатываются теги для его дочерних элементов.
+func resolveTags(tp TagProcessor, node *yaml.Node) (*yaml.Node, error) {
+	switch node.Kind {
+	case yaml.SequenceNode, yaml.MappingNode:
+		for i := range node.Content {
+			var err error
+			node.Content[i], err = resolveTags(tp, node.Content[i])
+			if err != nil {
+				return nil, err
+			}
+		}
+	default:
+		if resolver, ok := tagResolvers[node.Tag]; ok {
+			return resolver.Resolve(tp, node)
+		}
+	}
+	return node, nil
+}
diff --git a/yaml/tag_processor_test.go b/yaml/tag_processor_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e54ec041180e1fa31975ea9fdd9e789ebcdc2e2a
--- /dev/null
+++ b/yaml/tag_processor_test.go
@@ -0,0 +1,64 @@
+package yaml
+
+import (
+	"testing"
+
+	"git.perx.ru/perxis/perxis-go/yaml/testdata"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"gopkg.in/yaml.v3"
+)
+
+func TestTagProcessor(t *testing.T) {
+	t.Run("!file", func(t *testing.T) {
+		file, err := testdata.FS.Open("file/file_simple.yaml")
+		require.NoError(t, err)
+		defer file.Close()
+
+		var result any
+		decoder := yaml.NewDecoder(file)
+		err = decoder.Decode(WithTagProcessor(testdata.FS)(&result))
+		require.NoError(t, err)
+		assert.Equal(t, map[string]any{"config": `server {
+    listen 80;
+    server_name example.com;
+
+    location / {
+        root /var/www/example.com/html;
+        index index.html index.htm;
+        try_files $uri $uri/ =404;
+    }
+}`}, result)
+	})
+	t.Run("!include", func(t *testing.T) {
+		t.Run("simple", func(t *testing.T) {
+			file, err := testdata.FS.Open("include/include_simple.yaml")
+			require.NoError(t, err)
+			defer file.Close()
+
+			var result any
+			decoder := yaml.NewDecoder(file)
+			err = decoder.Decode(WithTagProcessor(testdata.FS)(&result))
+			require.NoError(t, err)
+			assert.Equal(t, map[string]any{"data": map[string]any{"text": "Hello, World!"}}, result)
+		})
+		t.Run("with merge", func(t *testing.T) {
+			file, err := testdata.FS.Open("include/include_merge.yaml")
+			require.NoError(t, err)
+			defer file.Close()
+
+			var result any
+			decoder := yaml.NewDecoder(file)
+			err = decoder.Decode(WithTagProcessor(testdata.FS)(&result))
+			require.NoError(t, err)
+			assert.Equal(t, map[string]any{
+				"server": map[string]any{
+					"host": "dev.perx.ru",
+					"port": 3000,
+					"ssl":  true,
+					"tags": []any{"http", "api"},
+				},
+			}, result)
+		})
+	})
+}
diff --git a/yaml/testdata/file/file_simple.yaml b/yaml/testdata/file/file_simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6e7181a3eb1ae553aa5a8055c9a95f772cb43e0b
--- /dev/null
+++ b/yaml/testdata/file/file_simple.yaml
@@ -0,0 +1 @@
+config: !file file/nginx.conf
\ No newline at end of file
diff --git a/yaml/testdata/file/nginx.conf b/yaml/testdata/file/nginx.conf
new file mode 100644
index 0000000000000000000000000000000000000000..a9bbbc506ed333d44456d224cecda27d77d65827
--- /dev/null
+++ b/yaml/testdata/file/nginx.conf
@@ -0,0 +1,10 @@
+server {
+    listen 80;
+    server_name example.com;
+
+    location / {
+        root /var/www/example.com/html;
+        index index.html index.htm;
+        try_files $uri $uri/ =404;
+    }
+}
\ No newline at end of file
diff --git a/yaml/testdata/include/default_server_config.yaml b/yaml/testdata/include/default_server_config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..eff5d022e1e6778243499803d37d589a96b813b9
--- /dev/null
+++ b/yaml/testdata/include/default_server_config.yaml
@@ -0,0 +1,4 @@
+host: localhost
+port: 3000
+ssl: true
+<<: !include include/default_server_tags.yaml
\ No newline at end of file
diff --git a/yaml/testdata/include/default_server_tags.yaml b/yaml/testdata/include/default_server_tags.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1f7c1497f5ea652c94b1e21fc48823147d728105
--- /dev/null
+++ b/yaml/testdata/include/default_server_tags.yaml
@@ -0,0 +1 @@
+tags: [ http, api ]
\ No newline at end of file
diff --git a/yaml/testdata/include/include_merge.yaml b/yaml/testdata/include/include_merge.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..894a9a91c0491a56663bb1e831ae9e0802727498
--- /dev/null
+++ b/yaml/testdata/include/include_merge.yaml
@@ -0,0 +1,3 @@
+server:
+  <<: !include include/default_server_config.yaml
+  host: dev.perx.ru
\ No newline at end of file
diff --git a/yaml/testdata/include/include_simple.yaml b/yaml/testdata/include/include_simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..689f5f9f0cd8e2f5acf9f05eb248bf92e3df168a
--- /dev/null
+++ b/yaml/testdata/include/include_simple.yaml
@@ -0,0 +1 @@
+data: !include include/simple_data.yaml
\ No newline at end of file
diff --git a/yaml/testdata/include/simple_data.yaml b/yaml/testdata/include/simple_data.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a0bfdf8ea14a5dae1dbe66345309cc67df0b2f4e
--- /dev/null
+++ b/yaml/testdata/include/simple_data.yaml
@@ -0,0 +1 @@
+text: Hello, World!
\ No newline at end of file
diff --git a/yaml/testdata/testdata.go b/yaml/testdata/testdata.go
new file mode 100644
index 0000000000000000000000000000000000000000..f8b469980cf76e31cd31f40dfae6f6cc0f92dcb1
--- /dev/null
+++ b/yaml/testdata/testdata.go
@@ -0,0 +1,6 @@
+package testdata
+
+import "embed"
+
+//go:embed *
+var FS embed.FS
diff --git a/yaml/yaml.go b/yaml/yaml.go
new file mode 100644
index 0000000000000000000000000000000000000000..3830b76d2f606f32013236152479a2eaa2c1609f
--- /dev/null
+++ b/yaml/yaml.go
@@ -0,0 +1,34 @@
+package yaml
+
+import (
+	"gopkg.in/yaml.v3"
+)
+
+var (
+	NewDecoder = yaml.NewDecoder
+	NewEncoder = yaml.NewEncoder
+	Unmarshal  = yaml.Unmarshal
+	Marshal    = yaml.Marshal
+)
+
+var tagResolvers = make(map[string]Resolver)
+
+func RegisterTagResolver(tag string, resolver Resolver) {
+	tagResolvers[tag] = resolver
+}
+
+// Resolver обрабатывает тег YAML и возвращает его обработанный вариант
+type Resolver interface {
+	Resolve(tp TagProcessor, node *yaml.Node) (*yaml.Node, error)
+}
+
+type ResolverFunc func(TagProcessor, *yaml.Node) (*yaml.Node, error)
+
+func (fn ResolverFunc) Resolve(tp TagProcessor, node *yaml.Node) (*yaml.Node, error) {
+	return fn(tp, node)
+}
+
+func init() {
+	RegisterTagResolver("!include", ResolverFunc(IncludeResolver))
+	RegisterTagResolver("!file", ResolverFunc(FileResolver))
+}