From 097c706ff1857fc825a36237d68c7f60119937ff Mon Sep 17 00:00:00 2001
From: Alex Petraky <petraky@perx.ru>
Date: Fri, 27 Sep 2024 13:19:12 +0000
Subject: [PATCH] =?UTF-8?q?feat:=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?=
 =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BC=D0=B5=D1=82=D1=80=D0=B8?=
 =?UTF-8?q?=D0=BA=D0=B8=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?=
 =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F=D0=BC/=D0=BF=D1=80?=
 =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=D0=BC=20=D0=B8?=
 =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D1=80=D0=B0=D0=BD=D1=81=D1=82?=
 =?UTF-8?q?=D0=B2=D0=B0=D0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Close #PRXS-2852
---
 assets/templates/middleware/telemetry_account |  78 +++
 assets/templates/middleware/telemetry_content | 130 +++++
 images/middleware/telemetry_middleware.go     |   4 +-
 pkg/clients/client.go                         |   4 +
 .../middleware/telemetry_middleware.go        | 175 ++++++-
 pkg/collaborators/collaborator.go             |   4 +
 .../middleware/telemetry_middleware.go        | 124 ++++-
 pkg/collections/collection.go                 |   4 +
 .../middleware/telemetry_middleware.go        | 175 ++++++-
 .../middleware/telemetry_middleware.go        | 178 ++++++-
 pkg/environments/environment.go               |   4 +
 .../middleware/telemetry_middleware.go        | 196 +++++++-
 pkg/files/middleware/telemetry_middleware.go  |   4 +-
 pkg/invitations/invitation.go                 |   4 +
 .../middleware/telemetry_middleware.go        | 160 +++++-
 pkg/items/item.go                             |   4 +
 pkg/items/middleware/telemetry_middleware.go  | 469 ++++++++++++++++--
 pkg/locales/locale.go                         |   4 +
 .../middleware/telemetry_middleware.go        | 112 ++++-
 pkg/members/middleware/middleware.go          |   2 +-
 .../middleware/telemetry_middleware.go        |  11 +-
 .../middleware/telemetry_middleware.go        |  10 +-
 .../middleware/telemetry_middleware.go        |  52 +-
 pkg/roles/middleware/middleware.go            |   2 +-
 pkg/roles/middleware/telemetry_middleware.go  | 133 ++++-
 pkg/roles/role.go                             |   4 +
 .../middleware/access_logging_middleware.go   |  38 +-
 pkg/spaces/middleware/telemetry_middleware.go | 343 ++++++++++++-
 pkg/spaces/space.go                           |   4 +
 pkg/users/middleware/telemetry_middleware.go  |  11 +-
 30 files changed, 2228 insertions(+), 215 deletions(-)
 create mode 100644 assets/templates/middleware/telemetry_account
 create mode 100644 assets/templates/middleware/telemetry_content

