diff --git a/absences.go b/absences.go index f85f258..89b0143 100644 --- a/absences.go +++ b/absences.go @@ -2,15 +2,30 @@ package themis import ( "context" + "errors" "fmt" "time" "github.com/rs/zerolog/log" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + semconv "go.opentelemetry.io/otel/semconv/v1.24.0" + "go.opentelemetry.io/otel/trace" ) func (s *Store) AddAbsence(ctx context.Context, session time.Time, userId string) error { + ctx, span := tracer.Start(ctx, "add_absence", trace.WithAttributes( + semconv.DBSystemSqlite, + semconv.DBSQLTable("absences"), + semconv.DBOperation("insert"), + attribute.String("user_id", userId), + attribute.String("session_date", session.Format(time.DateOnly)), + )) + defer span.End() + if session.Weekday() != time.Monday { log.Debug().Ctx(ctx).Msg(fmt.Sprintf("%s is not a monday", session)) + span.RecordError(errors.New(fmt.Sprintf("%s is not a monday", session))) return fmt.Errorf("not a monday") } @@ -21,17 +36,23 @@ func (s *Store) AddAbsence(ctx context.Context, session time.Time, userId string tx, err := s.db.Begin() if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to begin transaction") return fmt.Errorf("failed to begin transaction: %w", err) } defer tx.Commit() //nolint:errcheck stmt, err := s.db.PrepareContext(ctx, "INSERT INTO absences (session_date, userid) VALUES (?, ?)") if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to prepare absence query") return fmt.Errorf("failed to prepare absence query: %w", err) } _, err = stmt.ExecContext(ctx, session.Format(time.DateOnly), userId) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to insert absence") return fmt.Errorf("failed to insert absence: %w", err) } @@ -39,20 +60,34 @@ func (s *Store) AddAbsence(ctx context.Context, session time.Time, userId string } func (s *Store) GetAbsentees(ctx context.Context, session time.Time) ([]string, error) { + ctx, span := tracer.Start(ctx, "get_absentees", trace.WithAttributes( + semconv.DBSystemSqlite, + semconv.DBSQLTable("absences"), + semconv.DBOperation("select"), + attribute.String("session_date", session.Format(time.DateOnly)), + )) + defer span.End() + log.Debug().Ctx(ctx).Time("session", session).Msg("getting list of absentees") tx, err := s.db.Begin() if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to begin transaction") return nil, fmt.Errorf("failed to begin transaction: %w", err) } defer tx.Commit() //nolint:errcheck stmt, err := s.db.PrepareContext(ctx, `SELECT userid FROM absences WHERE session_date = ?`) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to prepare query") return nil, fmt.Errorf("failed to prepare query: %w", err) } rows, err := stmt.QueryContext(ctx, session.Format(time.DateOnly)) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to execute query") return nil, fmt.Errorf("failed to execute query: %w", err) } @@ -74,23 +109,38 @@ func (s *Store) GetAbsentees(ctx context.Context, session time.Time) ([]string, type Schedule map[string][]string func (s *Store) GetSchedule(ctx context.Context, from, to time.Time) (Schedule, error) { + ctx, span := tracer.Start(ctx, "add_absence", trace.WithAttributes( + semconv.DBSystemSqlite, + semconv.DBSQLTable("absences"), + semconv.DBOperation("select"), + attribute.String("from", from.Format(time.DateOnly)), + attribute.String("to", to.Format(time.DateOnly)), + )) + defer span.End() + log.Debug().Ctx(ctx).Time("from", from).Time("to", to).Msg("getting next sessions schedule") schedule := make(Schedule) initSchedule(schedule, from, to) tx, err := s.db.Begin() if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to begin transaction") return nil, fmt.Errorf("failed to begin transaction: %w", err) } defer tx.Commit() //nolint:errcheck stmt, err := s.db.PrepareContext(ctx, `SELECT session_date, userid FROM absences WHERE session_date BETWEEN ? AND ? ORDER BY session_date ASC`) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to prepare query") return nil, fmt.Errorf("failed to prepare query: %w", err) } rows, err := stmt.QueryContext(ctx, from.Format(time.DateOnly), to.Format(time.DateOnly)) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to execute query") return nil, fmt.Errorf("failed to execute query: %w", err) } @@ -99,6 +149,8 @@ func (s *Store) GetSchedule(ctx context.Context, from, to time.Time) (Schedule, var user string err = rows.Scan(&date, &user) if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, "failed to scan row") return nil, fmt.Errorf("failed to scan row: %w", err) } diff --git a/cmd/themis-server/main.go b/cmd/themis-server/main.go index 5dbeee9..641fde8 100644 --- a/cmd/themis-server/main.go +++ b/cmd/themis-server/main.go @@ -20,6 +20,7 @@ import ( _ "github.com/mattn/go-sqlite3" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/propagation" @@ -1033,5 +1034,6 @@ func initTracing(db *sql.DB) { sdktrace.WithResource(res), ) + otel.SetTracerProvider(tp) tracer = tp.Tracer("themis") } diff --git a/store.go b/store.go index 6322eb6..2018bbf 100644 --- a/store.go +++ b/store.go @@ -14,11 +14,20 @@ import ( "github.com/golang-migrate/migrate/v4/source/iofs" _ "github.com/mattn/go-sqlite3" "github.com/rs/zerolog/log" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" ) //go:embed migrations/*.sql var migrations embed.FS +var tracer trace.Tracer + +func init() { + tp := otel.GetTracerProvider() + tracer = tp.Tracer("themis") +} + type Store struct { db *sql.DB }