diff --git a/README.md b/README.md index 9bc2a23..488f2f5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# go-cron-sentry +# Sentry Cron reporter + Package to send reports to https://sentry.io/crons/ service. + +Handles stop, start and detects and sends crash too. + +For more information see https://docs.sentry.io/product/crons/ and https://docs.sentry.io/product/crons/getting-started/http/ + + +## Example + +```go +package main + +import "github.com/teamniteo/go-sentry/cron" + +var cronReport = cron.NewMonitor("teamniteo", "monitor-slug-or-uuid") + +func main() { + cronReport.Start() + defer cronReport.Stop() // will handle crash too + + // ... the rest of the stuff +} + +``` \ No newline at end of file diff --git a/cron/cron.go b/cron/cron.go new file mode 100644 index 0000000..16f85b0 --- /dev/null +++ b/cron/cron.go @@ -0,0 +1,52 @@ +package cron + +import ( + "fmt" + "os" + + "github.com/imroc/req" +) + +type Cron struct { + Team string + DSN string + Monitor string +} + +func (c *Cron) header() req.Header { + return req.Header{ + "Content-Type": "application/json", + "Authorization": fmt.Sprintf("DSN %s", c.DSN), + } +} + +func (c *Cron) url(verb string) string { + return fmt.Sprintf("https://sentry.io/api/0/organizations/%s/monitors/%s/%s/", c.Team, c.Monitor, verb) +} + +func NewMonitor(team, monitor string) Cron { + sentryDSN := os.Getenv("SENTRY_DSN") + + return Cron{ + Team: team, + DSN: sentryDSN, + Monitor: monitor, + } +} + +func (m *Cron) Start() error { + _, err := req.Post(m.url("checkins"), m.header(), started.json()) + return err +} + +func (m *Cron) Stop() error { + + // handle crash + if err := recover(); err != nil { + req.Put(m.url("latest"), m.header(), errored.json()) + return nil + } + + _, err := req.Put(m.url("latest"), m.header(), finished.json()) + return err +} diff --git a/cron/cron_test.go b/cron/cron_test.go new file mode 100644 index 0000000..a56f3f0 --- /dev/null +++ b/cron/cron_test.go @@ -0,0 +1,30 @@ +package cron + +import "testing" + +func TestCron_url(t *testing.T) { + + tests := []struct { + name string + fields Cron + verb string + want string + }{ + {"started", Cron{"team", "dsn", "monitor"}, "checkins", "https://sentry.io/api/0/organizations/team/monitors/monitor/checkins/"}, + {"ok", Cron{"team", "dsn", "monitor"}, "latest", "https://sentry.io/api/0/organizations/team/monitors/monitor/latest/"}, + {"errored", Cron{"team", "dsn", "monitor"}, "latest", "https://sentry.io/api/0/organizations/team/monitors/monitor/latest/"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Cron{ + Team: tt.fields.Team, + DSN: tt.fields.DSN, + Monitor: tt.fields.Monitor, + } + if got := c.url(tt.verb); got != tt.want { + t.Errorf("Cron.url() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cron/report.go b/cron/report.go new file mode 100644 index 0000000..306251a --- /dev/null +++ b/cron/report.go @@ -0,0 +1,15 @@ +package cron + +import "strings" + +type Report string + +const ( + started Report = `{"status": "in_progress"}` + finished Report = `{"status": "ok"}` + errored Report = `{"status": "error"}` +) + +func (r Report) json() *strings.Reader { + return strings.NewReader(string(r)) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..889ecdb --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/teamniteo/go-sentry + +go 1.20 + +require github.com/imroc/req v0.3.2 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2c66909 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/imroc/req v0.3.2 h1:M/JkeU6RPmX+WYvT2vaaOL0K+q8ufL5LxwvJc4xeB4o= +github.com/imroc/req v0.3.2/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw=