diff --git a/pkg/log/client.go b/pkg/log/client.go
index 559b7cab5ebd5454c7c5296513cffe53a8b4a962..598139b3b5212f5d2512977039427574f9249d98 100644
--- a/pkg/log/client.go
+++ b/pkg/log/client.go
@@ -2,7 +2,6 @@ package log
 
 import (
 	"context"
-	"fmt"
 	"io"
 
 	"git.perx.ru/perxis/perxis-go/pkg/errors"
@@ -34,6 +33,8 @@ func (c *Client) Log(ctx context.Context, entries <-chan *Entry) error {
 	for e := range entries {
 		err := stream.Send(&pb.LogRequest{Entry: EntryToPB(e)})
 		if err != nil {
+			// нет смысла проверять на ошибку
+			_ = stream.CloseSend()
 			return errors.Wrap(err, "send request to stream")
 		}
 	}
@@ -41,7 +42,6 @@ func (c *Client) Log(ctx context.Context, entries <-chan *Entry) error {
 	response, err := stream.CloseAndRecv()
 	if err != nil {
 		if errors.Is(err, io.EOF) {
-			fmt.Println("EOF, OK")
 			return nil
 		}
 		return err
diff --git a/pkg/log/mocks/Service.go b/pkg/log/mocks/Service.go
new file mode 100644
index 0000000000000000000000000000000000000000..efc07061bbba95e24757b1346ae4ff81cbca8a90
--- /dev/null
+++ b/pkg/log/mocks/Service.go
@@ -0,0 +1,240 @@
+// Code generated by mockery v2.40.1. DO NOT EDIT.
+
+package mocks
+
+import (
+	context "context"
+
+	log "git.perx.ru/perxis/perxis-go/pkg/log"
+	mock "github.com/stretchr/testify/mock"
+
+	options "git.perx.ru/perxis/perxis-go/pkg/options"
+)
+
+// Service is an autogenerated mock type for the Service type
+type Service struct {
+	mock.Mock
+}
+
+type Service_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *Service) EXPECT() *Service_Expecter {
+	return &Service_Expecter{mock: &_m.Mock}
+}
+
+// Delete provides a mock function with given fields: ctx, filter
+func (_m *Service) Delete(ctx context.Context, filter *log.Filter) error {
+	ret := _m.Called(ctx, filter)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Delete")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Filter) error); ok {
+		r0 = rf(ctx, filter)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Service_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
+type Service_Delete_Call struct {
+	*mock.Call
+}
+
+// Delete is a helper method to define mock.On call
+//   - ctx context.Context
+//   - filter *log.Filter
+func (_e *Service_Expecter) Delete(ctx interface{}, filter interface{}) *Service_Delete_Call {
+	return &Service_Delete_Call{Call: _e.mock.On("Delete", ctx, filter)}
+}
+
+func (_c *Service_Delete_Call) Run(run func(ctx context.Context, filter *log.Filter)) *Service_Delete_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*log.Filter))
+	})
+	return _c
+}
+
+func (_c *Service_Delete_Call) Return(_a0 error) *Service_Delete_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Service_Delete_Call) RunAndReturn(run func(context.Context, *log.Filter) error) *Service_Delete_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Find provides a mock function with given fields: ctx, filter, _a2
+func (_m *Service) Find(ctx context.Context, filter *log.Filter, _a2 *options.FindOptions) (*log.FindResult, error) {
+	ret := _m.Called(ctx, filter, _a2)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Find")
+	}
+
+	var r0 *log.FindResult
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Filter, *options.FindOptions) (*log.FindResult, error)); ok {
+		return rf(ctx, filter, _a2)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Filter, *options.FindOptions) *log.FindResult); ok {
+		r0 = rf(ctx, filter, _a2)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*log.FindResult)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, *log.Filter, *options.FindOptions) error); ok {
+		r1 = rf(ctx, filter, _a2)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// Service_Find_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Find'
+type Service_Find_Call struct {
+	*mock.Call
+}
+
+// Find is a helper method to define mock.On call
+//   - ctx context.Context
+//   - filter *log.Filter
+//   - _a2 *options.FindOptions
+func (_e *Service_Expecter) Find(ctx interface{}, filter interface{}, _a2 interface{}) *Service_Find_Call {
+	return &Service_Find_Call{Call: _e.mock.On("Find", ctx, filter, _a2)}
+}
+
+func (_c *Service_Find_Call) Run(run func(ctx context.Context, filter *log.Filter, _a2 *options.FindOptions)) *Service_Find_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*log.Filter), args[2].(*options.FindOptions))
+	})
+	return _c
+}
+
+func (_c *Service_Find_Call) Return(_a0 *log.FindResult, _a1 error) *Service_Find_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *Service_Find_Call) RunAndReturn(run func(context.Context, *log.Filter, *options.FindOptions) (*log.FindResult, error)) *Service_Find_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Log provides a mock function with given fields: ctx, entries
+func (_m *Service) Log(ctx context.Context, entries <-chan *log.Entry) error {
+	ret := _m.Called(ctx, entries)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Log")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, <-chan *log.Entry) error); ok {
+		r0 = rf(ctx, entries)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Service_Log_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Log'
+type Service_Log_Call struct {
+	*mock.Call
+}
+
+// Log is a helper method to define mock.On call
+//   - ctx context.Context
+//   - entries <-chan *log.Entry
+func (_e *Service_Expecter) Log(ctx interface{}, entries interface{}) *Service_Log_Call {
+	return &Service_Log_Call{Call: _e.mock.On("Log", ctx, entries)}
+}
+
+func (_c *Service_Log_Call) Run(run func(ctx context.Context, entries <-chan *log.Entry)) *Service_Log_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(<-chan *log.Entry))
+	})
+	return _c
+}
+
+func (_c *Service_Log_Call) Return(_a0 error) *Service_Log_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Service_Log_Call) RunAndReturn(run func(context.Context, <-chan *log.Entry) error) *Service_Log_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// LogEntry provides a mock function with given fields: ctx, entry
+func (_m *Service) LogEntry(ctx context.Context, entry *log.Entry) error {
+	ret := _m.Called(ctx, entry)
+
+	if len(ret) == 0 {
+		panic("no return value specified for LogEntry")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Entry) error); ok {
+		r0 = rf(ctx, entry)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Service_LogEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LogEntry'
+type Service_LogEntry_Call struct {
+	*mock.Call
+}
+
+// LogEntry is a helper method to define mock.On call
+//   - ctx context.Context
+//   - entry *log.Entry
+func (_e *Service_Expecter) LogEntry(ctx interface{}, entry interface{}) *Service_LogEntry_Call {
+	return &Service_LogEntry_Call{Call: _e.mock.On("LogEntry", ctx, entry)}
+}
+
+func (_c *Service_LogEntry_Call) Run(run func(ctx context.Context, entry *log.Entry)) *Service_LogEntry_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*log.Entry))
+	})
+	return _c
+}
+
+func (_c *Service_LogEntry_Call) Return(_a0 error) *Service_LogEntry_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Service_LogEntry_Call) RunAndReturn(run func(context.Context, *log.Entry) error) *Service_LogEntry_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// NewService creates a new instance of Service. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewService(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *Service {
+	mock := &Service{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/pkg/log/mocks/Storage.go b/pkg/log/mocks/Storage.go
new file mode 100644
index 0000000000000000000000000000000000000000..07646ee70c428b5fdf08a92d04f082fe5dda5a12
--- /dev/null
+++ b/pkg/log/mocks/Storage.go
@@ -0,0 +1,292 @@
+// Code generated by mockery v2.40.1. DO NOT EDIT.
+
+package mocks
+
+import (
+	context "context"
+
+	log "git.perx.ru/perxis/perxis-go/pkg/log"
+	mock "github.com/stretchr/testify/mock"
+
+	options "git.perx.ru/perxis/perxis-go/pkg/options"
+)
+
+// Storage is an autogenerated mock type for the Storage type
+type Storage struct {
+	mock.Mock
+}
+
+type Storage_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *Storage) EXPECT() *Storage_Expecter {
+	return &Storage_Expecter{mock: &_m.Mock}
+}
+
+// Delete provides a mock function with given fields: ctx, filter
+func (_m *Storage) Delete(ctx context.Context, filter *log.Filter) error {
+	ret := _m.Called(ctx, filter)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Delete")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Filter) error); ok {
+		r0 = rf(ctx, filter)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Storage_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
+type Storage_Delete_Call struct {
+	*mock.Call
+}
+
+// Delete is a helper method to define mock.On call
+//   - ctx context.Context
+//   - filter *log.Filter
+func (_e *Storage_Expecter) Delete(ctx interface{}, filter interface{}) *Storage_Delete_Call {
+	return &Storage_Delete_Call{Call: _e.mock.On("Delete", ctx, filter)}
+}
+
+func (_c *Storage_Delete_Call) Run(run func(ctx context.Context, filter *log.Filter)) *Storage_Delete_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*log.Filter))
+	})
+	return _c
+}
+
+func (_c *Storage_Delete_Call) Return(_a0 error) *Storage_Delete_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Storage_Delete_Call) RunAndReturn(run func(context.Context, *log.Filter) error) *Storage_Delete_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Find provides a mock function with given fields: ctx, filter, _a2
+func (_m *Storage) Find(ctx context.Context, filter *log.Filter, _a2 *options.FindOptions) ([]*log.Entry, int, error) {
+	ret := _m.Called(ctx, filter, _a2)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Find")
+	}
+
+	var r0 []*log.Entry
+	var r1 int
+	var r2 error
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Filter, *options.FindOptions) ([]*log.Entry, int, error)); ok {
+		return rf(ctx, filter, _a2)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *log.Filter, *options.FindOptions) []*log.Entry); ok {
+		r0 = rf(ctx, filter, _a2)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]*log.Entry)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, *log.Filter, *options.FindOptions) int); ok {
+		r1 = rf(ctx, filter, _a2)
+	} else {
+		r1 = ret.Get(1).(int)
+	}
+
+	if rf, ok := ret.Get(2).(func(context.Context, *log.Filter, *options.FindOptions) error); ok {
+		r2 = rf(ctx, filter, _a2)
+	} else {
+		r2 = ret.Error(2)
+	}
+
+	return r0, r1, r2
+}
+
+// Storage_Find_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Find'
+type Storage_Find_Call struct {
+	*mock.Call
+}
+
+// Find is a helper method to define mock.On call
+//   - ctx context.Context
+//   - filter *log.Filter
+//   - _a2 *options.FindOptions
+func (_e *Storage_Expecter) Find(ctx interface{}, filter interface{}, _a2 interface{}) *Storage_Find_Call {
+	return &Storage_Find_Call{Call: _e.mock.On("Find", ctx, filter, _a2)}
+}
+
+func (_c *Storage_Find_Call) Run(run func(ctx context.Context, filter *log.Filter, _a2 *options.FindOptions)) *Storage_Find_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*log.Filter), args[2].(*options.FindOptions))
+	})
+	return _c
+}
+
+func (_c *Storage_Find_Call) Return(_a0 []*log.Entry, _a1 int, _a2 error) *Storage_Find_Call {
+	_c.Call.Return(_a0, _a1, _a2)
+	return _c
+}
+
+func (_c *Storage_Find_Call) RunAndReturn(run func(context.Context, *log.Filter, *options.FindOptions) ([]*log.Entry, int, error)) *Storage_Find_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Init provides a mock function with given fields: ctx
+func (_m *Storage) Init(ctx context.Context) error {
+	ret := _m.Called(ctx)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Init")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+		r0 = rf(ctx)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Storage_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init'
+type Storage_Init_Call struct {
+	*mock.Call
+}
+
+// Init is a helper method to define mock.On call
+//   - ctx context.Context
+func (_e *Storage_Expecter) Init(ctx interface{}) *Storage_Init_Call {
+	return &Storage_Init_Call{Call: _e.mock.On("Init", ctx)}
+}
+
+func (_c *Storage_Init_Call) Run(run func(ctx context.Context)) *Storage_Init_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context))
+	})
+	return _c
+}
+
+func (_c *Storage_Init_Call) Return(_a0 error) *Storage_Init_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Storage_Init_Call) RunAndReturn(run func(context.Context) error) *Storage_Init_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Log provides a mock function with given fields: ctx, entry
+func (_m *Storage) Log(ctx context.Context, entry []*log.Entry) error {
+	ret := _m.Called(ctx, entry)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Log")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, []*log.Entry) error); ok {
+		r0 = rf(ctx, entry)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Storage_Log_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Log'
+type Storage_Log_Call struct {
+	*mock.Call
+}
+
+// Log is a helper method to define mock.On call
+//   - ctx context.Context
+//   - entry []*log.Entry
+func (_e *Storage_Expecter) Log(ctx interface{}, entry interface{}) *Storage_Log_Call {
+	return &Storage_Log_Call{Call: _e.mock.On("Log", ctx, entry)}
+}
+
+func (_c *Storage_Log_Call) Run(run func(ctx context.Context, entry []*log.Entry)) *Storage_Log_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].([]*log.Entry))
+	})
+	return _c
+}
+
+func (_c *Storage_Log_Call) Return(_a0 error) *Storage_Log_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Storage_Log_Call) RunAndReturn(run func(context.Context, []*log.Entry) error) *Storage_Log_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Reset provides a mock function with given fields: ctx
+func (_m *Storage) Reset(ctx context.Context) error {
+	ret := _m.Called(ctx)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Reset")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+		r0 = rf(ctx)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// Storage_Reset_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Reset'
+type Storage_Reset_Call struct {
+	*mock.Call
+}
+
+// Reset is a helper method to define mock.On call
+//   - ctx context.Context
+func (_e *Storage_Expecter) Reset(ctx interface{}) *Storage_Reset_Call {
+	return &Storage_Reset_Call{Call: _e.mock.On("Reset", ctx)}
+}
+
+func (_c *Storage_Reset_Call) Run(run func(ctx context.Context)) *Storage_Reset_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context))
+	})
+	return _c
+}
+
+func (_c *Storage_Reset_Call) Return(_a0 error) *Storage_Reset_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *Storage_Reset_Call) RunAndReturn(run func(context.Context) error) *Storage_Reset_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// NewStorage creates a new instance of Storage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewStorage(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *Storage {
+	mock := &Storage{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}