github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/send/github_comment.go (about) 1 package send 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "os" 8 "time" 9 10 "github.com/google/go-github/v53/github" 11 "github.com/mongodb/grip/message" 12 "github.com/pkg/errors" 13 "go.opentelemetry.io/otel/attribute" 14 "go.opentelemetry.io/otel/codes" 15 "go.opentelemetry.io/otel/trace" 16 ) 17 18 type githubCommentLogger struct { 19 issue int 20 opts *GithubOptions 21 gh githubClient 22 23 *Base 24 } 25 26 // NewGithubCommentLogger creates a new Sender implementation that 27 // adds a comment to a github issue (or pull request) for every log 28 // message sent. 29 // 30 // Specify the credentials to use the GitHub via the GithubOptions 31 // structure, and the issue number as an argument to the constructor. 32 func NewGithubCommentLogger(name string, issueID int, opts *GithubOptions) (Sender, error) { 33 opts.populate() 34 s := &githubCommentLogger{ 35 Base: NewBase(name), 36 opts: opts, 37 issue: issueID, 38 gh: &githubClientImpl{}, 39 } 40 41 s.gh.Init(opts.Token, opts.MaxAttempts, opts.MinDelay) 42 43 fallback := log.New(os.Stdout, "", log.LstdFlags) 44 if err := s.SetErrorHandler(ErrorHandlerFromLogger(fallback)); err != nil { 45 return nil, err 46 } 47 48 if err := s.SetFormatter(MakeDefaultFormatter()); err != nil { 49 return nil, err 50 } 51 52 s.reset = func() { 53 fallback.SetPrefix(fmt.Sprintf("[%s] [%s/%s#%d] ", 54 s.Name(), opts.Account, opts.Repo, issueID)) 55 } 56 57 return s, nil 58 } 59 60 func (s *githubCommentLogger) Send(m message.Composer) { 61 if s.Level().ShouldLog(m) { 62 text, err := s.formatter(m) 63 if err != nil { 64 s.ErrorHandler()(err, m) 65 return 66 } 67 68 comment := &github.IssueComment{Body: &text} 69 70 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 71 defer cancel() 72 73 ctx, span := tracer.Start(ctx, "CreateComment", trace.WithAttributes( 74 attribute.String(githubEndpointAttribute, "CreateComment"), 75 attribute.String(githubOwnerAttribute, s.opts.Account), 76 attribute.String(githubRepoAttribute, s.opts.Repo), 77 )) 78 defer span.End() 79 80 if _, resp, err := s.gh.CreateComment(ctx, s.opts.Account, s.opts.Repo, s.issue, comment); err != nil { 81 s.ErrorHandler()(errors.Wrap(err, "sending GitHub create comment request"), m) 82 83 span.RecordError(err) 84 span.SetStatus(codes.Error, "sending comment") 85 } else if err = handleHTTPResponseError(resp.Response); err != nil { 86 s.ErrorHandler()(errors.Wrap(err, "creating GitHub comment"), m) 87 88 span.RecordError(err) 89 span.SetStatus(codes.Error, "sending comment") 90 } 91 } 92 } 93 94 func (s *githubCommentLogger) Flush(_ context.Context) error { return nil }