openreplay/backend/pkg/integrations/clients/sentry.go
Alexander f8a8dfa459
[Integrations] small refactoring (#1752)
* feat(backend): small refactoring in integrations

* feat(backend): ignore context timeout error
2023-12-14 11:28:05 +01:00

151 lines
3.5 KiB
Go

package clients
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"openreplay/backend/pkg/messages"
)
/*
They also have different stuff
Documentation says:
"Note: This endpoint is experimental and may be removed without notice."
*/
type sentry struct {
OrganizationSlug string // `json:"organization_slug"`
ProjectSlug string // `json:"project_slug"`
Token string // `json:"token"`
}
type sentryEvent struct {
Tags []struct {
Key string
Value string `json:"value"`
}
DateCreated string `json:"dateCreated"` // or dateReceived ?
Title string
EventID string `json:"eventID"`
}
func (sn *sentry) Request(c *client) error {
requestURL := fmt.Sprintf("https://sentry.io/api/0/projects/%v/%v/events/", sn.OrganizationSlug, sn.ProjectSlug)
req, err := http.NewRequest("GET", requestURL, nil)
if err != nil {
return err
}
authHeader := "Bearer " + sn.Token
req.Header.Add("Authorization", authHeader)
// by link ?
lastEventId := c.requestData.GetLastMessageId()
firstEvent := true
PageLoop:
for {
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
io.Copy(ioutil.Discard, resp.Body) // Read the body to free socket
return fmt.Errorf("Sentry: server respond with the code %v", resp.StatusCode)
}
var jsonEventList []json.RawMessage
err = json.NewDecoder(resp.Body).Decode(&jsonEventList)
if err != nil {
return err
}
for _, jsonEvent := range jsonEventList {
var e sentryEvent
err = json.Unmarshal(jsonEvent, &e)
if err != nil {
c.errChan <- err
continue
}
if lastEventId == e.EventID {
break PageLoop
}
parsedTime, err := time.Parse(time.RFC3339, e.DateCreated)
if err != nil {
c.errChan <- fmt.Errorf("%v | Event: %v", err, e)
continue
}
timestamp := uint64(parsedTime.UnixMilli())
// TODO: not to receive all the messages (use default integration timestamp)
if firstEvent { // TODO: reverse range?
c.requestData.SetLastMessageId(timestamp, e.EventID)
firstEvent = false
}
var sessionID uint64
var token string
for _, tag := range e.Tags {
if tag.Key == "openReplaySessionToken" {
token = tag.Value
break
}
if tag.Key == "asayer_session_id" {
sessionID, err = strconv.ParseUint(tag.Value, 10, 64)
break
}
}
if err != nil {
c.errChan <- err
continue
}
if token == "" && sessionID == 0 { // We can't felter them on request
continue
}
c.evChan <- &SessionErrorEvent{
SessionID: sessionID,
Token: token,
IntegrationEvent: &messages.IntegrationEvent{
Source: "sentry",
Timestamp: timestamp,
Name: e.Title,
Payload: string(jsonEvent),
},
}
}
// check link before parsing body?
linkHeader := resp.Header.Get("Link")
if linkHeader == "" {
return fmt.Errorf("No Link header found in the responce.")
}
pagInfo := strings.Split(linkHeader, ",")
if len(pagInfo) < 2 {
return fmt.Errorf("Link header format error. Got: '%v'", linkHeader)
}
nextLinkInfo := pagInfo[1]
if strings.Contains(nextLinkInfo, `results="false"`) {
break
}
if !strings.Contains(nextLinkInfo, `results="true"`) {
return fmt.Errorf("Link header format error. Results status not found. Got: '%v'", linkHeader)
}
nextLink := GetLinkFromAngularBrackets(nextLinkInfo)
req.URL, err = url.Parse(nextLink)
if err != nil {
return err
}
}
return nil
}