wip: refactor command logging and tracing

main
William Perron 10 months ago
parent 4c09153756
commit 1646762081
No known key found for this signature in database
GPG Key ID: 80535D1C3032BD6D

@ -20,6 +20,8 @@ import (
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
@ -44,7 +46,7 @@ var (
gen = correlation.NewGenerator(seq) gen = correlation.NewGenerator(seq)
) )
type Handler func(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) type Handler func(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) error
func main() { func main() {
log.Info().Msg("startup.") log.Info().Msg("startup.")
@ -228,7 +230,7 @@ func main() {
}, },
} }
handlers := map[string]Handler{ handlers := map[string]Handler{
"info": func(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) { "info": func(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) error {
uptime, err := themis.Uptime(ctx) uptime, err := themis.Uptime(ctx)
if err != nil { if err != nil {
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
@ -238,10 +240,9 @@ func main() {
}, },
}) })
if err != nil { if err != nil {
log.Error().Ctx(ctx).Err(err).Msg("failed to respond to interaction") return fmt.Errorf("failed to respond to interaction: %w", err)
} }
log.Error().Ctx(ctx).Err(err).Msg("failed to get server uptime") return fmt.Errorf("failed to get server uptime: %w", err)
return
} }
claimCount, uniquePlayers, err := store.CountClaims(ctx) claimCount, uniquePlayers, err := store.CountClaims(ctx)
@ -960,57 +961,50 @@ func serve(address string) error {
} }
func withLogging(name string, h Handler) Handler { func withLogging(name string, h Handler) Handler {
return func(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) { return func(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) error {
ctx, span := tracer.Start(ctx, "discord-command") ctx, span := tracer.Start(ctx, "discord-command")
defer span.End() defer span.End()
start := time.Now() start := time.Now()
logCommandInvocation(ctx, name, s, i) logCommandInvocation(ctx, name, s, i)
h(ctx, s, i) err := h(ctx, s, i)
debugCommandCompletion(ctx, name, time.Since(start), s, i) debugCommandCompletion(ctx, name, time.Since(start), err, s, i)
return nil
} }
} }
func logCommandInvocation(ctx context.Context, name string, s *discordgo.Session, i *discordgo.InteractionCreate) { func logCommandInvocation(ctx context.Context, name string, s *discordgo.Session, i *discordgo.InteractionCreate) {
log.Info(). span := trace.SpanFromContext(ctx)
Ctx(ctx). span.SetAttributes(
Str("userid", i.Member.User.ID). attribute.String("user_id", i.Member.User.ID),
Str("username", i.Member.User.Username). attribute.String("username", i.Member.User.Username),
Str("command", name). attribute.String("command_name", name),
Str("params", func() string { )
p := make([]string, 0, len(i.ApplicationCommandData().Options))
for _, o := range i.ApplicationCommandData().Options {
sb := strings.Builder{}
sb.WriteString(o.Name)
sb.WriteRune('=')
for _, o := range i.ApplicationCommandData().Options {
switch o.Type { switch o.Type {
case discordgo.ApplicationCommandOptionSubCommand, discordgo.ApplicationCommandOptionSubCommandGroup: case discordgo.ApplicationCommandOptionSubCommand, discordgo.ApplicationCommandOptionSubCommandGroup:
panic("unreachable") panic("unreachable")
case discordgo.ApplicationCommandOptionString: case discordgo.ApplicationCommandOptionString:
sb.WriteString(o.StringValue()) span.SetAttributes(attribute.String(fmt.Sprintf("command_option.%s", o.Name), o.StringValue()))
case discordgo.ApplicationCommandOptionInteger: case discordgo.ApplicationCommandOptionInteger:
sb.WriteString(fmt.Sprint(o.IntValue())) span.SetAttributes(attribute.Int64(fmt.Sprintf("command_option.%s", o.Name), o.IntValue()))
case discordgo.ApplicationCommandOptionBoolean: case discordgo.ApplicationCommandOptionBoolean:
sb.WriteString(fmt.Sprint(o.BoolValue())) span.SetAttributes(attribute.Bool(fmt.Sprintf("command_option.%s", o.Name), o.BoolValue()))
default: default:
sb.WriteString("[unsupported type]") span.SetAttributes(attribute.String(fmt.Sprintf("command_option.%s", o.Name), "unsupported_type"))
} }
p = append(p, sb.String())
} }
return strings.Join(p, ", ")
}()). log.Info().Ctx(ctx).Msg("command invoked")
Msg("command invoked")
} }
func debugCommandCompletion(ctx context.Context, name string, dur time.Duration, s *discordgo.Session, i *discordgo.InteractionCreate) { func debugCommandCompletion(ctx context.Context, name string, dur time.Duration, err error, s *discordgo.Session, i *discordgo.InteractionCreate) {
log.Info(). span := trace.SpanFromContext(ctx)
Ctx(ctx). if err != nil {
Str("userid", i.Member.User.ID). span.SetStatus(codes.Error, err.Error())
Str("username", i.Member.User.Username). }
Str("command", name). log.Info().Ctx(ctx).Dur("latency_ms", dur).Msg("command completed")
Dur("latency_ms", dur).
Msg("command completed")
} }
func min(a, b int) int { func min(a, b int) int {

Loading…
Cancel
Save