Przeglądaj źródła

Added Sentry for log.Error

Yoginth 7 lat temu
rodzic
commit
71dbaad94f

+ 4 - 0
cmd/hook.go

@@ -19,6 +19,7 @@ import (
 	"strings"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/urfave/cli"
 	"gitlab.com/gitote/git-module"
 	log "gopkg.in/clog.v1"
@@ -227,6 +228,7 @@ func runHookPostReceive(c *cli.Context) error {
 			RepoName:     os.Getenv(http.ENV_REPO_NAME),
 		}
 		if err := models.PushUpdate(options); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "PushUpdate: %v", err)
 		}
 
@@ -243,9 +245,11 @@ func runHookPostReceive(c *cli.Context) error {
 		if err == nil {
 			resp.Body.Close()
 			if resp.StatusCode/100 != 2 {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "Fail to trigger task: not 2xx response code")
 			}
 		} else {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Fail to trigger task: %v", err)
 		}
 	}

+ 2 - 0
models/access.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"gitote/gitote/models/errors"
 
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 )
 
@@ -107,6 +108,7 @@ func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) {
 		repo, err := GetRepositoryByID(access.RepoID)
 		if err != nil {
 			if errors.IsRepoNotExist(err) {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "GetRepositoryByID: %v", err)
 				continue
 			}

+ 5 - 0
models/action.go

@@ -12,6 +12,7 @@ import (
 	"unicode"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"github.com/json-iterator/go"
 	"gitlab.com/gitote/git-module"
@@ -159,6 +160,7 @@ func (a *Action) GetIssueTitle() string {
 	index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
 	issue, err := GetIssueByIndex(a.RepoID, index)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "GetIssueByIndex: %v", err)
 		return "500 when get issue"
 	}
@@ -169,6 +171,7 @@ func (a *Action) GetIssueContent() string {
 	index := com.StrTo(a.GetIssueInfos()[0]).MustInt64()
 	issue, err := GetIssueByIndex(a.RepoID, index)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "GetIssueByIndex: %v", err)
 		return "500 when get issue"
 	}
@@ -304,6 +307,7 @@ func (push *PushCommits) AvatarLink(email string) string {
 		if err != nil {
 			push.avatars[email] = tool.AvatarLink(email)
 			if !errors.IsUserNotExist(err) {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(4, "GetUserByEmail: %v", err)
 			}
 		} else {
@@ -487,6 +491,7 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
 		}
 
 		if err = UpdateIssuesCommit(pusher, repo, opts.Commits.Commits); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "UpdateIssuesCommit: %v", err)
 		}
 	}

+ 2 - 0
models/admin.go

@@ -10,6 +10,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	log "gopkg.in/clog.v1"
 )
@@ -85,6 +86,7 @@ func RemoveAllWithNotice(title, path string) {
 		desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
 		log.Warn(desc)
 		if err = CreateRepositoryNotice(desc); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "CreateRepositoryNotice: %v", err)
 		}
 	}

+ 10 - 0
models/comment.go

@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	api "gitlab.com/gitote/go-gitote-client"
 	log "gopkg.in/clog.v1"
@@ -174,6 +175,7 @@ func (cmt *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue)
 		issue.Content = fmt.Sprintf("Reopened #%d", issue.Index)
 	}
 	if err = mailIssueCommentToParticipants(issue, cmt.Poster, mentions); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "mailIssueCommentToParticipants: %v", err)
 	}
 
@@ -276,9 +278,11 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
 	// Notify watchers for whatever action comes in, ignore if no action type.
 	if act.OpType > 0 {
 		if err = notifyWatchers(e, act); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "notifyWatchers: %v", err)
 		}
 		if err = comment.mailParticipants(e, act.OpType, opts.Issue); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "MailParticipants: %v", err)
 		}
 	}
@@ -350,6 +354,7 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri
 		Repository: repo.APIFormat(nil),
 		Sender:     doer.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
 	}
 
@@ -459,6 +464,7 @@ func UpdateComment(doer *User, c *Comment, oldContent string) (err error) {
 	}
 
 	if err = c.Issue.LoadAttributes(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Issue.LoadAttributes [issue_id: %d]: %v", c.IssueID, err)
 	} else if err = PrepareWebhooks(c.Issue.Repo, HOOK_EVENT_ISSUE_COMMENT, &api.IssueCommentPayload{
 		Action:  api.HOOK_ISSUE_COMMENT_EDITED,
@@ -472,6 +478,7 @@ func UpdateComment(doer *User, c *Comment, oldContent string) (err error) {
 		Repository: c.Issue.Repo.APIFormat(nil),
 		Sender:     doer.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
 	}
 
@@ -510,10 +517,12 @@ func DeleteCommentByID(doer *User, id int64) error {
 
 	_, err = DeleteAttachmentsByComment(comment.ID, true)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Failed to delete attachments by comment[%d]: %v", comment.ID, err)
 	}
 
 	if err = comment.Issue.LoadAttributes(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Issue.LoadAttributes [issue_id: %d]: %v", comment.IssueID, err)
 	} else if err = PrepareWebhooks(comment.Issue.Repo, HOOK_EVENT_ISSUE_COMMENT, &api.IssueCommentPayload{
 		Action:     api.HOOK_ISSUE_COMMENT_DELETED,
@@ -522,6 +531,7 @@ func DeleteCommentByID(doer *User, id int64) error {
 		Repository: comment.Issue.Repo.APIFormat(nil),
 		Sender:     doer.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
 	}
 	return nil

+ 13 - 0
models/issue.go

@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	api "gitlab.com/gitote/go-gitote-client"
 	log "gopkg.in/clog.v1"
@@ -225,6 +226,7 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
 	if issue.IsPull {
 		err = issue.PullRequest.LoadIssue()
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LoadIssue: %v", err)
 			return
 		}
@@ -245,6 +247,7 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
 		})
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	}
 }
@@ -335,6 +338,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
 	if issue.IsPull {
 		err = issue.PullRequest.LoadIssue()
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LoadIssue: %v", err)
 			return
 		}
@@ -355,6 +359,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
 		})
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	}
 
@@ -492,6 +497,7 @@ func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (e
 		err = PrepareWebhooks(repo, HOOK_EVENT_ISSUES, apiIssues)
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
 	}
 
@@ -534,6 +540,7 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
 		})
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	}
 
@@ -576,6 +583,7 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
 		})
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	}
 
@@ -590,6 +598,7 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
 
 	issue.Assignee, err = GetUserByID(issue.AssigneeID)
 	if err != nil && !errors.IsUserNotExist(err) {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "GetUserByID [assignee_id: %v]: %v", issue.AssigneeID, err)
 		return nil
 	}