diff --git a/assets/templates/middleware/telemetry_account b/assets/templates/middleware/telemetry_account
new file mode 100644
index 00000000..39bf058e
--- /dev/null
+++ b/assets/templates/middleware/telemetry_account
@@ -0,0 +1,78 @@
+// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+
+import (
+    "context"
+    "time"
+
+    "git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
+    "go.opentelemetry.io/otel"
+    "go.opentelemetry.io/otel/attribute"
+    otelmetric "go.opentelemetry.io/otel/metric"
+    "go.opentelemetry.io/otel/trace"
+)
+
+{{ $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}} {
+  attributes := otelmetric.WithAttributeSet(attribute.NewSet(
+  attribute.String("service", "{{ $.Interface.Name }}"),
+  attribute.String("method", "{{ $method.Name }}"),
+  attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
+  ))
+
+  _d.requestMetrics.Total.Add(ctx, 1, attributes)
+
+  start := time.Now()
+  ctx, _span := otel.Tracer(_d._instance).Start(ctx, "{{$.Interface.Name}}.{{$method.Name}}")
+
+  defer func() {
+    _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+    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}}
+    _span.End()
+  }()
+  {{$method.Pass (printf "_d.%s." $.Interface.Name) }}
+}
+  {{end}}
+{{end}}
\ No newline at end of file
diff --git a/assets/templates/middleware/telemetry_content b/assets/templates/middleware/telemetry_content
new file mode 100644
index 00000000..8f3903c7
--- /dev/null
+++ b/assets/templates/middleware/telemetry_content
@@ -0,0 +1,130 @@
+// source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
+
+import (
+    "context"
+    "time"
+
+    oid "git.perx.ru/perxis/perxis-go/id"
+    "git.perx.ru/perxis/perxis-go/pkg/telemetry/metrics"
+    "go.opentelemetry.io/otel"
+    "go.opentelemetry.io/otel/attribute"
+    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
+}
+{{- $paramsList := list -}}
+{{range $method := .Interface.Methods}}
+  {{if $method.AcceptsContext}}
+    {{- $paramsList = list -}}
+    {{- $paramsList = append $paramsList $method.ParamsNames -}}
+    {{- $paramsList = append $paramsList $method.ResultsNames -}}
+    // {{$method.Name}} implements {{$.Interface.Type}}
+func (_d {{$decorator}}) {{$method.Declaration}} {
+    {{ $spaceID := "" }}
+    {{- range $param := $method.Params -}}
+      {{- if (eq $param.Name "spaceId") -}}
+        {{- $spaceID = "spaceId" -}}
+      {{- end -}}
+    {{- end -}}
+  var att = []attribute.KeyValue{
+      attribute.String("service", "{{ $.Interface.Name }}"),
+      attribute.String("method", "{{ $method.Name }}"),
+  }
+
+  attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
+
+  _d.requestMetrics.Total.Add(ctx, 1, attributes)
+
+  start := time.Now()
+  ctx, _span := otel.Tracer(_d._instance).Start(ctx, "{{$.Interface.Name}}.{{$method.Name}}")
+
+  defer func() {
+    _d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
+
+    var spID string
+    {{- if (eq $spaceID "") -}}
+    {{- $l := len $paramsList }}
+    vv := []interface{}{
+    {{- range $i, $p := $paramsList | toStrings }}
+        {{- if (eq $i $l) }}
+    {{- $p }}
+        {{- else }}
+    {{- $p }},
+        {{- end -}}
+    {{- end -}}
+    }
+    for _, v := range vv {
+        if v == nil {
+            continue
+        }
+        if sg, ok := v.(SpaceGetter); ok {
+            spID = sg.GetSpaceID()
+            break
+        }
+    }
+    {{- else }}
+    spID = spaceId
+    {{- end }}
+    if spID != "" {
+        principal := auth.GetPrincipal(ctx)
+        if accessor, ok := principal.(auth.SpaceAccessor); ok {
+            principal = accessor.Space(spID)
+        }
+        caller, _ := oid.NewObjectId(principal)
+
+        att = append(att, attribute.String("spaceID", spID))
+        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}}
+    _span.End()
+  }()
+  {{$method.Pass (printf "_d.%s." $.Interface.Name) }}
+}
+  {{end}}
+{{end}}
\ No newline at end of file
diff --git a/images/middleware/telemetry_middleware.go b/images/middleware/telemetry_middleware.go
index 72d38c2e..b34c1f61 100644
--- a/images/middleware/telemetry_middleware.go
+++ b/images/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\assets\templates\middleware\telemetry
+// template: ../../assets/templates/middleware/telemetry
 // 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 ""
+//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
 
