Skip to content

Commit

Permalink
Fix error group instances (#8803)
Browse files Browse the repository at this point in the history
## Summary
The error groups are not setting the correct first and last instances

On search:
- First instance: `ErrorGroup.CreatedAt` -> min `ErrorObject.Timestamp`
- Last instance:  `ErrorGroup.UpdatedAt` -> max `ErrorObject.Timestamp`

On detail page
- First instance: missing -> min `ErrorObject.Timestamp`
- Last instance: missing -> max `ErrorObject.Timestamp`


https://www.loom.com/share/ec0409905c224529b5a642ea3ea9f489?sid=91e0bd44-7c9f-4b34-947d-4328dae80203

## How did you test this change?
1) View the error search page
2) View the dates on the search card
- [ ] Confirm the dates are correct
3) Click into an error
- [ ] confirm the first/last occurrences are correct



## Are there any deployment considerations?
Watch performance of `ErrorGroups` graphql query

## Does this work require review from our design team?
N/A
  • Loading branch information
SpennyNDaJets committed Jun 19, 2024
1 parent db025d3 commit 55f949a
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 23 deletions.
31 changes: 23 additions & 8 deletions backend/clickhouse/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,30 +378,45 @@ func (client *Client) QueryErrorGroupAggregateFrequency(ctx context.Context, pro
return items, err
}