@@ -625,6 +634,7 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
 		err = PrepareWebhooks(issue.Repo, HOOK_EVENT_ISSUES, apiIssues)
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, isRemoveAssignee, err)
 	}
 
@@ -766,9 +776,11 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
 		RepoName:     repo.Name,
 		IsPrivate:    repo.IsPrivate,
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "NotifyWatchers: %v", err)
 	}
 	if err = issue.MailParticipants(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "MailParticipants: %v", err)
 	}
 
@@ -779,6 +791,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
 		Repository: repo.APIFormat(nil),
 		Sender:     issue.Poster.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks: %v", err)
 	}
 

+ 2 - 0
models/issue_mail.go

@@ -7,6 +7,7 @@ import (
 	"gitote/gitote/pkg/setting"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 )
 
@@ -162,6 +163,7 @@ func (issue *Issue) MailParticipants() (err error) {
 	}
 
 	if err = mailIssueCommentToParticipants(issue, issue.Poster, mentions); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "mailIssueCommentToParticipants: %v", err)
 	}
 

+ 3 - 0
models/milestone.go

@@ -5,6 +5,7 @@ import (
 	"gitote/gitote/pkg/setting"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	api "gitlab.com/gitote/go-gitote-client"
 	log "gopkg.in/clog.v1"
@@ -330,6 +331,7 @@ func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err
 	if issue.IsPull {
 		err = issue.PullRequest.LoadIssue()
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LoadIssue: %v", err)
 			return
 		}
@@ -350,6 +352,7 @@ func ChangeMilestoneAssign(doer *User, issue *Issue, oldMilestoneID int64) (err
 		})
 	}
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
 	}
 

+ 24 - 0
models/mirror.go

@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"gitlab.com/gitote/git-module"
 	log "gopkg.in/clog.v1"
@@ -52,6 +53,7 @@ func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
 	case "repo_id":
 		m.Repo, err = GetRepositoryByID(m.RepoID)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "GetRepositoryByID [%d]: %v", m.ID, err)
 		}
 	case "updated_unix":
@@ -113,6 +115,7 @@ func (m *Mirror) readAddress() {
 
 	cfg, err := ini.Load(m.Repo.GitConfigPath())
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Load: %v", err)
 		return
 	}
@@ -256,6 +259,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
 	}) {
 		desc := fmt.Sprintf("Source URL of mirror repository '%s' is not accessible: %s", m.Repo.FullName(), m.MosaicsAddress())
 		if err := CreateRepositoryNotice(desc); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "CreateRepositoryNotice: %v", err)
 		}
 		return nil, false
@@ -272,6 +276,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
 		desc := fmt.Sprintf("Fail to update mirror repository '%s': %s", repoPath, stderr)
 		log.Error(2, desc)
 		if err = CreateRepositoryNotice(desc); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "CreateRepositoryNotice: %v", err)
 		}
 		return nil, false
@@ -279,6 +284,7 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
 	output := stderr
 
 	if err := m.Repo.UpdateSize(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "UpdateSize [repo_id: %d]: %v", m.Repo.ID, err)
 	}
 
@@ -288,8 +294,10 @@ func (m *Mirror) runSync() ([]*mirrorSyncResult, bool) {
 			timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath),
 			"git", "remote", "update", "--prune"); err != nil {
 			desc := fmt.Sprintf("Fail to update mirror wiki repository '%s': %s", wikiPath, stderr)
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, desc)
 			if err = CreateRepositoryNotice(desc); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "CreateRepositoryNotice: %v", err)
 			}
 		}
@@ -348,6 +356,7 @@ func MirrorUpdate() {
 		MirrorQueue.Add(m.RepoID)
 		return nil
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "MirrorUpdate: %v", err)
 	}
 }
@@ -362,6 +371,7 @@ func SyncMirrors() {
 
 		m, err := GetMirrorByRepoID(com.StrTo(repoID).MustInt64())
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "GetMirrorByRepoID [%d]: %v", m.RepoID, err)
 			continue
 		}
@@ -373,6 +383,7 @@ func SyncMirrors() {
 
 		m.ScheduleNextSync()
 		if err = UpdateMirror(m); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "UpdateMirror [%d]: %v", m.RepoID, err)
 			continue
 		}
@@ -387,6 +398,7 @@ func SyncMirrors() {
 		} else {
 			gitRepo, err = git.OpenRepository(m.Repo.RepoPath())
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "OpenRepository [%d]: %v", m.RepoID, err)
 				continue
 			}
@@ -401,6 +413,7 @@ func SyncMirrors() {
 			// Delete reference
 			if result.newCommitID == GIT_SHORT_EMPTY_SHA {
 				if err = MirrorSyncDeleteAction(m.Repo, result.refName); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "MirrorSyncDeleteAction [repo_id: %d]: %v", m.RepoID, err)
 				}
 				continue
@@ -410,6 +423,7 @@ func SyncMirrors() {
 			isNewRef := false
 			if result.oldCommitID == GIT_SHORT_EMPTY_SHA {
 				if err = MirrorSyncCreateAction(m.Repo, result.refName); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "MirrorSyncCreateAction [repo_id: %d]: %v", m.RepoID, err)
 					continue
 				}
@@ -422,32 +436,38 @@ func SyncMirrors() {
 			if !isNewRef {
 				oldCommitID, err = git.GetFullCommitID(gitRepo.Path, result.oldCommitID)
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
 					continue
 				}
 				newCommitID, err = git.GetFullCommitID(gitRepo.Path, result.newCommitID)
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
 					continue
 				}
 				commits, err = gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID)
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
 					continue
 				}
 			} else {
 				refNewCommitID, err := gitRepo.GetBranchCommitID(result.refName)
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
 					continue
 				}
 				if newCommit, err := gitRepo.GetCommit(refNewCommitID); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "GetCommit [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommitID, err)
 					continue
 				} else {
 					// TODO: Get the commits for the new ref until the closest ancestor branch like Github does
 					commits, err = newCommit.CommitsBeforeLimit(10)
 					if err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(2, "CommitsBeforeLimit [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommitID, err)
 					}
 					oldCommitID = git.EMPTY_SHA
@@ -460,12 +480,14 @@ func SyncMirrors() {
 				NewCommitID: newCommitID,
 				Commits:     ListToPushCommits(commits),
 			}); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "MirrorSyncPushAction [repo_id: %d]: %v", m.RepoID, err)
 				continue
 			}
 		}
 
 		if _, err = x.Exec("UPDATE mirror SET updated_unix = ? WHERE repo_id = ?", time.Now().Unix(), m.RepoID); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Update 'mirror.updated_unix' [%d]: %v", m.RepoID, err)
 			continue
 		}