diff --git a/pkg/clients/client.go b/pkg/clients/client.go
index 6c4c6735..447c523a 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 22c604f2..284aac95 100644
--- a/pkg/clients/middleware/telemetry_middleware.go
+++ b/pkg/clients/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +22,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,10 +56,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -63,6 +71,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, client *clients.Client
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, client, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -84,10 +116,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, client *clients.Client
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -97,6 +131,21 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, id str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -118,10 +167,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, id str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -131,6 +182,21 @@ func (_d telemetryMiddleware) Enable(ctx context.Context, spaceId string, id str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -153,10 +219,12 @@ func (_d telemetryMiddleware) Enable(ctx context.Context, spaceId string, id str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -166,6 +234,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, id string
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -188,10 +271,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, id string
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -201,6 +286,21 @@ func (_d telemetryMiddleware) GetBy(ctx context.Context, spaceId string, params
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -223,10 +323,12 @@ func (_d telemetryMiddleware) GetBy(ctx context.Context, spaceId string, params
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -236,6 +338,21 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (clients
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -257,10 +374,12 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (clients
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -270,6 +389,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, client *clients.Client
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, client, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/collaborators/collaborator.go b/pkg/collaborators/collaborator.go
index 5fe1b481..b3406960 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 cd950166..310eb2b5 100644
--- a/pkg/collaborators/middleware/telemetry_middleware.go
+++ b/pkg/collaborators/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +22,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,10 +56,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -63,6 +71,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, subject s
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -85,10 +108,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, subject s
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -98,6 +123,21 @@ func (_d telemetryMiddleware) ListCollaborators(ctx context.Context, spaceId str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -119,10 +159,12 @@ func (_d telemetryMiddleware) ListCollaborators(ctx context.Context, spaceId str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -132,6 +174,30 @@ func (_d telemetryMiddleware) ListSpaces(ctx context.Context, subject string) (s
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, subject, spaces, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -153,10 +219,12 @@ func (_d telemetryMiddleware) ListSpaces(ctx context.Context, subject string) (s
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -166,6 +234,21 @@ func (_d telemetryMiddleware) Remove(ctx context.Context, spaceId string, subjec
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -187,10 +270,12 @@ func (_d telemetryMiddleware) Remove(ctx context.Context, spaceId string, subjec
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -200,6 +285,21 @@ func (_d telemetryMiddleware) Set(ctx context.Context, spaceId string, subject s
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/collections/collection.go b/pkg/collections/collection.go
index b5d2418a..2baeffc6 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 306570db..1651bef4 100644
--- a/pkg/collections/middleware/telemetry_middleware.go
+++ b/pkg/collections/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +23,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,10 +57,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -64,6 +72,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, collection *collection
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, collection, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -85,10 +117,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, collection *collection
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -98,6 +132,21 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -120,10 +169,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -133,6 +184,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -157,10 +223,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -170,6 +238,21 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string, envId st
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -193,10 +276,12 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string, envId st
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -206,6 +291,21 @@ func (_d telemetryMiddleware) SetSchema(ctx context.Context, spaceId string, env
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -229,10 +329,12 @@ func (_d telemetryMiddleware) SetSchema(ctx context.Context, spaceId string, env
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -242,6 +344,21 @@ func (_d telemetryMiddleware) SetState(ctx context.Context, spaceId string, envI
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -265,10 +382,12 @@ func (_d telemetryMiddleware) SetState(ctx context.Context, spaceId string, envI
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -278,6 +397,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, coll *collections.Coll
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, coll, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/delivery/middleware/telemetry_middleware.go b/pkg/delivery/middleware/telemetry_middleware.go
index 05a01730..d8ad462e 100644
--- a/pkg/delivery/middleware/telemetry_middleware.go
+++ b/pkg/delivery/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +26,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,10 +60,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -67,6 +75,21 @@ func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, env
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -92,10 +115,12 @@ func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, env
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -105,6 +130,21 @@ func (_d telemetryMiddleware) FindItems(ctx context.Context, spaceId string, env
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -131,10 +171,12 @@ func (_d telemetryMiddleware) FindItems(ctx context.Context, spaceId string, env
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -144,6 +186,21 @@ func (_d telemetryMiddleware) GetCollection(ctx context.Context, spaceId string,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -167,10 +224,12 @@ func (_d telemetryMiddleware) GetCollection(ctx context.Context, spaceId string,
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -180,6 +239,21 @@ func (_d telemetryMiddleware) GetEnvironment(ctx context.Context, spaceId string
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -202,10 +276,12 @@ func (_d telemetryMiddleware) GetEnvironment(ctx context.Context, spaceId string
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -215,6 +291,21 @@ func (_d telemetryMiddleware) GetItem(ctx context.Context, spaceId string, envId
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -240,10 +331,12 @@ func (_d telemetryMiddleware) GetItem(ctx context.Context, spaceId string, envId
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -253,6 +346,21 @@ func (_d telemetryMiddleware) ListCollections(ctx context.Context, spaceId strin
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -275,10 +383,12 @@ func (_d telemetryMiddleware) ListCollections(ctx context.Context, spaceId strin
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -288,6 +398,21 @@ func (_d telemetryMiddleware) ListEnvironments(ctx context.Context, spaceId stri
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -309,10 +434,12 @@ func (_d telemetryMiddleware) ListEnvironments(ctx context.Context, spaceId stri
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -322,6 +449,21 @@ func (_d telemetryMiddleware) ListLocales(ctx context.Context, spaceId string) (
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/environments/environment.go b/pkg/environments/environment.go
index 3e0f7bb6..6ccfc255 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 95b50dbc..bd5388ce 100644
--- a/pkg/environments/middleware/telemetry_middleware.go
+++ b/pkg/environments/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +22,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,10 +56,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -63,6 +71,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, env *environments.Envi
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, env, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -84,10 +116,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, env *environments.Envi
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -97,6 +131,21 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -118,10 +167,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, envId
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -131,6 +182,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -153,10 +219,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -166,6 +234,21 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (envs []
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -187,10 +270,12 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (envs []
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -200,6 +285,21 @@ func (_d telemetryMiddleware) Migrate(ctx context.Context, spaceId string, envId
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -222,10 +322,12 @@ func (_d telemetryMiddleware) Migrate(ctx context.Context, spaceId string, envId
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -235,6 +337,21 @@ func (_d telemetryMiddleware) RemoveAlias(ctx context.Context, spaceId string, e
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -257,10 +374,12 @@ func (_d telemetryMiddleware) RemoveAlias(ctx context.Context, spaceId string, e
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -270,6 +389,21 @@ func (_d telemetryMiddleware) SetAlias(ctx context.Context, spaceId string, envI
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -292,10 +426,12 @@ func (_d telemetryMiddleware) SetAlias(ctx context.Context, spaceId string, envI
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -305,6 +441,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, env *environments.Envi
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, env, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/files/middleware/telemetry_middleware.go b/pkg/files/middleware/telemetry_middleware.go
index bed97ea1..386ad3eb 100644
--- a/pkg/files/middleware/telemetry_middleware.go
+++ b/pkg/files/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry
 // 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 ""
+//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
 
diff --git a/pkg/invitations/invitation.go b/pkg/invitations/invitation.go
index a5b91ed0..86d0db29 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 44b7d268..b46faa4a 100644
--- a/pkg/invitations/middleware/telemetry_middleware.go
+++ b/pkg/invitations/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +23,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,10 +57,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -64,6 +72,30 @@ func (_d telemetryMiddleware) Accept(ctx context.Context, invitationId string, u
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, invitationId, userId, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -85,10 +117,12 @@ func (_d telemetryMiddleware) Accept(ctx context.Context, invitationId string, u
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -98,6 +132,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, invitation *invitation
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, invitation, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -119,10 +177,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, invitation *invitation
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -132,6 +192,30 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, invitationId string) (
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, invitationId, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -152,10 +236,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, invitationId string) (
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -165,6 +251,30 @@ func (_d telemetryMiddleware) Find(ctx context.Context, filter *invitations.Filt
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, filter, opts, invitations, total, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -188,10 +298,12 @@ func (_d telemetryMiddleware) Find(ctx context.Context, filter *invitations.Filt
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -201,6 +313,30 @@ func (_d telemetryMiddleware) Get(ctx context.Context, invitationId string) (inv
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, invitationId, invitation, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/items/item.go b/pkg/items/item.go
index 78e33bab..fa1bc084 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 98891f9f..dc9d8d45 100644
--- a/pkg/items/middleware/telemetry_middleware.go
+++ b/pkg/items/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +23,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,10 +57,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -64,6 +72,21 @@ func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, env
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -89,10 +112,12 @@ func (_d telemetryMiddleware) Aggregate(ctx context.Context, spaceId string, env
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -102,6 +127,21 @@ func (_d telemetryMiddleware) AggregatePublished(ctx context.Context, spaceId st
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -127,10 +167,12 @@ func (_d telemetryMiddleware) AggregatePublished(ctx context.Context, spaceId st
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -140,6 +182,30 @@ func (_d telemetryMiddleware) Archive(ctx context.Context, item *items.Item, opt
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -161,10 +227,12 @@ func (_d telemetryMiddleware) Archive(ctx context.Context, item *items.Item, opt
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -174,6 +242,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, item *items.Item, opts
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, opts, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -196,10 +288,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, item *items.Item, opts
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -209,6 +303,30 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, item *items.Item, opti
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -230,10 +348,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, item *items.Item, opti
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -243,6 +363,21 @@ func (_d telemetryMiddleware) Find(ctx context.Context, spaceId string, envId st
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -269,10 +404,12 @@ func (_d telemetryMiddleware) Find(ctx context.Context, spaceId string, envId st
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -282,6 +419,21 @@ func (_d telemetryMiddleware) FindArchived(ctx context.Context, spaceId string,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -308,10 +460,12 @@ func (_d telemetryMiddleware) FindArchived(ctx context.Context, spaceId string,
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -321,6 +475,21 @@ func (_d telemetryMiddleware) FindPublished(ctx context.Context, spaceId string,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -347,10 +516,12 @@ func (_d telemetryMiddleware) FindPublished(ctx context.Context, spaceId string,
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -360,6 +531,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -385,10 +571,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -398,6 +586,21 @@ func (_d telemetryMiddleware) GetPublished(ctx context.Context, spaceId string,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -423,10 +626,12 @@ func (_d telemetryMiddleware) GetPublished(ctx context.Context, spaceId string,
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -436,6 +641,21 @@ func (_d telemetryMiddleware) GetRevision(ctx context.Context, spaceId string, e
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -462,10 +682,12 @@ func (_d telemetryMiddleware) GetRevision(ctx context.Context, spaceId string, e
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -475,6 +697,30 @@ func (_d telemetryMiddleware) Introspect(ctx context.Context, item *items.Item,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, opts, itm, sch, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -498,10 +744,12 @@ func (_d telemetryMiddleware) Introspect(ctx context.Context, item *items.Item,
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -511,6 +759,21 @@ func (_d telemetryMiddleware) ListRevisions(ctx context.Context, spaceId string,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -536,10 +799,12 @@ func (_d telemetryMiddleware) ListRevisions(ctx context.Context, spaceId string,
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -549,6 +814,30 @@ func (_d telemetryMiddleware) Publish(ctx context.Context, item *items.Item, opt
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -570,10 +859,12 @@ func (_d telemetryMiddleware) Publish(ctx context.Context, item *items.Item, opt
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -583,6 +874,30 @@ func (_d telemetryMiddleware) Unarchive(ctx context.Context, item *items.Item, o
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -604,10 +919,12 @@ func (_d telemetryMiddleware) Unarchive(ctx context.Context, item *items.Item, o
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -617,6 +934,30 @@ func (_d telemetryMiddleware) Undelete(ctx context.Context, item *items.Item, op
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -638,10 +979,12 @@ func (_d telemetryMiddleware) Undelete(ctx context.Context, item *items.Item, op
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -651,6 +994,30 @@ func (_d telemetryMiddleware) Unpublish(ctx context.Context, item *items.Item, o
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -672,10 +1039,12 @@ func (_d telemetryMiddleware) Unpublish(ctx context.Context, item *items.Item, o
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -685,6 +1054,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, item *items.Item, opti
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, item, options, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/locales/locale.go b/pkg/locales/locale.go
index e0e32616..80cd2d60 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 98fe346e..b1196849 100644
--- a/pkg/locales/middleware/telemetry_middleware.go
+++ b/pkg/locales/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +22,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,10 +56,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -63,6 +71,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, locale *locales.Locale
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, locale, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -84,10 +116,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, locale *locales.Locale
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -97,6 +131,21 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, locale
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -118,10 +167,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, locale
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -131,6 +182,21 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (locales
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -152,10 +218,12 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (locales
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -165,6 +233,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, locale *locales.Locale
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, locale, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/members/middleware/middleware.go b/pkg/members/middleware/middleware.go
index 04626790..bb491623 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 6193a4ba..68267958 100644
--- a/pkg/members/middleware/telemetry_middleware.go
+++ b/pkg/members/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_account
 // 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 ""
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/members -i Members -t ../../../assets/templates/middleware/telemetry_account -o telemetry_middleware.go -l ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,7 @@ import (
 	"context"
 	"time"
 
+	"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"
@@ -53,6 +54,7 @@ func (_d telemetryMiddleware) Get(ctx context.Context, orgId string, userId stri
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Members"),
 		attribute.String("method", "Get"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -88,6 +90,7 @@ func (_d telemetryMiddleware) ListMembers(ctx context.Context, orgId string) (me
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Members"),
 		attribute.String("method", "ListMembers"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -122,6 +125,7 @@ func (_d telemetryMiddleware) ListOrganizations(ctx context.Context, userId stri
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Members"),
 		attribute.String("method", "ListOrganizations"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -156,6 +160,7 @@ func (_d telemetryMiddleware) Remove(ctx context.Context, orgId string, userId s
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Members"),
 		attribute.String("method", "Remove"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -190,6 +195,7 @@ func (_d telemetryMiddleware) RemoveAll(ctx context.Context, orgId string) (err
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Members"),
 		attribute.String("method", "RemoveAll"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -223,6 +229,7 @@ func (_d telemetryMiddleware) Set(ctx context.Context, orgId string, userId stri
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Members"),
 		attribute.String("method", "Set"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
diff --git a/pkg/organizations/middleware/telemetry_middleware.go b/pkg/organizations/middleware/telemetry_middleware.go
index d728b1f1..6d35569e 100644
--- a/pkg/organizations/middleware/telemetry_middleware.go
+++ b/pkg/organizations/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_account
 // 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 ""
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/organizations -i Organizations -t ../../../assets/templates/middleware/telemetry_account -o telemetry_middleware.go -l ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,7 @@ import (
 	"context"
 	"time"
 
+	"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"
@@ -54,6 +55,7 @@ func (_d telemetryMiddleware) Create(ctx context.Context, org *organizations.Org
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Create"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -88,6 +90,7 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, orgId string) (err err
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Delete"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -121,6 +124,7 @@ func (_d telemetryMiddleware) Find(ctx context.Context, filter *organizations.Fi
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Find"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -157,6 +161,7 @@ func (_d telemetryMiddleware) Get(ctx context.Context, orgId string) (org *organ
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Get"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -191,6 +196,7 @@ func (_d telemetryMiddleware) Update(ctx context.Context, org *organizations.Org
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Organizations"),
 		attribute.String("method", "Update"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
diff --git a/pkg/references/middleware/telemetry_middleware.go b/pkg/references/middleware/telemetry_middleware.go
index 71c51698..c4203bfe 100644
--- a/pkg/references/middleware/telemetry_middleware.go
+++ b/pkg/references/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +23,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,10 +57,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -64,6 +72,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -89,10 +112,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, envId str
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -102,6 +127,21 @@ func (_d telemetryMiddleware) Publish(ctx context.Context, spaceId string, envId
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/roles/middleware/middleware.go b/pkg/roles/middleware/middleware.go
index 299199a4..aaeb2da8 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 5d9d5e35..65772b99 100644
--- a/pkg/roles/middleware/telemetry_middleware.go
+++ b/pkg/roles/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +22,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,10 +56,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -63,6 +71,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, role *roles.Role) (cre
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, role, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -84,10 +116,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, role *roles.Role) (cre
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -97,6 +131,21 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, roleId
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -118,10 +167,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string, roleId
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -131,6 +182,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, roleId st
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -153,10 +219,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string, roleId st
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -166,6 +234,21 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (roles [
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -187,10 +270,12 @@ func (_d telemetryMiddleware) List(ctx context.Context, spaceId string) (roles [
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -200,6 +285,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, role *roles.Role) (err
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, role, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/roles/role.go b/pkg/roles/role.go
index 76520f8f..81feb1e9 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 9596d7d4..d155ee1f 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 e9623692..f3d69b57 100644
--- a/pkg/spaces/middleware/telemetry_middleware.go
+++ b/pkg/spaces/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // 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 ""
+//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 ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,8 @@ 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 +23,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,10 +57,12 @@ 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -64,6 +72,30 @@ func (_d telemetryMiddleware) AbortTransfer(ctx context.Context, spaceID string)
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, spaceID, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -84,10 +116,12 @@ func (_d telemetryMiddleware) AbortTransfer(ctx context.Context, spaceID string)
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -97,6 +131,30 @@ func (_d telemetryMiddleware) Create(ctx context.Context, space *spaces.Space) (
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, space, created, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -118,10 +176,12 @@ func (_d telemetryMiddleware) Create(ctx context.Context, space *spaces.Space) (
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -131,6 +191,21 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string) (err e
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -151,10 +226,12 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, spaceId string) (err e
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -164,6 +241,30 @@ func (_d telemetryMiddleware) Find(ctx context.Context, filter *spaces.Filter, f
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, filter, fo, spaces, total, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -187,10 +288,12 @@ func (_d telemetryMiddleware) Find(ctx context.Context, filter *spaces.Filter, f
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -200,6 +303,21 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string) (space *s
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -221,10 +339,12 @@ func (_d telemetryMiddleware) Get(ctx context.Context, spaceId string) (space *s
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -234,6 +354,30 @@ func (_d telemetryMiddleware) List(ctx context.Context, orgId string) (spaces []
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, orgId, spaces, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -255,10 +399,12 @@ func (_d telemetryMiddleware) List(ctx context.Context, orgId string) (spaces []
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -268,6 +414,30 @@ func (_d telemetryMiddleware) ListTransfers(ctx context.Context, orgID string) (
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, orgID, spaces, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -289,10 +459,12 @@ func (_d telemetryMiddleware) ListTransfers(ctx context.Context, orgID string) (
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -302,6 +474,30 @@ func (_d telemetryMiddleware) Move(ctx context.Context, spaceID string, orgID st
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, spaceID, orgID, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -323,10 +519,12 @@ func (_d telemetryMiddleware) Move(ctx context.Context, spaceID string, orgID st
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -336,6 +534,30 @@ func (_d telemetryMiddleware) SetState(ctx context.Context, spaceID string, stat
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, spaceID, state, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -357,10 +579,12 @@ func (_d telemetryMiddleware) SetState(ctx context.Context, spaceID string, stat
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -370,6 +594,30 @@ func (_d telemetryMiddleware) Transfer(ctx context.Context, spaceID string, tran
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, spaceID, transferToOrg, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -391,10 +639,12 @@ func (_d telemetryMiddleware) Transfer(ctx context.Context, spaceID string, tran
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -404,6 +654,30 @@ func (_d telemetryMiddleware) Update(ctx context.Context, space *spaces.Space) (
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		vv := []interface{}{ctx, space, err}
+		for _, v := range vv {
+			if v == nil {
+				continue
+			}
+			if sg, ok := v.(SpaceGetter); ok {
+				spID = sg.GetSpaceID()
+				break
+			}
+		}
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
@@ -424,10 +698,12 @@ func (_d telemetryMiddleware) Update(ctx context.Context, space *spaces.Space) (
 
 // 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"),
-	))
+	}
+
+	attributes := otelmetric.WithAttributeSet(attribute.NewSet(att...))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
 
@@ -437,6 +713,21 @@ func (_d telemetryMiddleware) UpdateConfig(ctx context.Context, spaceId string,
 	defer func() {
 		_d.requestMetrics.DurationMilliseconds.Record(ctx, time.Since(start).Milliseconds(), attributes)
 
+		var spID string
+		spID = spaceId
+		if spID != "" {
+			principal := auth.GetPrincipal(ctx)
+			if accessor, ok := principal.(auth.SpaceAccessor); ok {
+				principal = accessor.Space(spID)
+			}
+			caller, _ := oid.NewObjectId(principal)
+
+			att = append(att, attribute.String("spaceID", spID))
+			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,
diff --git a/pkg/spaces/space.go b/pkg/spaces/space.go
index baa44124..f4c5f4ab 100644
--- a/pkg/spaces/space.go
+++ b/pkg/spaces/space.go
@@ -88,3 +88,7 @@ type StateInfo struct {
 func (s Space) Clone() *Space {
 	return &s
 }
+
+func (s Space) GetSpaceID() string {
+	return s.ID
+}
diff --git a/pkg/users/middleware/telemetry_middleware.go b/pkg/users/middleware/telemetry_middleware.go
index 698b4f6b..d508595b 100644
--- a/pkg/users/middleware/telemetry_middleware.go
+++ b/pkg/users/middleware/telemetry_middleware.go
@@ -1,10 +1,10 @@
 // Code generated by gowrap. DO NOT EDIT.
-// template: ..\..\..\assets\templates\middleware\telemetry
+// template: ../../../assets/templates/middleware/telemetry_account
 // 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 ""
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/telemetry_account -o telemetry_middleware.go -l ""
 
 // source template: https://github.com/hexdigest/gowrap/blob/master/templates/opentelemetry
 
@@ -12,6 +12,7 @@ import (
 	"context"
 	"time"
 
+	"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"
@@ -54,6 +55,7 @@ func (_d telemetryMiddleware) Create(ctx context.Context, create *users.User) (u
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Users"),
 		attribute.String("method", "Create"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -88,6 +90,7 @@ func (_d telemetryMiddleware) Delete(ctx context.Context, userId string) (err er
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Users"),
 		attribute.String("method", "Delete"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -121,6 +124,7 @@ func (_d telemetryMiddleware) Find(ctx context.Context, filter *users.Filter, op
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Users"),
 		attribute.String("method", "Find"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -157,6 +161,7 @@ func (_d telemetryMiddleware) Get(ctx context.Context, userId string) (user *use
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Users"),
 		attribute.String("method", "Get"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -191,6 +196,7 @@ func (_d telemetryMiddleware) GetByIdentity(ctx context.Context, identity string
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Users"),
 		attribute.String("method", "GetByIdentity"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
@@ -225,6 +231,7 @@ func (_d telemetryMiddleware) Update(ctx context.Context, update *users.User) (e
 	attributes := otelmetric.WithAttributeSet(attribute.NewSet(
 		attribute.String("service", "Users"),
 		attribute.String("method", "Update"),
+		attribute.String("principal", auth.GetPrincipal(ctx).GetID(ctx)),
 	))
 
 	_d.requestMetrics.Total.Add(ctx, 1, attributes)
-- 
GitLab