From a368f592340398928f69f44f5529fa7b19d1129b Mon Sep 17 00:00:00 2001 From: SoXX Date: Sun, 11 Aug 2024 22:17:24 +0200 Subject: [PATCH] feat(telemetry): Implement OpenTelemetry tracing and logging in tag management functions --- pkg/database/tag.go | 102 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/pkg/database/tag.go b/pkg/database/tag.go index b2a011d..47bdf1a 100644 --- a/pkg/database/tag.go +++ b/pkg/database/tag.go @@ -5,12 +5,25 @@ import ( "errors" otterError "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/error" "git.anthrove.art/Anthrove/otter-space-sdk/v2/pkg/models" + log "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" "gorm.io/gorm" ) func CreateTag(ctx context.Context, tagName models.TagName, tagType models.TagType) (models.Tag, error) { + ctx, span := tracer.Start(ctx, "CreateTag") + defer span.End() + + span.SetAttributes( + attribute.String("tag_name", string(tagName)), + attribute.String("tag_type", string(tagType)), + ) + + span.AddEvent("Starting tag creation") if client == nil { + logger.WithContext(ctx).Error(otterError.DatabaseIsNotConnected) + span.RecordError(&otterError.Database{Reason: otterError.DatabaseIsNotConnected}) return models.Tag{}, &otterError.Database{Reason: otterError.DatabaseIsNotConnected} } @@ -19,63 +32,142 @@ func CreateTag(ctx context.Context, tagName models.TagName, tagType models.TagTy Type: tagType, } + logger.WithContext(ctx).WithFields(log.Fields{ + "name": tagName, + "type": tagType, + }).Debug("attempting to create tag") + result := client.WithContext(ctx).Create(&tag) if result.Error != nil { if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + + logger.WithContext(ctx).WithFields(log.Fields{ + "name": tagName, + "type": tagType, + }).Error(otterError.DuplicateKey) + + span.RecordError(&otterError.Database{Reason: otterError.DuplicateKey}) + return models.Tag{}, &otterError.Database{Reason: otterError.DuplicateKey} } + + logger.WithContext(ctx).WithFields(log.Fields{ + "name": tagName, + "type": tagType, + }).Error(result.Error) + + span.RecordError(result.Error) + return models.Tag{}, result.Error } + logger.WithContext(ctx).WithFields(log.Fields{ + "name": tagName, + "type": tagType, + }).Debug("tag created") + span.AddEvent("Tag created successfully") return tag, nil } func CreateTagInBatch(ctx context.Context, tags []models.Tag, batchSize int) error { + ctx, span := tracer.Start(ctx, "CreateTagInBatch") + defer span.End() + + span.SetAttributes( + attribute.Int64("batch_size", int64(batchSize)), + attribute.Int64("tag_count", int64(len(tags))), + ) + + span.AddEvent("Starting batch tag creation") + if client == nil { + logger.WithContext(ctx).Error(otterError.DatabaseIsNotConnected) + span.RecordError(&otterError.Database{Reason: otterError.DatabaseIsNotConnected}) return &otterError.Database{Reason: otterError.DatabaseIsNotConnected} } - if tags == nil { - return &otterError.EntityValidationFailed{Reason: otterError.TagListIsEmpty} - } - - if len(tags) == 0 { + if tags == nil || len(tags) == 0 { + logger.WithContext(ctx).Error(otterError.TagListIsEmpty) + span.RecordError(&otterError.EntityValidationFailed{Reason: otterError.TagListIsEmpty}) return &otterError.EntityValidationFailed{Reason: otterError.TagListIsEmpty} } if batchSize == 0 { + logger.WithContext(ctx).Error(otterError.BatchSizeIsEmpty) + span.RecordError(&otterError.EntityValidationFailed{Reason: otterError.BatchSizeIsEmpty}) return &otterError.EntityValidationFailed{Reason: otterError.BatchSizeIsEmpty} } + logger.WithContext(ctx).WithFields(log.Fields{ + "tag_length": len(tags), + }).Debug("attempting to create tags") + result := client.WithContext(ctx).CreateInBatches(&tags, batchSize) if result.Error != nil { if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + logger.WithContext(ctx).WithFields(log.Fields{ + "tag_length": len(tags), + }).Error(otterError.DuplicateKey) + span.RecordError(&otterError.Database{Reason: otterError.DuplicateKey}) return &otterError.Database{Reason: otterError.DuplicateKey} } + logger.WithContext(ctx).WithFields(log.Fields{ + "tag_length": len(tags), + }).Error(result.Error) + span.RecordError(result.Error) return result.Error } + logger.WithContext(ctx).WithFields(log.Fields{ + "tag_length": len(tags), + }).Debug("tags created") + + span.AddEvent("Batch tags created successfully") return nil } func DeleteTag(ctx context.Context, tagName models.TagName) error { + ctx, span := tracer.Start(ctx, "DeleteTag") + defer span.End() + + span.SetAttributes( + attribute.String("tag_name", string(tagName)), + ) + + span.AddEvent("Starting tag deletion") + var tag models.Tag if client == nil { + logger.WithContext(ctx).Error(otterError.DatabaseIsNotConnected) + span.RecordError(&otterError.Database{Reason: otterError.DatabaseIsNotConnected}) return &otterError.Database{Reason: otterError.DatabaseIsNotConnected} } if len(tagName) == 0 { + logger.WithContext(ctx).Error(otterError.TagNameIsEmpty) + span.RecordError(&otterError.EntityValidationFailed{Reason: otterError.TagNameIsEmpty}) return &otterError.EntityValidationFailed{Reason: otterError.TagNameIsEmpty} } + logger.WithContext(ctx).WithFields(log.Fields{ + "tag_name": tagName, + }).Debug("attempting to delete tag") + result := client.WithContext(ctx).Delete(&tag, tagName) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { + span.RecordError(&otterError.Database{Reason: otterError.NoDataFound}) return &otterError.Database{Reason: otterError.NoDataFound} } + span.RecordError(result.Error) return result.Error } + logger.WithContext(ctx).WithFields(log.Fields{ + "tag_name": tagName, + }).Debug("tag deleted") + + span.AddEvent("Tag deleted successfully") return nil }