package v1 import ( "context" "log/slog" remotev1 "code.icb4dc0.de/buildr/api/generated/remote/v1" ) var _ slog.Handler = (*GrpcExecutorHandler)(nil) func NewGrpcExecutorHandler(sender StreamSender[*remotev1.ExecutionServerMessage]) *GrpcExecutorHandler { return &GrpcExecutorHandler{ Level: slog.LevelDebug, sender: sender, } } type GrpcExecutorHandler struct { sender StreamSender[*remotev1.ExecutionServerMessage] group string attributes []slog.Attr Level slog.Level } func (g GrpcExecutorHandler) Enabled(_ context.Context, level slog.Level) bool { return g.Level <= level } //nolint:gocritic // can't pass by reference due to interface constraints func (g GrpcExecutorHandler) Handle(_ context.Context, record slog.Record) error { taskLog := remotev1.TaskLog{ Time: record.Time.UnixMicro(), Message: record.Message, Level: int32(record.Level), Attributes: make([]*remotev1.TaskLog_LogAttribute, 0, record.NumAttrs()), } record.Attrs(func(attr slog.Attr) bool { taskLog.Attributes = append(taskLog.Attributes, &remotev1.TaskLog_LogAttribute{ Key: attr.Key, Value: attr.Value.String(), }) return true }) resp := remotev1.ExecutionServerMessage{ Envelope: &remotev1.ExecutionServerMessage_TaskLog{ TaskLog: &taskLog, }, } return g.sender.Send(&resp) } func (g GrpcExecutorHandler) WithAttrs(attrs []slog.Attr) slog.Handler { all := make([]slog.Attr, len(g.attributes)+len(attrs)) copy(all, g.attributes) copy(all[len(g.attributes):], attrs) return GrpcExecutorHandler{ sender: g.sender, Level: g.Level, group: g.group, attributes: all, } } func (g GrpcExecutorHandler) WithGroup(name string) slog.Handler { g.group = name return g }