codeword/vendor/penahub.gitlab.yandexcloud.net/external/trashlog.git/sink/sink.go
2024-08-27 22:09:10 +03:00

151 lines
3.3 KiB
Go

package sink
import (
"context"
"github.com/themakers/hlog"
"penahub.gitlab.yandexcloud.net/external/trashlog.git/dal/clickhouse"
"penahub.gitlab.yandexcloud.net/external/trashlog.git/model"
trashlogProto "penahub.gitlab.yandexcloud.net/external/trashlog.git/proto/generated"
)
type Sink struct {
logger hlog.Logger
store *clickhouse.DAL
}
type InfoMobileRec struct {
Level string
TS uint64
Message string
Module []string
Stacktrace string
KeyFields map[string]interface{}
CtxFields map[string]interface{}
SvcBuildTime uint64
SvcVersion string
SvcCommit string
SvcFile string
SvcLine uint64
}
func (s *Sink) TgLog(_ context.Context, record *trashlogProto.Record) (*trashlogProto.Dummy, error) {
data := Dto2daoRecord(record)
s.logger.Emit(InfoMobileRec{
Level: data.Level,
TS: data.TS,
Message: data.Message,
Module: data.Module,
Stacktrace: data.Stacktrace,
KeyFields: data.KeyFields,
CtxFields: data.CtxFields,
SvcBuildTime: data.SvcBuildTime,
SvcVersion: data.SvcVersion,
SvcCommit: data.SvcCommit,
SvcFile: data.SvcFile,
SvcLine: data.SvcLine,
})
return &trashlogProto.Dummy{}, nil
}
func New(log hlog.Logger, store *clickhouse.DAL) *Sink {
return &Sink{
logger: log.Module("sink"),
store: store,
}
}
func (s *Sink) GetFields(
_ context.Context,
_ *trashlogProto.Dummy,
) (*trashlogProto.Fields2Add, error) {
var result trashlogProto.Fields2Add
result.Fields = make(map[string]string)
result.Fields = s.store.Schema
return &result, nil
}
func (s *Sink) Modify(
ctx context.Context,
fields *trashlogProto.Fields2Add,
) (*trashlogProto.NotModified, error) {
if err := s.store.AddColumn(ctx, fields.Fields); err != nil {
return &trashlogProto.NotModified{Columns: fields.Fields}, err
}
return &trashlogProto.NotModified{}, nil
}
func (s *Sink) Valve(stream trashlogProto.Trashlog_ValveServer) error {
ctxChan := stream.Context()
dataChan := make(chan *trashlogProto.Record)
go func() {
for {
record, err := stream.Recv()
if err != nil {
return
}
dataChan <- record
}
}()
for {
select {
case <-ctxChan.Done():
if err := stream.SendAndClose(&trashlogProto.Dummy{}); err != nil {
return err
}
return nil
case record := <-dataChan:
s.store.PutRecord(Dto2daoRecord(record))
}
}
}
func Dto2daoRecord(in *trashlogProto.Record) model.Record {
keyFields := map[string]interface{}{}
for key, value := range in.KeyFields {
keyFields[key] = Dto2daoValue(value)
}
ctxFields := map[string]interface{}{}
for key, value := range in.CtxFields {
ctxFields[key] = Dto2daoValue(value)
}
return model.Record{
Level: in.Level,
TS: in.TS,
Message: in.Message,
Module: in.Module,
Stacktrace: in.Stacktrace,
SvcBuildTime: in.SvcFields.BuildTime,
SvcVersion: in.SvcFields.Version,
SvcCommit: in.SvcFields.Commit,
SvcFile: in.SvcFields.File,
SvcLine: in.SvcFields.Line,
KeyFields: keyFields,
CtxFields: ctxFields,
}
}
func Dto2daoValue(in *trashlogProto.Value) interface{} {
switch in.Value.(type) {
case *trashlogProto.Value_Str:
return in.GetStr()
case *trashlogProto.Value_Double:
return in.GetDouble()
case *trashlogProto.Value_Num:
return in.GetNum()
case *trashlogProto.Value_Flag:
return in.GetFlag()
}
return nil
}