diff --git a/pkg/users/middleware/caching_middleware.go b/pkg/users/middleware/caching_middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..6dc04868c75edcd77ba9bb2b3adda3f1ff3022f0
--- /dev/null
+++ b/pkg/users/middleware/caching_middleware.go
@@ -0,0 +1,91 @@
+package service
+
+import (
+	"context"
+
+	"git.perx.ru/perxis/perxis-go/pkg/cache"
+	services "git.perx.ru/perxis/perxis-go/pkg/options"
+	service "git.perx.ru/perxis/perxis-go/pkg/users"
+)
+
+func CachingMiddleware(cache *cache.Cache) Middleware {
+	return func(next service.Users) service.Users {
+		return &cachingMiddleware{
+			cache: cache,
+			next:  next,
+		}
+	}
+}
+
+type cachingMiddleware struct {
+	cache *cache.Cache
+	next  service.Users
+}
+
+func (m cachingMiddleware) Create(ctx context.Context, create *service.User) (user *service.User, err error) {
+	return m.next.Create(ctx, create)
+}
+
+func (m cachingMiddleware) Get(ctx context.Context, userId string) (user *service.User, err error) {
+
+	value, e := m.cache.Get(userId)
+	if e == nil {
+		return value.(*service.User), err
+	}
+	user, err = m.next.Get(ctx, userId)
+	if err == nil {
+		m.cache.Set(user.ID, user)
+		for _, i := range user.Identities {
+			m.cache.Set(i, user)
+		}
+	}
+	return user, err
+}
+
+func (m cachingMiddleware) Find(ctx context.Context, filter *service.Filter, options *services.FindOptions) (users []*service.User, total int, err error) {
+	return m.next.Find(ctx, filter, options)
+}
+
+func (m cachingMiddleware) Update(ctx context.Context, update *service.User) (err error) {
+
+	err = m.next.Update(ctx, update)
+	value, e := m.cache.Get(update.ID)
+	if err == nil && e == nil {
+		usr := value.(*service.User)
+		m.cache.Remove(usr.ID)
+		for _, i := range usr.Identities {
+			m.cache.Remove(i)
+		}
+	}
+	return err
+}
+
+func (m cachingMiddleware) Delete(ctx context.Context, userId string) (err error) {
+
+	err = m.next.Delete(ctx, userId)
+	value, e := m.cache.Get(userId)
+	if err == nil && e == nil {
+		usr := value.(*service.User)
+		m.cache.Remove(usr.ID)
+		for _, i := range usr.Identities {
+			m.cache.Remove(i)
+		}
+	}
+	return err
+}
+
+func (m cachingMiddleware) GetByIdentity(ctx context.Context, identity string) (user *service.User, err error) {
+
+	value, e := m.cache.Get(identity)
+	if e == nil {
+		return value.(*service.User), err
+	}
+	user, err = m.next.GetByIdentity(ctx, identity)
+	if err == nil {
+		m.cache.Set(user.ID, user)
+		for _, i := range user.Identities {
+			m.cache.Set(i, user)
+		}
+	}
+	return user, err
+}
diff --git a/pkg/users/middleware/caching_middleware_test.go b/pkg/users/middleware/caching_middleware_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7ad09b52fdc003eac069005a8cdb956dd58949a7
--- /dev/null
+++ b/pkg/users/middleware/caching_middleware_test.go
@@ -0,0 +1,165 @@
+package service
+
+import (
+	"context"
+	"testing"
+	"time"
+
+	"git.perx.ru/perxis/perxis-go/pkg/cache"
+	"git.perx.ru/perxis/perxis-go/pkg/errors"
+	"git.perx.ru/perxis/perxis-go/pkg/users"
+	"git.perx.ru/perxis/perxis-go/pkg/users/mocks"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/require"
+)
+
+func TestUsersCache(t *testing.T) {
+
+	const (
+		userID   = "user_id"
+		identity = "user identity"
+		size     = 5
+		ttl      = 20 * time.Millisecond
+	)
+
+	errNotFound := errors.NotFound(errors.New("not found"))
+
+	t.Run("Get from cache", func(t *testing.T) {
+		usrs := &mocks.Users{}
+		ctx := context.Background()
+
+		svc := CachingMiddleware(cache.NewCache(size, ttl))(usrs)
+
+		usrs.On("Get", mock.Anything, userID).Return(&users.User{ID: userID, Name: "User", Identities: []string{identity}}, nil).Once()
+
+		v1, err := svc.Get(ctx, userID)
+		require.NoError(t, err)
+
+		v2, err := svc.Get(ctx, userID)
+		require.NoError(t, err)
+		assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.")
+
+		v3, err := svc.GetByIdentity(ctx, identity)
+		require.NoError(t, err)
+		assert.Same(t, v2, v3, "Ожидается получение объекта из кэша при запросе по Identity.")
+
+		usrs.AssertExpectations(t)
+	})
+
+	t.Run("GetByIdentity from cache", func(t *testing.T) {
+		usrs := &mocks.Users{}
+		ctx := context.Background()
+
+		svc := CachingMiddleware(cache.NewCache(size, ttl))(usrs)
+
+		usrs.On("GetByIdentity", mock.Anything, identity).Return(&users.User{ID: userID, Name: "User", Identities: []string{identity}}, nil).Once()
+
+		v1, err := svc.GetByIdentity(ctx, identity)
+		require.NoError(t, err)
+
+		v2, err := svc.GetByIdentity(ctx, identity)
+		require.NoError(t, err)
+		assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.")
+
+		v3, err := svc.Get(ctx, userID)
+		require.NoError(t, err)
+		assert.Same(t, v2, v3, "Ожидается получение объекта из кэша при запросе по userID.")
+
+		usrs.AssertExpectations(t)
+	})
+
+	t.Run("Invalidate Cache", func(t *testing.T) {
+		t.Run("After Update", func(t *testing.T) {
+			usrs := &mocks.Users{}
+			ctx := context.Background()
+
+			svc := CachingMiddleware(cache.NewCache(size, ttl))(usrs)
+
+			usrs.On("Get", mock.Anything, userID).Return(&users.User{ID: userID, Name: "User", Identities: []string{identity}}, nil).Once()
+			usrs.On("Update", mock.Anything, mock.Anything).Return(nil).Once()
+
+			v1, err := svc.Get(ctx, userID)
+			require.NoError(t, err)
+
+			v2, err := svc.GetByIdentity(ctx, identity)
+			require.NoError(t, err)
+			assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.")
+
+			err = svc.Update(ctx, &users.User{ID: userID, Name: "New User", Identities: []string{identity}})
+			require.NoError(t, err)
+
+			usrs.On("GetByIdentity", mock.Anything, identity).Return(&users.User{ID: userID, Name: "New User", Identities: []string{identity}}, nil).Once()
+
+			v3, err := svc.GetByIdentity(ctx, identity)
+			require.NoError(t, err)
+			assert.NotSame(t, v3, v2, "Ожидается удаление объекта из кеша после обновления и получение его заново из сервиса.")
+
+			v4, err := svc.Get(ctx, userID)
+			require.NoError(t, err)
+			assert.NotSame(t, v4, v2)
+			assert.Same(t, v4, v3, "Ожидается получение нового обьекта из кеша.")
+
+			usrs.AssertExpectations(t)
+		})
+
+		t.Run("After Delete", func(t *testing.T) {
+			usrs := &mocks.Users{}
+			ctx := context.Background()
+
+			svc := CachingMiddleware(cache.NewCache(size, ttl))(usrs)
+
+			usrs.On("Get", mock.Anything, userID).Return(&users.User{ID: userID, Name: "User", Identities: []string{identity}}, nil).Once()
+			usrs.On("Delete", mock.Anything, mock.Anything).Return(nil).Once()
+
+			v1, err := svc.Get(ctx, userID)
+			require.NoError(t, err)
+
+			v2, err := svc.GetByIdentity(ctx, identity)
+			require.NoError(t, err)
+			assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.")
+
+			err = svc.Delete(ctx, userID)
+			require.NoError(t, err)
+
+			usrs.On("GetByIdentity", mock.Anything, identity).Return(nil, errNotFound).Once()
+			usrs.On("Get", mock.Anything, userID).Return(nil, errNotFound).Once()
+
+			_, err = svc.GetByIdentity(ctx, identity)
+			require.Error(t, err)
+			assert.EqualErrorf(t, err, "not found", "Ожидается удаление объекта из кеша после удаления из хранилища и получение ошибки от сервиса.")
+
+			_, err = svc.Get(ctx, userID)
+			require.Error(t, err)
+			assert.EqualErrorf(t, err, "not found", "Ожидается удаление объекта из кеша после удаления из хранилища и получение ошибки от сервиса.")
+
+			usrs.AssertExpectations(t)
+		})
+
+		t.Run("After TTL expired", func(t *testing.T) {
+			usrs := &mocks.Users{}
+			ctx := context.Background()
+
+			svc := CachingMiddleware(cache.NewCache(size, ttl))(usrs)
+
+			usrs.On("Get", mock.Anything, userID).Return(&users.User{ID: userID, Name: "User", Identities: []string{identity}}, nil).Once()
+
+			v1, err := svc.Get(ctx, userID)
+			require.NoError(t, err)
+
+			v2, err := svc.Get(ctx, userID)
+			require.NoError(t, err)
+			assert.Same(t, v1, v2, "Ожидается получение объекта из кэша.")
+
+			time.Sleep(2 * ttl)
+
+			usrs.On("Get", mock.Anything, userID).Return(&users.User{ID: userID, Name: "User", Identities: []string{identity}}, nil).Once()
+
+			v3, err := svc.Get(ctx, userID)
+			require.NoError(t, err)
+			assert.NotSame(t, v2, v3, "Ожидается получение объекта из кэша при запросе по Identity.")
+
+			usrs.AssertExpectations(t)
+		})
+	})
+}
diff --git a/pkg/users/middleware/error_logging_middleware.go b/pkg/users/middleware/error_logging_middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..b0ec1fea8fa9fda00ac08a73e2e35e2dad51a549
--- /dev/null
+++ b/pkg/users/middleware/error_logging_middleware.go
@@ -0,0 +1,91 @@
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/error_log
+// gowrap: http://github.com/hexdigest/gowrap
+
+package service
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/error_log -o error_logging_middleware.go -l ""
+
+import (
+	"context"
+
+	"git.perx.ru/perxis/perxis-go/pkg/options"
+	"git.perx.ru/perxis/perxis-go/pkg/users"
+	"go.uber.org/zap"
+)
+
+// errorLoggingMiddleware implements users.Users that is instrumented with logging
+type errorLoggingMiddleware struct {
+	logger *zap.Logger
+	next   users.Users
+}
+
+// ErrorLoggingMiddleware instruments an implementation of the users.Users with simple logging
+func ErrorLoggingMiddleware(logger *zap.Logger) Middleware {
+	return func(next users.Users) users.Users {
+		return &errorLoggingMiddleware{
+			next:   next,
+			logger: logger,
+		}
+	}
+}
+
+func (m *errorLoggingMiddleware) Create(ctx context.Context, create *users.User) (user *users.User, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Create(ctx, create)
+}
+
+func (m *errorLoggingMiddleware) Delete(ctx context.Context, userId string) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Delete(ctx, userId)
+}
+
+func (m *errorLoggingMiddleware) Find(ctx context.Context, filter *users.Filter, options *options.FindOptions) (users []*users.User, total int, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Find(ctx, filter, options)
+}
+
+func (m *errorLoggingMiddleware) Get(ctx context.Context, userId string) (user *users.User, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Get(ctx, userId)
+}
+
+func (m *errorLoggingMiddleware) GetByIdentity(ctx context.Context, identity string) (user *users.User, err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.GetByIdentity(ctx, identity)
+}
+
+func (m *errorLoggingMiddleware) Update(ctx context.Context, update *users.User) (err error) {
+	logger := m.logger
+	defer func() {
+		if err != nil {
+			logger.Warn("response error", zap.Error(err))
+		}
+	}()
+	return m.next.Update(ctx, update)
+}
diff --git a/pkg/users/middleware/logging_middleware.go b/pkg/users/middleware/logging_middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..a4bfb5fc53d8bc64a539eded9da47b2b6fa209c3
--- /dev/null
+++ b/pkg/users/middleware/logging_middleware.go
@@ -0,0 +1,251 @@
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/access_log
+// gowrap: http://github.com/hexdigest/gowrap
+
+package service
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/access_log -o logging_middleware.go -l ""
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"git.perx.ru/perxis/perxis-go/pkg/auth"
+	"git.perx.ru/perxis/perxis-go/pkg/options"
+	"git.perx.ru/perxis/perxis-go/pkg/users"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+// loggingMiddleware implements users.Users that is instrumented with logging
+type loggingMiddleware struct {
+	logger *zap.Logger
+	next   users.Users
+}
+
+// LoggingMiddleware instruments an implementation of the users.Users with simple logging
+func LoggingMiddleware(logger *zap.Logger) Middleware {
+	return func(next users.Users) users.Users {
+		return &loggingMiddleware{
+			next:   next,
+			logger: logger,
+		}
+	}
+}
+
+func (m *loggingMiddleware) Create(ctx context.Context, create *users.User) (user *users.User, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":    ctx,
+		"create": create} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Create.Request", fields...)
+
+	user, err = m.next.Create(ctx, create)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	}
+
+	for k, v := range map[string]interface{}{
+		"user": user,
+		"err":  err} {
+		if k == "err" {
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Create.Response", fields...)
+
+	return user, err
+}
+
+func (m *loggingMiddleware) Delete(ctx context.Context, userId string) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":    ctx,
+		"userId": userId} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Delete.Request", fields...)
+
+	err = m.next.Delete(ctx, userId)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Delete.Response", fields...)
+
+	return err
+}
+
+func (m *loggingMiddleware) Find(ctx context.Context, filter *users.Filter, options *options.FindOptions) (users []*users.User, total int, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":     ctx,
+		"filter":  filter,
+		"options": options} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Find.Request", fields...)
+
+	users, total, err = m.next.Find(ctx, filter, options)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	}
+
+	for k, v := range map[string]interface{}{
+		"users": users,
+		"total": total,
+		"err":   err} {
+		if k == "err" {
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Find.Response", fields...)
+
+	return users, total, err
+}
+
+func (m *loggingMiddleware) Get(ctx context.Context, userId string) (user *users.User, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":    ctx,
+		"userId": userId} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Get.Request", fields...)
+
+	user, err = m.next.Get(ctx, userId)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	}
+
+	for k, v := range map[string]interface{}{
+		"user": user,
+		"err":  err} {
+		if k == "err" {
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Get.Response", fields...)
+
+	return user, err
+}
+
+func (m *loggingMiddleware) GetByIdentity(ctx context.Context, identity string) (user *users.User, err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":      ctx,
+		"identity": identity} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("GetByIdentity.Request", fields...)
+
+	user, err = m.next.GetByIdentity(ctx, identity)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	}
+
+	for k, v := range map[string]interface{}{
+		"user": user,
+		"err":  err} {
+		if k == "err" {
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("GetByIdentity.Response", fields...)
+
+	return user, err
+}
+
+func (m *loggingMiddleware) Update(ctx context.Context, update *users.User) (err error) {
+	begin := time.Now()
+	var fields []zapcore.Field
+	for k, v := range map[string]interface{}{
+		"ctx":    ctx,
+		"update": update} {
+		if k == "ctx" {
+			fields = append(fields, zap.String("principal", fmt.Sprint(auth.GetPrincipal(ctx))))
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Update.Request", fields...)
+
+	err = m.next.Update(ctx, update)
+
+	fields = []zapcore.Field{
+		zap.Duration("time", time.Since(begin)),
+		zap.Error(err),
+	}
+
+	for k, v := range map[string]interface{}{
+		"err": err} {
+		if k == "err" {
+			continue
+		}
+		fields = append(fields, zap.Reflect(k, v))
+	}
+
+	m.logger.Debug("Update.Response", fields...)
+
+	return err
+}
diff --git a/pkg/users/middleware/middleware.go b/pkg/users/middleware/middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..2888f263ca2083bdea91e3c3e62cde40f85e974f
--- /dev/null
+++ b/pkg/users/middleware/middleware.go
@@ -0,0 +1,28 @@
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/middleware
+// gowrap: http://github.com/hexdigest/gowrap
+
+package service
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/middleware -o middleware.go -l ""
+
+import (
+	"git.perx.ru/perxis/perxis-go/pkg/users"
+	"go.uber.org/zap"
+)
+
+type Middleware func(users.Users) users.Users
+
+func WithLog(s users.Users, logger *zap.Logger, log_access bool) users.Users {
+	if logger == nil {
+		logger = zap.NewNop()
+	}
+
+	logger = logger.Named("Users")
+	s = ErrorLoggingMiddleware(logger)(s)
+	if log_access {
+		s = LoggingMiddleware(logger)(s)
+	}
+	s = RecoveringMiddleware(logger)(s)
+	return s
+}
diff --git a/pkg/users/middleware/recovering_middleware.go b/pkg/users/middleware/recovering_middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..57c401b12c0b56e9f40109570c6efe59bac8d902
--- /dev/null
+++ b/pkg/users/middleware/recovering_middleware.go
@@ -0,0 +1,104 @@
+// Code generated by gowrap. DO NOT EDIT.
+// template: ../../../assets/templates/middleware/recovery
+// gowrap: http://github.com/hexdigest/gowrap
+
+package service
+
+//go:generate gowrap gen -p git.perx.ru/perxis/perxis-go/pkg/users -i Users -t ../../../assets/templates/middleware/recovery -o recovering_middleware.go -l ""
+
+import (
+	"context"
+	"fmt"
+
+	"git.perx.ru/perxis/perxis-go/pkg/options"
+	"git.perx.ru/perxis/perxis-go/pkg/users"
+	"go.uber.org/zap"
+)
+
+// recoveringMiddleware implements users.Users that is instrumented with logging
+type recoveringMiddleware struct {
+	logger *zap.Logger
+	next   users.Users
+}
+
+// RecoveringMiddleware instruments an implementation of the users.Users with simple logging
+func RecoveringMiddleware(logger *zap.Logger) Middleware {
+	return func(next users.Users) users.Users {
+		return &recoveringMiddleware{
+			next:   next,
+			logger: logger,
+		}
+	}
+}
+
+func (m *recoveringMiddleware) Create(ctx context.Context, create *users.User) (user *users.User, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Create(ctx, create)
+}
+
+func (m *recoveringMiddleware) Delete(ctx context.Context, userId string) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Delete(ctx, userId)
+}
+
+func (m *recoveringMiddleware) Find(ctx context.Context, filter *users.Filter, options *options.FindOptions) (users []*users.User, total int, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Find(ctx, filter, options)
+}
+
+func (m *recoveringMiddleware) Get(ctx context.Context, userId string) (user *users.User, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Get(ctx, userId)
+}
+
+func (m *recoveringMiddleware) GetByIdentity(ctx context.Context, identity string) (user *users.User, err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.GetByIdentity(ctx, identity)
+}
+
+func (m *recoveringMiddleware) Update(ctx context.Context, update *users.User) (err error) {
+	logger := m.logger
+	defer func() {
+		if r := recover(); r != nil {
+			logger.Error("panic", zap.Error(fmt.Errorf("%v", r)))
+			err = fmt.Errorf("%v", r)
+		}
+	}()
+
+	return m.next.Update(ctx, update)
+}