@@ -474,6 +496,7 @@ func SyncMirrors() {
 		// update if latest commit date is newer.
 		commitDate, err := git.GetLatestCommitDate(m.Repo.RepoPath(), "")
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "GetLatestCommitDate [%d]: %v", m.RepoID, err)
 			continue
 		} else if commitDate.Before(m.Repo.Updated) {
@@ -481,6 +504,7 @@ func SyncMirrors() {
 		}
 
 		if _, err = x.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", commitDate.Unix(), m.RepoID); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Update 'repository.updated_unix' [%d]: %v", m.RepoID, err)
 			continue
 		}

+ 4 - 0
models/models.go

@@ -13,6 +13,7 @@ import (
 
 	"github.com/Unknwon/com"
 	_ "github.com/denisenkom/go-mssqldb"
+	raven "github.com/getsentry/raven-go"
 	_ "github.com/go-sql-driver/mysql"
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/xorm"
@@ -352,12 +353,14 @@ func ImportDatabase(dirPath string, verbose bool) (err error) {
 
 			meta := make(map[string]interface{})
 			if err = jsoniter.Unmarshal(scanner.Bytes(), &meta); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "Failed to unmarshal to map: %v", err)
 			}
 
 			// Reset created_unix back to the date save in archive because Insert method updates its value
 			if isInsertProcessor && !skipInsertProcessors[rawTableName] {
 				if _, err = x.Exec("UPDATE "+rawTableName+" SET created_unix=? WHERE id=?", meta["CreatedUnix"], meta["ID"]); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "Failed to reset 'created_unix': %v", err)
 				}
 			}
@@ -365,6 +368,7 @@ func ImportDatabase(dirPath string, verbose bool) (err error) {
 			switch rawTableName {
 			case "milestone":
 				if _, err = x.Exec("UPDATE "+rawTableName+" SET deadline_unix=?, closed_date_unix=? WHERE id=?", meta["DeadlineUnix"], meta["ClosedDateUnix"], meta["ID"]); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "Failed to reset 'milestone.deadline_unix', 'milestone.closed_date_unix': %v", err)
 				}
 			}

+ 24 - 0
models/pull.go

@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"gitlab.com/gitote/git-module"
 	api "gitlab.com/gitote/go-gitote-client"
@@ -324,11 +325,13 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 	}
 
 	if err = MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "MergePullRequestAction [%d]: %v", pr.ID, err)
 	}
 
 	// Reload pull request information.
 	if err = pr.LoadAttributes(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "LoadAttributes: %v", err)
 		return nil
 	}
@@ -339,12 +342,14 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 		Repository:  pr.Issue.Repo.APIFormat(nil),
 		Sender:      doer.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks: %v", err)
 		return nil
 	}
 
 	l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "CommitsBetweenIDs: %v", err)
 		return nil
 	}
@@ -354,6 +359,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 	// to avoid strange diff commits produced.
 	mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "GetBranchCommit: %v", err)
 		return nil
 	}
@@ -363,6 +369,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 
 	commits, err := ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.RepoPath(), pr.BaseRepo.HTMLURL())
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "ToApiPayloadCommits: %v", err)
 		return nil
 	}
@@ -378,6 +385,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
 		Sender:     doer.APIFormat(),
 	}
 	if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks: %v", err)
 		return nil
 	}
@@ -483,9 +491,11 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
 		RepoName:     repo.Name,
 		IsPrivate:    repo.IsPrivate,
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "NotifyWatchers: %v", err)
 	}
 	if err = pull.MailParticipants(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "MailParticipants: %v", err)
 	}
 
@@ -498,6 +508,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
 		Repository:  repo.APIFormat(nil),
 		Sender:      pull.Poster.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks: %v", err)
 	}
 
@@ -660,6 +671,7 @@ func (pr *PullRequest) AddToTaskQueue() {
 	go PullRequestQueue.AddFunc(pr.ID, func() {
 		pr.Status = PULL_REQUEST_STATUS_CHECKING
 		if err := pr.UpdateCols("status"); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
 		}
 	})
@@ -710,9 +722,11 @@ func addHeadRepoTasks(prs []*PullRequest) {
 	for _, pr := range prs {
 		log.Trace("addHeadRepoTasks[%d]: composing new test task", pr.ID)
 		if err := pr.UpdatePatch(); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "UpdatePatch: %v", err)
 			continue
 		} else if err := pr.PushToBaseRepo(); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "PushToBaseRepo: %v", err)
 			continue
 		}
@@ -727,12 +741,14 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
 	log.Trace("AddTestPullRequestTask [head_repo_id: %d, head_branch: %s]: finding pull requests", repoID, branch)
 	prs, err := GetUnmergedPullRequestsByHeadInfo(repoID, branch)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Find pull requests [head_repo_id: %d, head_branch: %s]: %v", repoID, branch, err)
 		return
 	}
 
 	if isSync {
 		if err = PullRequestList(prs).LoadAttributes(); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "PullRequestList.LoadAttributes: %v", err)
 		}
 
@@ -740,6 +756,7 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
 			for _, pr := range prs {
 				pr.Issue.PullRequest = pr
 				if err = pr.Issue.LoadAttributes(); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "LoadAttributes: %v", err)
 					continue
 				}
@@ -750,6 +767,7 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
 					Repository:  pr.Issue.Repo.APIFormat(nil),
 					Sender:      doer.APIFormat(),
 				}); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "PrepareWebhooks [pull_id: %v]: %v", pr.ID, err)
 					continue
 				}
@@ -762,6 +780,7 @@ func AddTestPullRequestTask(doer *User, repoID int64, branch string, isSync bool
 	log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", repoID, branch)
 	prs, err = GetUnmergedPullRequestsByBaseInfo(repoID, branch)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Find pull requests [base_repo_id: %d, base_branch: %s]: %v", repoID, branch, err)
 		return
 	}
@@ -789,6 +808,7 @@ func (pr *PullRequest) checkAndUpdateStatus() {
 	// Make sure there is no waiting test to process before levaing the checking status.
 	if !PullRequestQueue.Exist(pr.ID) {
 		if err := pr.UpdateCols("status"); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "Update[%d]: %v", pr.ID, err)
 		}
 	}
@@ -805,11 +825,13 @@ func TestPullRequests() {
 			pr := bean.(*PullRequest)
 
 			if err := pr.LoadAttributes(); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(3, "LoadAttributes: %v", err)
 				return nil
 			}
 
 			if err := pr.testPatch(); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(3, "testPatch: %v", err)
 				return nil
 			}
