Compare commits

...

16 Commits

Author SHA1 Message Date
Владислав Весельский 174f52d948 On error save SQL request parameters to span. 2024-03-14 18:50:31 +03:00
Владислав Весельский 5801184782 Change span attributes for func SaveRow. 2024-03-14 13:46:49 +03:00
Владислав Весельский a84251e20d Use git.bit5.ru/backend/db v1.2.6. 2024-03-13 16:25:42 +03:00
Владислав Весельский afb9845d70 Add logs for SaveRow. 2024-03-13 15:54:10 +03:00
Владислав Весельский 19cbc17f35 Add logs for func saveStruct. 2024-03-13 15:49:29 +03:00
Владислав Весельский 7c9d4c28dc Logs. Add attribute field_amount. 2024-03-13 15:37:56 +03:00
Владислав Весельский 328bac49e0 Add logs for method DataCollection.saveWithoutMask. 2024-03-13 15:33:59 +03:00
Владислав Весельский 5af4d90edb Add logs for method DataCollection.saveByMask. 2024-03-13 15:31:17 +03:00
Владислав Весельский a4e2984934 Add logs for method DataCollection.Save. 2024-03-13 15:24:09 +03:00
Владислав Весельский b61bdcf676 Change logs for SaveRow. Do not use database semconv with Uptrace 2024-03-12 14:55:53 +03:00
Владислав Весельский 85d358da90 Add logs for func SaveMetaCollection 2024-03-12 14:38:54 +03:00
Владислав Весельский eb73f8d63b Add error message for func SaveRow 2024-03-12 13:34:05 +03:00
Владислав Весельский 218e470106 Add error message for func saveStruct 2024-03-12 10:31:53 +03:00
Владислав Весельский b31ca726e2 Add logs for func saveStruct 2024-03-11 13:10:13 +03:00
Владислав Весельский 9dfbdbe878 Use git.bit5.ru/backend/db v1.2.5 2024-03-07 15:21:28 +03:00
Владислав Весельский aba3ad40a6 Logs. Add code to change span status. 2024-03-05 13:03:57 +03:00
4 changed files with 136 additions and 23 deletions

View File