func (client *Client) QueryErrorGroupOccurrences(ctx context.Context, projectId int, errorGroupId int) (*time.Time, *time.Time, error) {
type ErrorGroupOccurence struct {
FirstOccurrence time.Time
LastOccurrence time.Time
}

func (client *Client) QueryErrorGroupOccurrences(ctx context.Context, projectId int, errorGroupIds []int) (map[int]ErrorGroupOccurence, error) {
sb := sqlbuilder.NewSelectBuilder()
sql, args := sb.Select(`
ErrorGroupID,
min(Timestamp) as firstOccurrence,
max(Timestamp) as lastOccurrence`).
From("error_objects FINAL").
Where(sb.Equal("ProjectID", projectId)).
Where(sb.Equal("ErrorGroupID", errorGroupId)).
Where(sb.In("ErrorGroupID", errorGroupIds)).
GroupBy("ErrorGroupID").
BuildWithFlavor(sqlbuilder.ClickHouse)

rows, err := client.conn.Query(ctx, sql, args...)
if err != nil {
return nil, nil, err
return nil, err
}

var firstOccurrence time.Time
var lastOccurrence time.Time
occurancesByErrorGroup := map[int]ErrorGroupOccurence{}
for rows.Next() {
if err := rows.Scan(&firstOccurrence, &lastOccurrence); err != nil {
return nil, nil, err
var errorGroupId int64
var firstOccurrence time.Time
var lastOccurrence time.Time

if err := rows.Scan(&errorGroupId, &firstOccurrence, &lastOccurrence); err != nil {
return nil, err
}

occurancesByErrorGroup[int(errorGroupId)] = ErrorGroupOccurence{
FirstOccurrence: firstOccurrence,
LastOccurrence: lastOccurrence,
}
}

return &firstOccurrence, &lastOccurrence, nil
return occurancesByErrorGroup, nil
}

func (client *Client) QueryErrorGroupTags(ctx context.Context, projectId int, errorGroupId int) ([]*modelInputs.ErrorGroupTagAggregation, error) {
Expand Down
27 changes: 24 additions & 3 deletions backend/private-graph/graph/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,27 @@ func (r *Resolver) SetErrorFrequenciesClickhouse(ctx context.Context, projectID
return nil
}

func (r *Resolver) SetErrorGroupOccurrences(ctx context.Context, projectID int, errorGroups []*model.ErrorGroup) error {
errorGroupIDs := make([]int, len(errorGroups))
for i, eg := range errorGroups {
errorGroupIDs[i] = eg.ID
}

occurencesByErrorGroup, err := r.ClickhouseClient.QueryErrorGroupOccurrences(ctx, projectID, errorGroupIDs)
if err != nil {
return err
}

for _, eg := range errorGroups {
if occurences, ok := occurencesByErrorGroup[eg.ID]; ok {
eg.FirstOccurrence = &occurences.FirstOccurrence
eg.LastOccurrence = &occurences.LastOccurrence
}
}

return nil
}

type SavedSegmentParams struct {
Query string
}
Expand Down Expand Up @@ -648,12 +669,12 @@ func (r *Resolver) doesAdminOwnErrorGroup(ctx context.Context, errorGroupSecureI
return eg, true, nil
}

func (r *Resolver) loadErrorGroupFrequenciesClickhouse(ctx context.Context, eg *model.ErrorGroup) error {
func (r *Resolver) loadErrorGroupFrequenciesClickhouse(ctx context.Context, projectID int, errorGroups []*model.ErrorGroup) error {
var err error
if eg.FirstOccurrence, eg.LastOccurrence, err = r.ClickhouseClient.QueryErrorGroupOccurrences(ctx, eg.ProjectID, eg.ID); err != nil {
if err = r.SetErrorGroupOccurrences(ctx, projectID, errorGroups); err != nil {
return e.Wrap(err, "error querying error group occurrences")
}
if err := r.SetErrorFrequenciesClickhouse(ctx, eg.ProjectID, []*model.ErrorGroup{eg}, 7); err != nil {
if err := r.SetErrorFrequenciesClickhouse(ctx, projectID, errorGroups, ErrorGroupLookbackDays); err != nil {
return e.Wrap(err, "error querying error group frequencies")
}
return nil
Expand Down
9 changes: 3 additions & 6 deletions backend/private-graph/graph/schema.resolvers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5220,7 +5220,7 @@ func (r *queryResolver) ErrorGroups(ctx context.Context, projectID int, count in
}

if len(results) > 0 {
if err := r.SetErrorFrequenciesClickhouse(ctx, project.ID, results, ErrorGroupLookbackDays); err != nil {
if err := r.loadErrorGroupFrequenciesClickhouse(ctx, project.ID, results); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -5290,7 +5290,7 @@ func (r *queryResolver) ErrorGroup(ctx context.Context, secureID string, useClic
if eg.UpdatedAt.Before(retentionDate) {
return nil, e.New("no new error instances after the workspace's retention date")
}
if err := r.SetErrorFrequenciesClickhouse(ctx, eg.ProjectID, []*model.ErrorGroup{eg}, ErrorGroupLookbackDays); err != nil {
if err := r.loadErrorGroupFrequenciesClickhouse(ctx, eg.ProjectID, []*model.ErrorGroup{eg}); err != nil {
return nil, err
}
return eg, err
Expand Down Expand Up @@ -6032,7 +6032,7 @@ func (r *queryResolver) DailyErrorFrequency(ctx context.Context, projectID int,
if err != nil {
return nil, err
}
if err := r.loadErrorGroupFrequenciesClickhouse(ctx, errGroup); err != nil {
if err := r.loadErrorGroupFrequenciesClickhouse(ctx, projectID, []*model.ErrorGroup{errGroup}); err != nil {
return nil, err
}

Expand All @@ -6047,9 +6047,6 @@ func (r *queryResolver) DailyErrorFrequency(ctx context.Context, projectID int,
return dists, nil
}

if err := r.SetErrorFrequenciesClickhouse(ctx, projectID, []*model.ErrorGroup{errGroup}, dateOffset); err != nil {
return nil, e.Wrap(err, "error setting error frequencies")
}
return errGroup.ErrorFrequency, nil
}

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/graph/generated/hooks.tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/src/graph/generated/operations.tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion frontend/src/graph/operators/query.gql
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,8 @@ query GetErrorGroups(
type
event
state
state
first_occurrence
last_occurrence
snoozed_until
environments
stack_trace
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/pages/ErrorsV2/ErrorFeedCard/ErrorFeedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ export const ErrorFeedCard = ({ errorGroup, onClick }: Props) => {
error_secure_id?: string
}>()
const body = getErrorBody(errorGroup?.event)
const createdDate = formatErrorGroupDate(errorGroup?.created_at)
const updatedDate = formatErrorGroupDate(errorGroup?.updated_at)
const firstInstance = formatErrorGroupDate(
errorGroup?.first_occurrence || errorGroup?.created_at,
)
const lastInstance = formatErrorGroupDate(
errorGroup?.last_occurrence || errorGroup?.updated_at,
)

const { totalCount, userCount } = getErrorGroupStats(errorGroup)
const snoozed =
Expand Down Expand Up @@ -172,14 +176,14 @@ export const ErrorFeedCard = ({ errorGroup, onClick }: Props) => {
</Box>
<Box display="flex" gap="4" alignItems="center">
<Tag shape="basic" kind="secondary">
{updatedDate}
{lastInstance}
</Tag>
<Tag
shape="basic"
kind="secondary"
iconLeft={<IconSolidSparkles size={12} />}
>
{createdDate}
{firstInstance}
</Tag>
</Box>
</Box>
Expand Down

0 comments on commit 55f949a

Please sign in to comment.