@@ -829,9 +851,11 @@ func TestPullRequests() {
 
 		pr, err := GetPullRequestByID(com.StrTo(prID).MustInt64())
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "GetPullRequestByID[%s]: %v", prID, err)
 			continue
 		} else if err = pr.testPatch(); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "testPatch[%d]: %v", pr.ID, err)
 			continue
 		}

+ 2 - 0
models/release.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"gitlab.com/gitote/git-module"
 	api "gitlab.com/gitote/go-gitote-client"
@@ -150,6 +151,7 @@ func (r *Release) preparePublishWebhooks() {
 		Repository: r.Repo.APIFormat(nil),
 		Sender:     r.Publisher.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks: %v", err)
 	}
 }

+ 21 - 0
models/repo.go

@@ -816,6 +816,7 @@ func MigrateRepository(doer, owner *User, opts MigrateRepoOptions) (*Repository,
 		}
 
 		if err = repo.UpdateSize(); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "UpdateSize [repo_id: %d]: %v", repo.ID, err)
 		}
 	}
@@ -1166,6 +1167,7 @@ func countRepositories(userID int64, private bool) int64 {
 
 	count, err := sess.Count(new(Repository))
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "countRepositories: %v", err)
 	}
 	return count
@@ -1435,10 +1437,12 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
 		daemonExportFile := path.Join(repo.RepoPath(), "git-daemon-export-ok")
 		if repo.IsPrivate && com.IsExist(daemonExportFile) {
 			if err = os.Remove(daemonExportFile); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(4, "Failed to remove %s: %v", daemonExportFile, err)
 			}
 		} else if !repo.IsPrivate && !com.IsExist(daemonExportFile) {
 			if f, err := os.Create(daemonExportFile); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(4, "Failed to create %s: %v", daemonExportFile, err)
 			} else {
 				f.Close()
@@ -1591,6 +1595,7 @@ func DeleteRepository(uid, repoID int64) error {
 
 	if repo.NumForks > 0 {
 		if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
 		}
 	}
@@ -1780,6 +1785,7 @@ func DeleteOldRepositoryArchives() {
 
 				dir, err := os.Open(dirPath)
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(3, "Fail to open directory '%s': %v", dirPath, err)
 					continue
 				}
@@ -1787,6 +1793,7 @@ func DeleteOldRepositoryArchives() {
 				fis, err := dir.Readdir(0)
 				dir.Close()
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(3, "Fail to read directory '%s': %v", dirPath, err)
 					continue
 				}
@@ -1801,6 +1808,7 @@ func DeleteOldRepositoryArchives() {
 						desc := fmt.Sprintf("Fail to health delete archive '%s': %v", archivePath, err)
 						log.Warn(desc)
 						if err = CreateRepositoryNotice(desc); err != nil {
+							raven.CaptureErrorAndWait(err, nil)
 							log.Error(3, "CreateRepositoryNotice: %v", err)
 						}
 					}
@@ -1809,6 +1817,7 @@ func DeleteOldRepositoryArchives() {
 
 			return nil
 		}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "DeleteOldRepositoryArchives: %v", err)
 	}
 }
@@ -1934,11 +1943,13 @@ func GitFsck() {
 				desc := fmt.Sprintf("Fail to health check repository '%s': %v", repoPath, err)
 				log.Warn(desc)
 				if err = CreateRepositoryNotice(desc); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(3, "CreateRepositoryNotice: %v", err)
 				}
 			}
 			return nil
 		}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "GitFsck: %v", err)
 	}
 }
@@ -1970,6 +1981,7 @@ type repoChecker struct {
 func repoStatsCheck(checker *repoChecker) {
 	results, err := x.Query(checker.querySQL)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Select %s: %v", checker.desc, err)
 		return
 	}
@@ -1978,6 +1990,7 @@ func repoStatsCheck(checker *repoChecker) {
 		log.Trace("Updating %s: %d", checker.desc, id)
 		_, err = x.Exec(checker.correctSQL, id, id)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Update %s[%d]: %v", checker.desc, id, err)
 		}
 	}
@@ -2032,6 +2045,7 @@ func CheckRepoStats() {
 	desc := "repository count 'num_closed_issues'"
 	results, err := x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Select %s: %v", desc, err)
 	} else {
 		for _, result := range results {
@@ -2039,6 +2053,7 @@ func CheckRepoStats() {
 			log.Trace("Updating %s: %d", desc, id)
 			_, err = x.Exec("UPDATE `repository` SET num_closed_issues=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, false, id)
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "Update %s[%d]: %v", desc, id, err)
 			}
 		}
@@ -2049,6 +2064,7 @@ func CheckRepoStats() {
 	// ***** START: Repository.NumForks *****
 	results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Select repository count 'num_forks': %v", err)
 	} else {
 		for _, result := range results {
@@ -2057,18 +2073,21 @@ func CheckRepoStats() {
 
 			repo, err := GetRepositoryByID(id)
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "GetRepositoryByID[%d]: %v", id, err)
 				continue
 			}
 
 			rawResult, err := x.Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID)
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "Select count of forks[%d]: %v", repo.ID, err)
 				continue
 			}
 			repo.NumForks = int(parseCountResult(rawResult))
 
 			if err = UpdateRepository(repo, false); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "UpdateRepository[%d]: %v", id, err)
 				continue
 			}
@@ -2402,6 +2421,7 @@ func ForkRepository(doer, owner *User, baseRepo *Repository, name, desc string)
 	}
 
 	if err = repo.UpdateSize(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "UpdateSize [repo_id: %d]: %v", repo.ID, err)
 	}
 	if err = PrepareWebhooks(baseRepo, HOOK_EVENT_FORK, &api.ForkPayload{
@@ -2409,6 +2429,7 @@ func ForkRepository(doer, owner *User, baseRepo *Repository, name, desc string)
 		Repo:   baseRepo.APIFormat(nil),
 		Sender: doer.APIFormat(),
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "PrepareWebhooks [repo_id: %d]: %v", baseRepo.ID, err)
 	}
 	return repo, nil

+ 2 - 0
models/repo_collaboration.go

@@ -3,6 +3,7 @@ package models
 import (
 	"fmt"
 
+	raven "github.com/getsentry/raven-go"
 	api "gitlab.com/gitote/go-gitote-client"
 	log "gopkg.in/clog.v1"
 )
@@ -36,6 +37,7 @@ func IsCollaborator(repoID, userID int64) bool {
 	}
 	has, err := x.Get(collaboration)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "get collaboration [repo_id: %d, user_id: %d]: %v", repoID, userID, err)
 		return false
 	}

+ 10 - 0
models/repo_editor.go