@ -8,6 +8,7 @@ import (
"git.bit5.ru/backend/meta" "git.bit5.ru/backend/meta"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
) )
type DataCollection struct { type DataCollection struct {
@ -41,7 +42,10 @@ func (coll *DataCollection) Save(ctx context.Context) error {
fields := coll.GetDbFields() fields := coll.GetDbFields()
countFields := len(fields) countFields := len(fields)
if countFields == 0 { if countFields == 0 {
return errors.New("Fields list is empty") err := errors.New("Fields list is empty")
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
countRows := len(coll.Items) countRows := len(coll.Items)
@ -60,10 +64,21 @@ func (coll *DataCollection) Save(ctx context.Context) error {
// NOTE: performance fix: if none of rows have mask we can save all data by one sql query // NOTE: performance fix: if none of rows have mask we can save all data by one sql query
if allDataWithoutMask { if allDataWithoutMask {
return coll.saveWithoutMask(ctx) if err := coll.saveWithoutMask(ctx); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
return nil
} }
return coll.saveByMask(ctx) if err := coll.saveByMask(ctx); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}
return nil
} }
func (coll *DataCollection) saveByMask(ctx context.Context) error { func (coll *DataCollection) saveByMask(ctx context.Context) error {
@ -77,7 +92,8 @@ func (coll *DataCollection) saveByMask(ctx context.Context) error {
tableName := coll.GetTableName() tableName := coll.GetTableName()
span.SetAttributes( span.SetAttributes(
attribute.String("db.sql.table", tableName), attribute.String("table", tableName),
attribute.Int("field_amount", countFields),
) )
for _, item := range coll.Items { for _, item := range coll.Items {
@ -110,7 +126,10 @@ func (coll *DataCollection) saveByMask(ctx context.Context) error {
log_len = 200 log_len = 200
} }
return errors.Errorf("%s (%s)", err.Error(), sqlSmt[0:log_len]) resultErr := errors.Errorf("%s (%s)", err.Error(), sqlSmt[0:log_len])
span.RecordError(resultErr)
span.SetStatus(codes.Error, resultErr.Error())
return resultErr
} }
} }
return nil return nil
@ -128,7 +147,7 @@ func (coll *DataCollection) saveWithoutMask(ctx context.Context) error {
countRows := len(coll.Items) countRows := len(coll.Items)
span.SetAttributes( span.SetAttributes(
attribute.String("db.sql.table", tableName), attribute.String("table", tableName),
attribute.Int("field_amount", countFields), attribute.Int("field_amount", countFields),
attribute.Int("item_amount", countRows), attribute.Int("item_amount", countRows),
) )
@ -143,7 +162,10 @@ func (coll *DataCollection) saveWithoutMask(ctx context.Context) error {
if ownerValue == uint32(0) { if ownerValue == uint32(0) {
rows[start+coll.ownerFieldIndex] = coll.OwnerId rows[start+coll.ownerFieldIndex] = coll.OwnerId
} else if ownerValue != coll.OwnerId { } else if ownerValue != coll.OwnerId {
return errors.Errorf("Wrong owner_id in %s value %d (!= %d)", tableName, ownerValue, coll.OwnerId) err := errors.Errorf("Wrong owner_id in %s value %d (!= %d)", tableName, ownerValue, coll.OwnerId)
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
offset++ offset++
} }
@ -151,7 +173,10 @@ func (coll *DataCollection) saveWithoutMask(ctx context.Context) error {
sqlSmt := createInsertSQLForFields(ctx, tableName, fields, countRows) sqlSmt := createInsertSQLForFields(ctx, tableName, fields, countRows)
_, err := coll.Db.UpdateBySQL(sqlSmt, rows...).Exec() _, err := coll.Db.UpdateBySQL(sqlSmt, rows...).Exec()
if err != nil { if err != nil {
return errors.Errorf("error: %s, sql: %s", err.Error(), sqlSmt) resultErr := errors.Errorf("error: %s, sql: %s", err.Error(), sqlSmt)
span.RecordError(resultErr)
span.SetStatus(codes.Error, resultErr.Error())
return resultErr
} }
return nil return nil
} }

3
go.mod
View File

@ -3,10 +3,11 @@ module git.bit5.ru/backend/dbmeta
go 1.13 go 1.13
require ( require (
git.bit5.ru/backend/db v1.2.4 git.bit5.ru/backend/db v1.2.6
git.bit5.ru/backend/errors v1.0.0 git.bit5.ru/backend/errors v1.0.0
git.bit5.ru/backend/meta v1.0.0 git.bit5.ru/backend/meta v1.0.0
github.com/go-logr/stdr v1.2.2 github.com/go-logr/stdr v1.2.2
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
go.opentelemetry.io/otel v1.11.1 go.opentelemetry.io/otel v1.11.1
go.opentelemetry.io/otel/trace v1.11.1
) )

8
go.sum
View File

@ -1,7 +1,7 @@
git.bit5.ru/backend/db v1.2.4 h1:17ej2UgW6tmIoQ7M8WyjRIe59xx1BqP9lvlT7mSXEIc= git.bit5.ru/backend/db v1.2.6 h1:ANfRTQ+C4BaMKbG+7onjET7qCcsFwq71dbolt0Po7Y4=
git.bit5.ru/backend/db v1.2.4/go.mod h1:LOPz0QYl7Ca3k8VkvQW39xrcu1s1Drcnbl2unUczAYw= git.bit5.ru/backend/db v1.2.6/go.mod h1:+1VkFgSf3zkGlHmG3gw5HyWBoucZDQ+bixQ6rpO6AqU=
git.bit5.ru/backend/dbr v1.3.0 h1:1mpzmSuZ5Mt4wL7cqjtuWOADq9kWdFY3Iet9mctC8pw= git.bit5.ru/backend/dbr v1.3.1 h1:O3fy+aztnNVzto/nMcydd9BVahAJTXPE8VuGY3dC1NY=
git.bit5.ru/backend/dbr v1.3.0/go.mod h1:oVVFv6hIzFkO4Wy0KcS4CYqkBjW1kFHYNLcmKmDlPow= git.bit5.ru/backend/dbr v1.3.1/go.mod h1:oVVFv6hIzFkO4Wy0KcS4CYqkBjW1kFHYNLcmKmDlPow=
git.bit5.ru/backend/errors v1.0.0 h1:WWJ0sly44q1HQjN01X75ZAGKZwwY5Ml+XVDXMjCkToA= git.bit5.ru/backend/errors v1.0.0 h1:WWJ0sly44q1HQjN01X75ZAGKZwwY5Ml+XVDXMjCkToA=
git.bit5.ru/backend/errors v1.0.0/go.mod h1:75faRwsnpM0Se00/Bh7fysWQXV8oMjNJFQ6f7+r9k3Y= git.bit5.ru/backend/errors v1.0.0/go.mod h1:75faRwsnpM0Se00/Bh7fysWQXV8oMjNJFQ6f7+r9k3Y=
git.bit5.ru/backend/meta v1.0.0 h1:1mZgEoOSA/P+IrnKkoiULpFUFX3JxyxGU6OXVn7j2kY= git.bit5.ru/backend/meta v1.0.0 h1:1mZgEoOSA/P+IrnKkoiULpFUFX3JxyxGU6OXVn7j2kY=

107
save.go
View File

@ -12,6 +12,7 @@ import (
"go.opentelemetry.io/otel" "go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.12.0" semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@ -49,6 +50,8 @@ func SaveRow(ctx context.Context, db *db.DBC, dataItem meta.IMetaStruct) error {
info, err := makeDataRowInfo(dataItem) info, err := makeDataRowInfo(dataItem)
if err != nil { if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err return err
} }
@ -77,15 +80,20 @@ func SaveRow(ctx context.Context, db *db.DBC, dataItem meta.IMetaStruct) error {
} }
if len(fields) == 0 { if len(fields) == 0 {
return errors.New("Fields list is empty") err := errors.New("Fields list is empty")
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
tableName := info.tableName tableName := info.tableName
sqlSmt := createInsertSQLForFields(ctx, tableName, fields, 1 /*one_row*/) sqlSmt := createInsertSQLForFields(ctx, tableName, fields, 1 /*one_row*/)
span.SetAttributes( span.SetAttributes(
semconv.DBSystemKey.String("mysql"),
semconv.DBSQLTableKey.String(tableName), semconv.DBSQLTableKey.String(tableName),
semconv.DBStatementKey.String(sqlSmt), semconv.DBStatementKey.String(sqlSmt),
semconv.DBOperationKey.String("INSERT"),
) )
updateBuilder := db.UpdateBySQL(sqlSmt, params...) updateBuilder := db.UpdateBySQL(sqlSmt, params...)
@ -95,7 +103,23 @@ func SaveRow(ctx context.Context, db *db.DBC, dataItem meta.IMetaStruct) error {
if len(sqlSmt) > 200 { if len(sqlSmt) > 200 {
sqlSmt = sqlSmt[0:200] sqlSmt = sqlSmt[0:200]
} }
return errors.Errorf("%s (%s)", err.Error(), sqlSmt)
span.SetAttributes(
attribute.Int("sql_param_amount", len(params)),
)
// Convert SQL request parameters to slice of strings.
paramStrs := convertInterfacesToStrings(ctx, params)
if len(paramStrs) > 0 {
span.SetAttributes(
attribute.StringSlice("sql_params", paramStrs),
)
}
resultErr := errors.Errorf("Can not execute SaveRow. Got error from updateBuilder.ExecContext. %s (%s)", err.Error(), sqlSmt)
span.RecordError(resultErr)
span.SetStatus(codes.Error, resultErr.Error())
return resultErr
} }
insertId, _ := res.LastInsertId() insertId, _ := res.LastInsertId()
@ -106,6 +130,20 @@ func SaveRow(ctx context.Context, db *db.DBC, dataItem meta.IMetaStruct) error {
return nil return nil
} }
func convertInterfacesToStrings(ctx context.Context, items []interface{}) []string {
itemAmount := len(items)
if itemAmount == 0 {
return nil
}
strs := make([]string, itemAmount)
for i, item := range items {
strs[i] = fmt.Sprint(item)
}
return strs
}
func SaveMetaRootStruct( func SaveMetaRootStruct(
ctx context.Context, ctx context.Context,
db *db.DBC, db *db.DBC,
@ -169,11 +207,15 @@ func SaveMetaRootStruct(
switch tfield.Kind() { switch tfield.Kind() {
case reflect.Slice: case reflect.Slice:
if err := SaveMetaCollection(ctx, db, dataItem.Field(i), ownerId, removedIds, deltaSave); err != nil { if err := SaveMetaCollection(ctx, db, dataItem.Field(i), ownerId, removedIds, deltaSave); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return errors.WithMessagef(err, "Can not execute SaveMetaRootStruct. Got error from SaveMetaCollection. ownerId: %d.", ownerId) return errors.WithMessagef(err, "Can not execute SaveMetaRootStruct. Got error from SaveMetaCollection. ownerId: %d.", ownerId)
} }
break break
case reflect.Struct: case reflect.Struct:
if err := saveStruct(ctx, db, dataItem.Field(i), ownerId); err != nil { if err := saveStruct(ctx, db, dataItem.Field(i), ownerId); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return errors.WithMessagef(err, "Can not execute SaveMetaRootStruct. Got error from saveStruct. ownerId: %d.", ownerId) return errors.WithMessagef(err, "Can not execute SaveMetaRootStruct. Got error from saveStruct. ownerId: %d.", ownerId)
} }
break break
@ -190,7 +232,12 @@ func SaveMetaRootStruct(
return nil return nil
} }
func saveStruct(ctx context.Context, db *db.DBC, dataItem reflect.Value, ownerId uint32) error { func saveStruct(
ctx context.Context,
db *db.DBC,
dataItem reflect.Value,
ownerId uint32,
) error {
ctx, span := tracer.Start(ctx, "saveStruct") ctx, span := tracer.Start(ctx, "saveStruct")
defer span.End() defer span.End()
@ -206,14 +253,20 @@ func saveStruct(ctx context.Context, db *db.DBC, dataItem reflect.Value, ownerId
row, _ = dataItem.Addr().Interface().(meta.IMetaStruct) row, _ = dataItem.Addr().Interface().(meta.IMetaStruct)
} }
if row == nil { if row == nil {
return errors.Errorf("Couldn't convert to IMetaStruct: %s", mType.Name()) err := errors.Errorf("Couldn't convert to IMetaStruct: %s", mType.Name())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
props := *row.CLASS_PROPS() props := *row.CLASS_PROPS()
if ownerField, ok := props["owner"]; ok { if ownerField, ok := props["owner"]; ok {
field := dataItem.FieldByName(strings.Title(ownerField)) field := dataItem.FieldByName(strings.Title(ownerField))
if !field.IsValid() { if !field.IsValid() {
return errors.Errorf("Owner field \"%s\" is not found in struct \"%s\"", ownerField, mType.Name()) err := errors.Errorf("Owner field \"%s\" is not found in struct \"%s\"", ownerField, mType.Name())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
// enforcing ownerId // enforcing ownerId
@ -223,17 +276,34 @@ func saveStruct(ctx context.Context, db *db.DBC, dataItem reflect.Value, ownerId
} }
return SaveRow(ctx, db, row) if err := SaveRow(ctx, db, row); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return errors.WithMessagef(err, "Can not execute saveStruct. Got error from SaveRow. ownerId: %d.", ownerId)
} }
func SaveMetaCollection(ctx context.Context, db *db.DBC, slice reflect.Value, ownerId uint32, removedIds meta.IRemovedIds, deltaSave bool) error { return nil
}
func SaveMetaCollection(
ctx context.Context,
db *db.DBC,
slice reflect.Value,
ownerId uint32,
removedIds meta.IRemovedIds,
deltaSave bool,
) error {
ctx, span := tracer.Start(ctx, "SaveMetaCollection") ctx, span := tracer.Start(ctx, "SaveMetaCollection")
defer span.End() defer span.End()
if slice.Type().Kind() != reflect.Slice { if slice.Type().Kind() != reflect.Slice {
return errors.Errorf("It isn't slice: %s", slice.Type().Kind()) err := errors.Errorf("It isn't slice: %s", slice.Type().Kind())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
sliceItem := reflect.New(slice.Type().Elem().Elem()) sliceItem := reflect.New(slice.Type().Elem().Elem())
if sliceItem.Type().Kind() != reflect.Ptr { if sliceItem.Type().Kind() != reflect.Ptr {
sliceItem = sliceItem.Addr() sliceItem = sliceItem.Addr()
@ -245,29 +315,42 @@ func SaveMetaCollection(ctx context.Context, db *db.DBC, slice reflect.Value, ow
} }
if row == nil { if row == nil {
return errors.Errorf("Couldn't convert to IMetaStruct: %s", sliceItem.Kind()) err := errors.Errorf("Couldn't convert to IMetaStruct: %s", sliceItem.Kind())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
item, _ := sliceItem.Interface().(meta.IMetaDataItem) item, _ := sliceItem.Interface().(meta.IMetaDataItem)
if item == nil { if item == nil {
return errors.Errorf("Couldn't convert to IMetaDataItem: %s", slice.Type()) err := errors.Errorf("Couldn't convert to IMetaDataItem: %s", slice.Type())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
} }
if !deltaSave { if !deltaSave {
cond := fmt.Sprintf("`%s`=%d ", item.GetOwnerFieldName(), ownerId) cond := fmt.Sprintf("`%s`=%d ", item.GetOwnerFieldName(), ownerId)
_, err := db.DeleteFrom(item.GetDbTableName()).Where(cond).Exec() _, err := db.DeleteFrom(item.GetDbTableName()).Where(cond).Exec()
if err != nil { if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err return err
} }
} }
collection, err := NewDataCollection(db, ownerId, "", item) collection, err := NewDataCollection(db, ownerId, "", item)
if err != nil { if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err return err
} }
for ind := 0; ind < slice.Len(); ind++ { for ind := 0; ind < slice.Len(); ind++ {
ind_item, err := convertToIdataItem(slice.Index(ind)) ind_item, err := convertToIdataItem(slice.Index(ind))
if err != nil { if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err return err
} }
// NOTE: we don't check here for error on purpose, here it's considered to be OK // NOTE: we don't check here for error on purpose, here it's considered to be OK
@ -275,6 +358,8 @@ func SaveMetaCollection(ctx context.Context, db *db.DBC, slice reflect.Value, ow
} }
if err := collection.Save(ctx); err != nil { if err := collection.Save(ctx); err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err return err
} }
@ -284,6 +369,8 @@ func SaveMetaCollection(ctx context.Context, db *db.DBC, slice reflect.Value, ow
if removedIds.HasList(classId) { if removedIds.HasList(classId) {
err := deleteByIds(db, ownerId, item, removedIds.GetList(classId)) err := deleteByIds(db, ownerId, item, removedIds.GetList(classId))
if err != nil { if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err return err
} }
} }