diff --git a/pkg/log/client.go b/pkg/log/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..d7f20570f697345565fe526d571154cb51e845bc
--- /dev/null
+++ b/pkg/log/client.go
@@ -0,0 +1,51 @@
+package log
+
+import (
+	"context"
+
+	"git.perx.ru/perxis/perxis-go/proto/common"
+	"git.perx.ru/perxis/perxis-go/proto/log"
+	"google.golang.org/grpc"
+)
+
+type Client struct {
+	client log.LogServiceClient
+}
+
+func NewClient(conn *grpc.ClientConn) *Client {
+	return &Client{
+		client: log.NewLogServiceClient(conn),
+	}
+}
+
+func (c *Client) Log(ctx context.Context, entries chan<- *Entry) error {
+	return nil
+}
+
+func (c *Client) LogEntry(ctx context.Context, entry *Entry) error {
+	_, err := c.client.LogEntry(ctx, &log.LogRequest{Entry: EntryToPB(entry)})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *Client) Find(ctx context.Context, request *FindRequest) (*FindResult, error) {
+	response, err := c.client.Find(ctx, &log.FindRequest{Filter: &log.Filter{Q: request.Filter.Q}, Options: &common.FindOptions{
+		Sort:     request.Options.Sort,
+		PageNum:  int32(request.Options.PageNum),
+		PageSize: int32(request.Options.PageSize),
+	}}, nil)
+	if err != nil {
+		return nil, err
+	}
+	return FindResultFromPB(response.GetResult()), nil
+}
+
+func (c *Client) Delete(ctx context.Context, filter *Filter) error {
+	_, err := c.client.Delete(ctx, &log.DeleteRequest{Filter: &log.Filter{Q: filter.Q}})
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/pkg/log/log.go b/pkg/log/log.go
index 16d00cbdcc1a6b2edb708a516ea32fe60c611b79..e9f98be0d765cc71bd658db6399fb1a6d85b5d2a 100644
--- a/pkg/log/log.go
+++ b/pkg/log/log.go
@@ -1,6 +1,11 @@
 package log
 
-import "time"
+import (
+	"time"
+
+	"git.perx.ru/perxis/perxis-go/proto/log"
+	"google.golang.org/protobuf/types/known/timestamppb"
+)
 
 const (
 	Info = iota
@@ -30,7 +35,7 @@ func (l Level) String() string {
 }
 
 type Entry struct {
-	ID        string      `json:"ID,omitempty" bson:"ID"`
+	ID        string      `json:"id,omitempty" bson:"id"`
 	Timestamp time.Time   `json:"timestamp" bson:"timestamp"`
 	LogLevel  Level       `json:"logLevel,omitempty" bson:"logLevel"`
 	Message   string      `json:"message,omitempty" bson:"message"`
@@ -42,3 +47,36 @@ type Entry struct {
 	Attr      interface{} `json:"attr,omitempty" bson:"attr"`
 	Tags      []string    `json:"tags,omitempty" bson:"tags"`
 }
+
+func EntryToPB(entry *Entry) *log.LogEntry {
+	logEntry := &log.LogEntry{
+		Id:        entry.ID,
+		Timestamp: timestamppb.New(entry.Timestamp),
+		Level:     log.LogLevel(entry.LogLevel),
+		Message:   entry.Message,
+		Category:  entry.Category,
+		Component: entry.Component,
+		Event:     entry.Event,
+		Object:    entry.Object,
+		Caller:    entry.Caller,
+		Attr:      nil, // todo: как с этим работать?
+		Tags:      entry.Tags,
+	}
+	return logEntry
+}
+
+func EntryFromPB(request *log.LogEntry) *Entry {
+	return &Entry{
+		ID:        request.Id,
+		Timestamp: request.Timestamp.AsTime(),
+		LogLevel:  Level(request.Level),
+		Message:   request.Message,
+		Category:  request.Category,
+		Component: request.Component,
+		Event:     request.Event,
+		Object:    request.Object,
+		Caller:    request.Caller,
+		Attr:      request.Attr, // todo: как с этим работать?
+		Tags:      request.Tags,
+	}
+}
diff --git a/pkg/log/service.go b/pkg/log/service.go
index fbf898393a48821f77940ed3c8455e9ba43082e8..1f6da75cd3622a549f42161e794531778d245c8e 100644
--- a/pkg/log/service.go
+++ b/pkg/log/service.go
@@ -3,7 +3,9 @@ package log
 import (
 	"context"
 
+	transportgrpc "git.perx.ru/perxis/perxis-go/pkg/items/transport/grpc"
 	"git.perx.ru/perxis/perxis-go/pkg/options"
+	"git.perx.ru/perxis/perxis-go/proto/log"
 )
 
 type Service interface {
@@ -35,3 +37,42 @@ type FindResult struct {
 	Options *options.FindOptions
 	Total   uint32
 }
+
+func FindResultToPB(result *FindResult) *log.FindResult {
+	findResult := &log.FindResult{}
+	entries := make([]*log.LogEntry, 0)
+	for _, e := range result.Entries {
+		entries = append(entries, EntryToPB(e))
+	}
+	findResult.Entries = entries
+	if result.Filter != nil {
+		findResult.Filter.Q = result.Filter.Q
+	}
+	if result.Options != nil {
+		findResult.Options, _ = transportgrpc.PtrServicesFindOptionsToProto(result.Options)
+	}
+
+	findResult.Total = result.Total
+
+	return findResult
+}
+
+func FindResultFromPB(result *log.FindResult) *FindResult {
+	findResult := &FindResult{}
+	entries := make([]*Entry, 0)
+	for _, e := range result.Entries {
+		entries = append(entries, EntryFromPB(e))
+	}
+	findResult.Entries = entries
+
+	if result.Filter != nil {
+		findResult.Filter.Q = result.Filter.Q
+	}
+	if result.Options != nil {
+		findResult.Options, _ = transportgrpc.ProtoToPtrServicesFindOptions(result.Options)
+	}
+
+	findResult.Total = result.Total
+
+	return findResult
+}
diff --git a/pkg/log/storage.go b/pkg/log/storage.go
index 9606b2956df92d6915b7056751f7d1955868c48a..f3d193c63226185c30adb31c0927ba93d6bb9cca 100644
--- a/pkg/log/storage.go
+++ b/pkg/log/storage.go
@@ -7,4 +7,6 @@ type Storage interface {
 	LogEntry(ctx context.Context, entry *Entry) error
 	Find(ctx context.Context, request *FindRequest) (*FindResult, error)
 	Delete(ctx context.Context, filter *Filter) error
+	Reset(ctx context.Context) error
+	Init(ctx context.Context) error
 }