@@ -15,6 +15,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	gouuid "github.com/satori/go.uuid"
 	git "gitlab.com/gitote/git-module"
 	log "gopkg.in/clog.v1"
@@ -139,11 +140,13 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
 
 	gitRepo, err := git.OpenRepository(repo.RepoPath())
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "OpenRepository: %v", err)
 		return nil
 	}
 	commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
 		return nil
 	}
@@ -166,6 +169,7 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
 		NewCommitID: commit.ID.String(),
 		Commits:     pushCommits,
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "CommitRepoAction: %v", err)
 		return nil
 	}
@@ -262,11 +266,13 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
 
 	gitRepo, err := git.OpenRepository(repo.RepoPath())
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "OpenRepository: %v", err)
 		return nil
 	}
 	commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
 		return nil
 	}
@@ -285,6 +291,7 @@ func (repo *Repository) DeleteRepoFile(doer *User, opts DeleteRepoFileOptions) (
 		NewCommitID: commit.ID.String(),
 		Commits:     pushCommits,
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "CommitRepoAction: %v", err)
 		return nil
 	}
@@ -479,11 +486,13 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
 
 	gitRepo, err := git.OpenRepository(repo.RepoPath())
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "OpenRepository: %v", err)
 		return nil
 	}
 	commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
 		return nil
 	}
@@ -502,6 +511,7 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
 		NewCommitID: commit.ID.String(),
 		Commits:     pushCommits,
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "CommitRepoAction: %v", err)
 		return nil
 	}

+ 2 - 0
models/ssh_key.go

@@ -17,6 +17,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"golang.org/x/crypto/ssh"
 	log "gopkg.in/clog.v1"
@@ -336,6 +337,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
 
 		// .ssh directory should have mode 700, and authorized_keys file should have mode 600.
 		if fi.Mode().Perm() > 0600 {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String())
 			if err = f.Chmod(0600); err != nil {
 				return err

+ 5 - 0
models/user.go

@@ -21,6 +21,7 @@ import (
 	"unicode/utf8"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"github.com/nfnt/resize"
 	"gitlab.com/gitote/git-module"
@@ -303,6 +304,7 @@ func (u *User) RelAvatarLink() string {
 	case setting.DisableGravatar, setting.OfflineMode:
 		if !com.IsExist(u.CustomAvatarPath()) {
 			if err := u.GenerateRandomAvatar(); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(3, "GenerateRandomAvatar: %v", err)
 			}
 		}
@@ -409,6 +411,7 @@ func (u *User) DeleteAvatar() error {
 func (u *User) IsAdminOfRepo(repo *Repository) bool {
 	has, err := HasAccess(u.ID, repo, ACCESS_MODE_ADMIN)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "HasAccess: %v", err)
 	}
 	return has
@@ -418,6 +421,7 @@ func (u *User) IsAdminOfRepo(repo *Repository) bool {
 func (u *User) IsWriterOfRepo(repo *Repository) bool {
 	has, err := HasAccess(u.ID, repo, ACCESS_MODE_WRITE)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "HasAccess: %v", err)
 	}
 	return has
@@ -646,6 +650,7 @@ func parseUserFromCode(code string) (user *User) {
 		if user, err = GetUserByName(string(b)); user != nil {
 			return user
 		} else if !errors.IsUserNotExist(err) {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "GetUserByName: %v", err)
 		}
 	}

+ 12 - 0
models/webhook.go

@@ -14,6 +14,7 @@ import (
 	"strings"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-xorm/xorm"
 	"github.com/json-iterator/go"
 	gouuid "github.com/satori/go.uuid"
@@ -121,6 +122,7 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
 	case "events":
 		w.HookEvent = &HookEvent{}
 		if err = jsoniter.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "Unmarshal [%d]: %v", w.ID, err)
 		}
 	case "created_unix":
@@ -133,6 +135,7 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
 func (w *Webhook) GetSlackHook() *SlackMeta {
 	s := &SlackMeta{}
 	if err := jsoniter.Unmarshal([]byte(w.Meta), s); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "GetSlackHook [%d]: %v", w.ID, err)
 	}
 	return s
@@ -440,6 +443,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
 
 		t.RequestInfo = &HookRequest{}
 		if err = jsoniter.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "Unmarshal[%d]: %v", t.ID, err)
 		}
 
@@ -450,6 +454,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
 
 		t.ResponseInfo = &HookResponse{}
 		if err = jsoniter.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "Unmarshal [%d]: %v", t.ID, err)
 		}
 	}
@@ -458,6 +463,7 @@ func (t *HookTask) AfterSet(colName string, _ xorm.Cell) {
 func (t *HookTask) MarshalJSON(v interface{}) string {
 	p, err := jsoniter.Marshal(v)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "Marshal [%d]: %v", t.ID, err)
 	}
 	return string(p)
@@ -566,6 +572,7 @@ func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Pay
 		if len(w.Secret) > 0 {
 			data, err := payloader.JSONPayload()
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "prepareWebhooks.JSONPayload: %v", err)
 			}
 			sig := hmac.New(sha256.New, []byte(w.Secret))
@@ -669,6 +676,7 @@ func (t *HookTask) deliver() {
 		// Update webhook last delivery status.
 		w, err := GetWebhookByID(t.HookID)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "GetWebhookByID: %v", err)
 			return
 		}
@@ -678,6 +686,7 @@ func (t *HookTask) deliver() {
 			w.LastStatus = HOOK_STATUS_FAILED
 		}
 		if err = UpdateWebhook(w); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "UpdateWebhook: %v", err)
 			return
 		}
@@ -720,6 +729,7 @@ func DeliverHooks() {
 	// Update hook task status.
 	for _, t := range tasks {
 		if err := UpdateHookTask(t); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
 		}
 	}
@@ -731,12 +741,14 @@ func DeliverHooks() {
 
 		tasks = make([]*HookTask, 0, 5)
 		if err := x.Where("repo_id = ?", repoID).And("is_delivered = ?", false).Find(&tasks); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "Get repository [%s] hook tasks: %v", repoID, err)
 			continue
 		}
 		for _, t := range tasks {
 			t.deliver()
 			if err := UpdateHookTask(t); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(4, "UpdateHookTask [%d]: %v", t.ID, err)
 				continue
 			}

+ 8 - 0
pkg/auth/auth.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-macaron/session"
 	gouuid "github.com/satori/go.uuid"
 	log "gopkg.in/clog.v1"
@@ -46,12 +47,14 @@ func SignedInID(c *macaron.Context, sess session.Store) int64 {
 			t, err := models.GetAccessTokenBySHA(tokenSHA)
 			if err != nil {
 				if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "GetAccessTokenBySHA: %v", err)
 				}
 				return 0
 			}
 			t.Updated = time.Now()
 			if err = models.UpdateAccessToken(t); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "UpdateAccessToken: %v", err)
 			}
 			return t.UID
@@ -65,6 +68,7 @@ func SignedInID(c *macaron.Context, sess session.Store) int64 {
 	if id, ok := uid.(int64); ok {
 		if _, err := models.GetUserByID(id); err != nil {
 			if !errors.IsUserNotExist(err) {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "GetUserByID: %v", err)
 			}
 			return 0
@@ -90,6 +94,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
 				u, err := models.GetUserByName(webAuthUser)
 				if err != nil {
 					if !errors.IsUserNotExist(err) {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(4, "GetUserByName: %v", err)
 						return nil, false
 					}
@@ -105,6 +110,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
 						}
 						if err = models.CreateUser(u); err != nil {
 							// FIXME: should I create a system notice?
+							raven.CaptureErrorAndWait(err, nil)
 							log.Error(4, "CreateUser: %v", err)
 							return nil, false
 						} else {
@@ -126,6 +132,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
 				u, err := models.UserLogin(uname, passwd, -1)
 				if err != nil {
 					if !errors.IsUserNotExist(err) {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(4, "UserLogin: %v", err)
 					}
 					return nil, false
@@ -139,6 +146,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
 
 	u, err := models.GetUserByID(uid)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "GetUserById: %v", err)
 		return nil, false
 	}

+ 8 - 0
pkg/auth/ldap/ldap.go

@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"strings"
 
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 	"gopkg.in/ldap.v2"
 )
@@ -126,6 +127,7 @@ func (ls *Source) findUserDN(l *ldap.Conn, name string) (string, bool) {
 
 	userDN := sr.Entries[0].DN
 	if userDN == "" {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "LDAP: Search was successful, but found no DN!")
 		return "", false
 	}
@@ -179,6 +181,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
 	}
 	l, err := dial(ls)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "LDAP connect failed for '%s': %v", ls.Host, err)
 		return "", "", "", "", false, false
 	}
@@ -225,6 +228,7 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
 
 	sr, err := l.Search(search)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "LDAP: User search failed: %v", err)
 		return "", "", "", "", false, false
 	} else if len(sr.Entries) < 1 {
@@ -262,9 +266,11 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
 
 		srg, err := l.Search(groupSearch)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LDAP: Group search failed: %v", err)
 			return "", "", "", "", false, false
 		} else if len(srg.Entries) < 1 {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LDAP: Group search failed: 0 entries")
 			return "", "", "", "", false, false
 		}
@@ -304,8 +310,10 @@ func (ls *Source) SearchEntry(name, passwd string, directBind bool) (string, str
 
 		sr, err = l.Search(search)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LDAP: Admin search failed: %v", err)
 		} else if len(sr.Entries) < 1 {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "LDAP: Admin search failed: 0 entries")
 		} else {
 			isAdmin = true

+ 2 - 0
pkg/context/context.go

@@ -17,6 +17,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-macaron/cache"
 	"github.com/go-macaron/csrf"
 	"github.com/go-macaron/i18n"
@@ -169,6 +170,7 @@ func (c *Context) Handle(status int, title string, err error) {
 		c.Data["Title"] = "Page Not Found"
 	case http.StatusInternalServerError:
 		c.Data["Title"] = "Internal Server Error"
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "%s: %v", title, err)
 		if !setting.ProdMode || (c.IsLogged && c.User.IsAdmin) {
 			c.Data["ErrorMsg"] = err

+ 6 - 0
pkg/mailer/mail.go

@@ -6,6 +6,7 @@ import (
 	"gitote/gitote/pkg/setting"
 	"html/template"
 
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 	"gopkg.in/gomail.v2"
 	"gopkg.in/macaron.v1"
@@ -82,6 +83,7 @@ func SendUserMail(c *macaron.Context, u User, tpl, code, subject, info string) {
 	}
 	body, err := mailRender.HTMLString(string(tpl), data)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "HTMLString: %v", err)
 		return
 	}
@@ -110,6 +112,7 @@ func SendActivateEmailMail(c *macaron.Context, u User, email string) {
 	}
 	body, err := mailRender.HTMLString(string(MAIL_AUTH_ACTIVATE_EMAIL), data)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "HTMLString: %v", err)
 		return
 	}
@@ -127,6 +130,7 @@ func SendRegisterNotifyMail(c *macaron.Context, u User) {
 	}
 	body, err := mailRender.HTMLString(string(MAIL_AUTH_REGISTER_NOTIFY), data)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "HTMLString: %v", err)
 		return
 	}
@@ -148,6 +152,7 @@ func SendCollaboratorMail(u, doer User, repo Repository) {
 	}
 	body, err := mailRender.HTMLString(string(MAIL_NOTIFY_COLLABORATOR), data)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "HTMLString: %v", err)
 		return
 	}
@@ -173,6 +178,7 @@ func composeIssueMessage(issue Issue, repo Repository, doer User, tplName string
 	data["Doer"] = doer
 	content, err := mailRender.HTMLString(tplName, data)
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "HTMLString (%s): %v", tplName, err)
 	}
 	from := gomail.NewMessage().FormatAddress(setting.MailService.FromEmail, doer.DisplayName())

+ 3 - 0
pkg/mailer/mailer.go

@@ -11,6 +11,7 @@ import (
 	"strings"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/jaytaylor/html2text"
 	log "gopkg.in/clog.v1"
 	"gopkg.in/gomail.v2"
@@ -37,6 +38,7 @@ func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
 	if setting.MailService.UsePlainText {
 		plainBody, err := html2text.FromString(htmlBody)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "html2text.FromString: %v", err)
 		} else {
 			contentType = "text/plain"
@@ -196,6 +198,7 @@ func processMailQueue() {
 		case msg := <-mailQueue:
 			log.Trace("New e-mail sending request %s: %s", msg.GetHeader("To"), msg.Info)
 			if err := gomail.Send(sender, msg.Message); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(3, "Fail to send emails %s: %s - %v", msg.GetHeader("To"), msg.Info, err)
 			} else {
 				log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info)

+ 2 - 0
pkg/process/manager.go

@@ -8,6 +8,7 @@ import (
 	"sync"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 )
 
@@ -97,6 +98,7 @@ func ExecDir(timeout time.Duration, dir, desc, cmdName string, args ...string) (
 	select {
 	case <-time.After(timeout):
 		if errKill := Kill(pid); errKill != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Fail to kill timeout process [pid: %d, desc: %s]: %v", pid, desc, errKill)
 		}
 		<-done

+ 10 - 0
pkg/ssh/ssh.go

@@ -35,6 +35,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
 
 		ch, reqs, err := newChan.Accept()
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "Error accepting channel: %v", err)
 			continue
 		}
@@ -53,6 +54,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
 					args[0] = strings.TrimLeft(args[0], "\x04")
 					_, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1])
 					if err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(3, "env: %v", err)
 						return
 					}
@@ -67,22 +69,26 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
 
 					stdout, err := cmd.StdoutPipe()
 					if err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(3, "SSH: StdoutPipe: %v", err)
 						return
 					}
 					stderr, err := cmd.StderrPipe()
 					if err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(3, "SSH: StderrPipe: %v", err)
 						return
 					}
 					input, err := cmd.StdinPipe()
 					if err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(3, "SSH: StdinPipe: %v", err)
 						return
 					}
 
 					// FIXME: check timeout
 					if err = cmd.Start(); err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(3, "SSH: Start: %v", err)
 						return
 					}
@@ -93,6 +99,7 @@ func handleServerConn(keyID string, chans <-chan ssh.NewChannel) {
 					io.Copy(ch.Stderr(), stderr)
 
 					if err = cmd.Wait(); err != nil {
+						raven.CaptureErrorAndWait(err, nil)
 						log.Error(3, "SSH: Wait: %v", err)
 						return
 					}
@@ -116,6 +123,7 @@ func listen(config *ssh.ServerConfig, host string, port int) {
 		// Once a ServerConfig has been configured, connections can be accepted.
 		conn, err := listener.Accept()
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "SSH: Error accepting incoming connection: %v", err)
 			continue
 		}
@@ -131,6 +139,7 @@ func listen(config *ssh.ServerConfig, host string, port int) {
 				if err == io.EOF {
 					log.Warn("SSH: Handshaking was terminated: %v", err)
 				} else {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(3, "SSH: Error on handshaking: %v", err)
 				}
 				return
@@ -153,6 +162,7 @@ func Listen(host string, port int, ciphers []string) {
 		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
 			pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))))
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(3, "SearchPublicKeyByContent: %v", err)
 				return nil, err
 			}

+ 2 - 0
pkg/template/template.go

@@ -14,6 +14,7 @@ import (
 	"strings"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/json-iterator/go"
 	"github.com/microcosm-cc/bluemonday"
 	"golang.org/x/net/html/charset"
@@ -272,6 +273,7 @@ func ActionIcon(opType int) string {
 func ActionContent2Commits(act Actioner) *models.PushCommits {
 	push := models.NewPushCommits()
 	if err := jsoniter.Unmarshal([]byte(act.GetContent()), push); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
 	}
 	return push

+ 3 - 0
routes/api/v1/repo/repo.go

@@ -9,6 +9,7 @@ import (
 	"gitote/gitote/routes/api/v1/convert"
 	"path"
 
+	raven "github.com/getsentry/raven-go"
 	api "gitlab.com/gitote/go-gitote-client"
 	log "gopkg.in/clog.v1"
 )
@@ -165,6 +166,7 @@ func CreateUserRepo(c *context.APIContext, owner *models.User, opt api.CreateRep
 		} else {
 			if repo != nil {
 				if err = models.DeleteRepository(c.User.ID, repo.ID); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "DeleteRepository: %v", err)
 				}
 			}
@@ -266,6 +268,7 @@ func Migrate(c *context.APIContext, f form.MigrateRepo) {
 	if err != nil {
 		if repo != nil {
 			if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "DeleteRepository: %v", errDelete)
 			}
 		}

+ 1 - 0
routes/install.go

@@ -294,6 +294,7 @@ func InstallPost(c *context.Context, f form.Install) {
 	if com.IsFile(setting.CustomConf) {
 		// Keeps custom settings if there is already something.
 		if err := cfg.Append(setting.CustomConf); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Fail to load custom conf '%s': %v", setting.CustomConf, err)
 		}
 	}

+ 2 - 0
routes/org/members.go

@@ -7,6 +7,7 @@ import (
 	"gitote/gitote/pkg/setting"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 )
 
@@ -72,6 +73,7 @@ func MembersAction(c *context.Context) {
 	}
 
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(4, "Action(%s): %v", c.Params(":action"), err)
 		c.JSON(200, map[string]interface{}{
 			"ok":  false,

+ 3 - 0
routes/org/teams.go

@@ -8,6 +8,7 @@ import (
 	"path"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 )
 
@@ -85,6 +86,7 @@ func TeamsAction(c *context.Context) {
 		if models.IsErrLastOrgOwner(err) {
 			c.Flash.Error(c.Tr("form.last_org_owner"))
 		} else {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(3, "Action(%s): %v", c.Params(":action"), err)
 			c.JSON(200, map[string]interface{}{
 				"ok":  false,
@@ -129,6 +131,7 @@ func TeamsRepoAction(c *context.Context) {
 	}
 
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(3, "Action(%s): '%s' %v", c.Params(":action"), c.Org.Team.Name, err)
 		c.Handle(500, "TeamsRepoAction", err)
 		return

+ 3 - 0
routes/repo/branch.go

@@ -6,6 +6,7 @@ import (
 	"gitote/gitote/pkg/tool"
 	"time"
 
+	raven "github.com/getsentry/raven-go"
 	"gitlab.com/gitote/git-module"
 	api "gitlab.com/gitote/go-gitote-client"
 	log "gopkg.in/clog.v1"
@@ -119,6 +120,7 @@ func DeleteBranchPost(c *context.Context) {
 	if len(commitID) > 0 {
 		branchCommitID, err := c.Repo.GitRepo.GetBranchCommitID(branchName)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Failed to get commit ID of branch %q: %v", branchName, err)
 			return
 		}
@@ -132,6 +134,7 @@ func DeleteBranchPost(c *context.Context) {
 	if err := c.Repo.GitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{
 		Force: true,
 	}); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Failed to delete branch %q: %v", branchName, err)
 		return
 	}

+ 2 - 0
routes/repo/editor.go

@@ -13,6 +13,7 @@ import (
 	"path"
 	"strings"
 
+	raven "github.com/getsentry/raven-go"
 	"gitlab.com/gitote/git-module"
 	log "gopkg.in/clog.v1"
 )
@@ -84,6 +85,7 @@ func editFile(c *context.Context, isNewFile bool) {
 		buf = append(buf, d...)
 		if err, content := template.ToUTF8WithErr(buf); err != nil {
 			if err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "ToUTF8WithErr: %v", err)
 			}
 			c.Data["FileContent"] = string(buf)

+ 4 - 0
routes/repo/http.go

@@ -19,6 +19,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	log "gopkg.in/clog.v1"
 	"gopkg.in/macaron.v1"
 )
@@ -265,6 +266,7 @@ func serviceRPC(h serviceHandler, service string) {
 	if h.r.Header.Get("Content-Encoding") == "gzip" {
 		reqBody, err = gzip.NewReader(reqBody)
 		if err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "HTTP.Get: fail to create gzip reader: %v", err)
 			h.w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -288,6 +290,7 @@ func serviceRPC(h serviceHandler, service string) {
 	cmd.Stderr = &stderr
 	cmd.Stdin = reqBody
 	if err = cmd.Run(); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "HTTP.serviceRPC: fail to serve RPC '%s': %v - %s", service, err, stderr.String())
 		h.w.WriteHeader(http.StatusInternalServerError)
 		return
@@ -316,6 +319,7 @@ func gitCommand(dir string, args ...string) []byte {
 	cmd.Dir = dir
 	out, err := cmd.Output()
 	if err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, fmt.Sprintf("Git: %v - %s", err, out))
 	}
 	return out

+ 2 - 0
routes/repo/issue.go

@@ -18,6 +18,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"gitlab.com/yoginth/paginater"
 	log "gopkg.in/clog.v1"
 )
@@ -889,6 +890,7 @@ func NewComment(c *context.Context, f form.CreateComment) {
 				c.Flash.Info(c.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index))
 			} else {
 				if err = issue.ChangeStatus(c.User, c.Repo.Repository, f.Status == "close"); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "ChangeStatus: %v", err)
 				} else {
 					log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed)

+ 3 - 0
routes/repo/repo.go

@@ -13,6 +13,7 @@ import (
 	"strings"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"gitlab.com/gitote/git-module"
 	log "gopkg.in/clog.v1"
 )
@@ -133,6 +134,7 @@ func CreatePost(c *context.Context, f form.CreateRepo) {
 
 	if repo != nil {
 		if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "DeleteRepository: %v", errDelete)
 		}
 	}
@@ -205,6 +207,7 @@ func MigratePost(c *context.Context, f form.MigrateRepo) {
 
 	if repo != nil {
 		if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(4, "DeleteRepository: %v", errDelete)
 		}
 	}

+ 3 - 0
routes/repo/setting.go

@@ -14,6 +14,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"gitlab.com/gitote/git-module"
 	log "gopkg.in/clog.v1"
 )
@@ -96,6 +97,7 @@ func SettingsPost(c *context.Context, f form.RepoSetting) {
 
 		if isNameChanged {
 			if err := models.RenameRepoAction(c.User, oldRepoName, repo); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "RenameRepoAction: %v", err)
 			}
 		}
@@ -406,6 +408,7 @@ func ChangeCollaborationAccessMode(c *context.Context) {
 	if err := c.Repo.Repository.ChangeCollaborationAccessMode(
 		c.QueryInt64("uid"),
 		models.AccessMode(c.QueryInt("mode"))); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "ChangeCollaborationAccessMode: %v", err)
 		return
 	}

+ 2 - 0
routes/repo/view.go

@@ -15,6 +15,7 @@ import (
 	"path"
 	"strings"
 
+	raven "github.com/getsentry/raven-go"
 	"gitlab.com/gitote/git-module"
 	"gitlab.com/yoginth/paginater"
 	log "gopkg.in/clog.v1"
@@ -170,6 +171,7 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
 			var fileContent string
 			if err, content := template.ToUTF8WithErr(buf); err != nil {
 				if err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(4, "ToUTF8WithErr: %s", err)
 				}
 				fileContent = string(buf)

+ 5 - 0
routes/user/auth.go

@@ -11,6 +11,7 @@ import (
 	"gitote/gitote/pkg/tool"
 	"net/url"
 
+	raven "github.com/getsentry/raven-go"
 	"github.com/go-macaron/captcha"
 	log "gopkg.in/clog.v1"
 )
@@ -243,6 +244,7 @@ func LoginTwoFactorPost(c *context.Context) {
 		return
 	}
 	if err = c.Cache.Put(u.TwoFactorCacheKey(passcode), 1, 60); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Failed to put cache 'two factor passcode': %v", err)
 	}
 
@@ -385,6 +387,7 @@ func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) {
 		c.Success(ACTIVATE)
 
 		if err := c.Cache.Put(u.MailResendCacheKey(), 1, 180); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Failed to put cache key 'mail resend': %v", err)
 		}
 		return
@@ -410,6 +413,7 @@ func Activate(c *context.Context) {
 				mailer.SendActivateAccountMail(c.Context, models.NewMailerUser(c.User))
 
 				if err := c.Cache.Put(c.User.MailResendCacheKey(), 1, 180); err != nil {
+					raven.CaptureErrorAndWait(err, nil)
 					log.Error(2, "Failed to put cache key 'mail resend': %v", err)
 				}
 			}
@@ -515,6 +519,7 @@ func ForgotPasswdPost(c *context.Context) {
 
 	mailer.SendResetPasswordMail(c.Context, models.NewMailerUser(u))
 	if err = c.Cache.Put(u.MailResendCacheKey(), 1, 180); err != nil {
+		raven.CaptureErrorAndWait(err, nil)
 		log.Error(2, "Failed to put cache key 'mail resend': %v", err)
 	}
 

+ 3 - 0
routes/user/setting.go

@@ -17,6 +17,7 @@ import (
 	"strings"
 
 	"github.com/Unknwon/com"
+	raven "github.com/getsentry/raven-go"
 	"github.com/pquerna/otp"
 	"github.com/pquerna/otp/totp"
 	log "gopkg.in/clog.v1"
@@ -196,6 +197,7 @@ func UpdateAvatarSetting(c *context.Context, f form.Avatar, ctxUser *models.User
 		// generate a random one when needed.
 		if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) {
 			if err := ctxUser.GenerateRandomAvatar(); err != nil {
+				raven.CaptureErrorAndWait(err, nil)
 				log.Error(2, "generate random avatar [%d]: %v", ctxUser.ID, err)
 			}
 		}
@@ -330,6 +332,7 @@ func SettingsEmailPost(c *context.Context, f form.AddEmail) {
 		mailer.SendActivateEmailMail(c.Context, models.NewMailerUser(c.User), email.Email)
 
 		if err := c.Cache.Put("MailResendLimit_"+c.User.LowerName, c.User.LowerName, 180); err != nil {
+			raven.CaptureErrorAndWait(err, nil)
 			log.Error(2, "Set cache 'MailResendLimit' failed: %v", err)
 		}
 		c.Flash.Info(c.Tr("settings.add_email_confirmation_sent", email.Email, setting.Service.ActiveCodeLives/60))