Add a Tag Name filter to the Incident Timeline API
What does this MR do and why?
Adds a 'Tag Name' filter to the Incident Timeline GraphQL API.
Query plan: !109293 (comment 1325355202)
Issue: #360009 (closed)
Screenshots or screen recordings
No visual changes.
How to set up and validate locally
Numbered steps to set up and validate the change are strongly suggested.
Set up data:
- Navigate to -> Monitor -> Incidents
- Create or edit an incident.
- Navigate to the Timeline tab.
- Add a few timeline items, including one with the tag 'Start Time'.
Query the API:
- Navigate to the graphql explorer
- Paste in the following query and data:
-
Click to expand Query
query timelineQueryWithTagFilter($fullPath: ID!, $incidentId: IssueID!, $tagName: String) { project(fullPath: $fullPath) { id incidentManagementTimelineEvents(incidentId: $incidentId, tagName: $tagName) { nodes { id note timelineEventTags { nodes { id name } } } } } }
-
Click to expand Query Variables
{ "fullPath": "flightjs/Flight (Project ID)", "incidentId": "gid://gitlab/Issue/<issue id", "tagName": "Start time" }
-
- Ensure the result includes the 'Start Time' incident timeline event.
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #360009 (closed)
Merge request reports
Activity
changed milestone to %15.9
assigned to @tristan.read
removed [deprecated] Accepting merge requests label
mentioned in issue gitlab-org/monitor/respond#193 (closed)
mentioned in issue gitlab-org/monitor/respond#194 (closed)
mentioned in issue gitlab-org/monitor/respond#195 (closed)
removed backend label
added 3879 commits
-
8763a620...3601a950 - 3879 commits from branch
master
-
8763a620...3601a950 - 3879 commits from branch
added 344 commits
-
3601a950...48b84384 - 344 commits from branch
master
-
3601a950...48b84384 - 344 commits from branch
added 2 commits
- A deleted user
added backend database databasereview pending labels
- A deleted user
added documentation label
added 2 commits
removed frontend label
- Resolved by Tristan Read
added 258 commits
-
b1f51206...8f32f272 - 245 commits from branch
master
- c58ec9d8 - Add search functionality to incident timeline resolver
- 8ac73862 - Fix rubocop errors
- db6b56dc - Refactor timeline tag list
- 077c3a17 - Add field to resolver [skip ci]
- 88e2c879 - Fix id type, generate docs [ci skip]
- 30671ef6 - Fix rubocop errors [ci skip]
- 56854203 - Use correct type [skip ci]
- 4a65d377 - Update graphql docs [skip ci]
- 91e78db4 - Use active record find method
- ff613088 - Check if params are present
- 5c2119a9 - Implement search by tag name in timeline finder
- ef47e536 - Fix rubocop errors [skip ci]
- 2ac397b6 - Remove local logging
Toggle commit list-
b1f51206...8f32f272 - 245 commits from branch
mentioned in issue gitlab-org/monitor/respond#200 (closed)
changed milestone to %15.10
added missed:15.9 label
mentioned in issue gitlab-org/monitor/respond#203 (closed)
added 2069 commits
-
2ac397b6...848a38e8 - 2056 commits from branch
master
- 848a38e8...35242b1c - 3 earlier commits
- 54936857 - Add field to resolver [skip ci]
- e6eab1ec - Fix id type, generate docs [ci skip]
- 7d0cc8cb - Fix rubocop errors [ci skip]
- c28678fc - Use correct type [skip ci]
- 5397cc89 - Update graphql docs [skip ci]
- 62086ade - Use active record find method
- a589adc6 - Check if params are present
- 44874fb7 - Implement search by tag name in timeline finder
- e4cac15e - Fix rubocop errors [skip ci]
- 3df069a9 - Remove local logging
Toggle commit list-
2ac397b6...848a38e8 - 2056 commits from branch
added 2 commits
added 2 commits
29 29 through: :timeline_event_tag_links 30 30 31 31 scope :order_occurred_at_asc_id_asc, -> { reorder(occurred_at: :asc, id: :asc) } 32 scope :with_tag_name, ->(tag_name) do Is there a naming convention for filters like this?
Edited by Tristan Read
- Resolved by Tristan Read
added 315 commits
-
029ed46e...1115a065 - 295 commits from branch
master
- 1115a065...a49c497c - 10 earlier commits
- 23807e91 - Implement search by tag name in timeline finder
- a122aead - Fix rubocop errors [skip ci]
- 4879d649 - Remove local logging
- 52d6ea87 - Add with_tags scope
- aa8aa5a4 - Fix rubocop error
- da7a9de6 - Use new timeline event scope
- d595cbfe - Fix rubocop errors
- bd529306 - Update scope name and remove comment
- aa116937 - Add tag name finder spec
- a4a3fad5 - [skip ci] add in-progress model specs
Toggle commit list-
029ed46e...1115a065 - 295 commits from branch
mentioned in issue gitlab-org/monitor/respond#204 (closed)
mentioned in issue gitlab-org/monitor/respond#205 (closed)
added 770 commits
-
a4a3fad5...43d6f585 - 750 commits from branch
master
- 43d6f585...fe2b6032 - 10 earlier commits
- 781e657e - Implement search by tag name in timeline finder
- aedcdd14 - Fix rubocop errors [skip ci]
- 45565f01 - Remove local logging
- 92185dff - Add with_tags scope
- 7947e81d - Fix rubocop error
- bf0ca6e3 - Use new timeline event scope
- c67b5376 - Fix rubocop errors
- f4e8d66b - Update scope name and remove comment
- 8d09a947 - Add tag name finder spec
- 0d78f4b6 - [skip ci] add in-progress model specs
Toggle commit list-
a4a3fad5...43d6f585 - 750 commits from branch
added 283 commits
-
0d78f4b6...e34cb724 - 263 commits from branch
master
- e34cb724...8a51773b - 10 earlier commits
- 563b6cd3 - Implement search by tag name in timeline finder
- fb2c41a2 - Fix rubocop errors [skip ci]
- 02a8eb98 - Remove local logging
- 33974d4c - Add with_tags scope
- 3d513df1 - Fix rubocop error
- 1c71807b - Use new timeline event scope
- cd8af854 - Fix rubocop errors
- dc7d0775 - Update scope name and remove comment
- 52f144fe - Add tag name finder spec
- 4e7819a1 - [skip ci] add in-progress model specs
Toggle commit list-
0d78f4b6...e34cb724 - 263 commits from branch
added 2 commits
14 14 required: true, 15 15 description: 'ID of the incident.' 16 16 17 argument :tag_name, 18 GraphQL::Types::String, 19 required: false, 20 description: 'Name of the tag to search on.', 21 default_value: nil - Comment on lines +17 to +21
Current behavior:
- Providing a tag name in the query will filter timeline events to those that are tagged with the name provided.
- It is not a 'contains' search, it requires an exact match.
- We could make this a 'contains' search. We could also make the filter case insensitive / trim whitespace if that's beneficial.
- To filter on multiple tags, the graphql query must be triggered twice. The UI calls for start time and end time events to selected.
- We could make this a 'multiple' search, e.g. providing an array of terms.
Query plan added here !109293 (comment 1325355202)
12 12 return ::IncidentManagement::TimelineEvent.none unless allowed? 13 13 14 14 collection = incident.incident_management_timeline_events 15 16 collection = collection.with_tag_name(params[:tag_name]) if params[:tag_name] Question Do you mind providing query plans for this new query?
See https://docs.gitlab.com/ee/development/database_review.html#queries
@splattael Thanks for the pointer, it's led to some great learning.
Regarding the query plan - I found the exact query (via
logs/database.log
) and ranexplain
on it locally and in database lab.Here are the the results:
Query
SELECT "incident_management_timeline_events".* FROM "incident_management_timeline_events" INNER JOIN "incident_management_timeline_event_tag_links" ON "incident_management_timeline_event_tag_links"."timeline_event_id" = "incident_management_timeline_events"."id" INNER JOIN "incident_management_timeline_event_tags" "timeline_event_tags" ON "timeline_event_tags"."id" = "incident_management_timeline_event_tag_links"."timeline_event_tag_id" WHERE "incident_management_timeline_events"."issue_id" = 451 AND "timeline_event_tags"."name" = 'Start time' ORDER BY "incident_management_timeline_events"."occurred_at" ASC, "incident_management_timeline_events"."id" ASC LIMIT 101
Explain plan (database lab)
Limit (cost=12.82..12.82 rows=1 width=377) (actual time=6.796..6.799 rows=0 loops=1) Buffers: shared hit=9 read=3 I/O Timings: read=6.742 write=0.000 -> Sort (cost=12.82..12.82 rows=1 width=377) (actual time=6.794..6.797 rows=0 loops=1) Sort Key: incident_management_timeline_events.occurred_at, incident_management_timeline_events.id Sort Method: quicksort Memory: 25kB Buffers: shared hit=9 read=3 I/O Timings: read=6.742 write=0.000 -> Nested Loop (cost=1.00..12.81 rows=1 width=377) (actual time=6.771..6.773 rows=0 loops=1) Buffers: shared hit=3 read=3 I/O Timings: read=6.742 write=0.000 -> Nested Loop (cost=0.56..9.35 rows=1 width=385) (actual time=6.771..6.772 rows=0 loops=1) Buffers: shared hit=3 read=3 I/O Timings: read=6.742 write=0.000 -> Index Scan using index_im_timeline_events_issue_id on public.incident_management_timeline_events (cost=0.42..3.80 rows=2 width=377) (actual time=6.770..6.771 rows=0 loops=1) Index Cond: (incident_management_timeline_events.issue_id = 451) Buffers: shared hit=3 read=3 I/O Timings: read=6.742 write=0.000 -> Index Only Scan using index_im_timeline_event_tags_on_tag_id_and_event_id on public.incident_management_timeline_event_tag_links (cost=0.14..2.76 rows=1 width=16) (actual time=0.000..0.000 rows=0 loops=0) Index Cond: (incident_management_timeline_event_tag_links.timeline_event_id = incident_management_timeline_events.id) Heap Fetches: 0 I/O Timings: read=0.000 write=0.000 -> Index Scan using incident_management_timeline_event_tags_pkey on public.incident_management_timeline_event_tags timeline_event_tags (cost=0.43..3.46 rows=1 width=8) (actual time=0.000..0.000 rows=0 loops=0) Index Cond: (timeline_event_tags.id = incident_management_timeline_event_tag_links.timeline_event_tag_id) Filter: (timeline_event_tags.name = 'Start time'::text) Rows Removed by Filter: 0 I/O Timings: read=0.000 write=0.000
Explain plan (local gdk)
Limit (cost=16.15..16.15 rows=1 width=173) (actual time=0.101..0.103 rows=2 loops=1) -> Sort (cost=16.15..16.15 rows=1 width=173) (actual time=0.099..0.100 rows=2 loops=1) Sort Key: incident_management_timeline_events.occurred_at, incident_management_timeline_events.id Sort Method: quicksort Memory: 25kB -> Nested Loop (cost=0.45..16.14 rows=1 width=173) (actual time=0.072..0.080 rows=2 loops=1) -> Nested Loop (cost=0.30..14.87 rows=7 width=181) (actual time=0.062..0.068 rows=2 loops=1) -> Index Scan using index_im_timeline_events_issue_id on incident_management_timeline_events (cost=0.15..3.18 rows=2 width=173) (actual time=0.028..0.036 rows=14 loops=1) Index Cond: (issue_id = 451) -> Index Scan using index_im_timeline_event_id on incident_management_timeline_event_tag_links (cost=0.15..5.78 rows=7 width=16) (actual time=0.002..0.002 rows=0 loops=14) Index Cond: (timeline_event_id = incident_management_timeline_events.id) -> Index Scan using incident_management_timeline_event_tags_pkey on incident_management_timeline_event_tags timeline_event_tags (cost=0.15..0.18 rows=1 width=8) (actual time=0.004..0.004 rows=1 loops=2) Index Cond: (id = incident_management_timeline_event_tag_links.timeline_event_tag_id) Filter: (name = 'Start time'::text) Planning Time: 0.459 ms Execution Time: 0.150 ms (15 rows)
Link to database lab result: https://console.postgres.ai/gitlab/gitlab-production-tunnel-pg12/sessions/16928/commands/57538
I'm not sure how valid the database lab results are. It's selecting events on a specific issue that I created locally, so the results will be empty. I see that I can do an update to add data to postgres.ai but I'll need to learn some more before trying this.
- Does this look good enough to send for database review?
- Do we have any projects in database lab that already have timeline events?
@tristan.read Would we always query with
issue_id
when querying the tag name? It doesn't seem we need a new index for that as I'd think the number of tags for incident won't be many, but I think we might need to add a new index if we need to query byimeline_event_tags.name
alone.@dskim_gitlab The planned UI would always use the
issue_id
, indeedI'm not sure what direct users of the API might do, but I doubt that it would be a common use case.
Here is an execution plan with actual production data - https://console.postgres.ai/gitlab/gitlab-production-tunnel-pg12/sessions/19201/commands/63391.
The plan is not ideal, and execution can be slow in some circumstances, but if we can assume that 1) An issue does not have many
incident_management_timeline_events
, and 2) timeline events does not have manyincident_management_timeline_event_tags
, which I think are both reasonable assumptions, I think we'll be fine.It's interesting that we have many millions of
incident_management_timeline_event_tags
, but very few records inincident_management_timeline_event_tag_links
, maybe because this is a new feature? That's interesting @krasio - I'd have guessed there would be a similar number of tags and links, since a link is what attaches a tag to a timeline event. Tags with no links would be 'orphans'. I'll ask one of the other backend devs on my team about this.
mentioned in issue gitlab-org/monitor/respond#215 (closed)
mentioned in issue #360009 (closed)
added 2167 commits
-
dfb3fce1...5b3c6931 - 2144 commits from branch
master
- 5b3c6931...6386c4b7 - 13 earlier commits
- 95c92e94 - Add with_tags scope
- 55f9e3f9 - Fix rubocop error
- 267ba865 - Use new timeline event scope
- f3298f90 - Fix rubocop errors
- 149cd48e - Update scope name and remove comment
- b532c5d8 - Add tag name finder spec
- f3c65ffa - [skip ci] add in-progress model specs
- f5f70b7a - [ci skip] remove extraneous spec setup data
- 8bd092b3 - [ci skip] Fix rubocop error
- 75ee5ccc - Fix timeline event spec
Toggle commit list-
dfb3fce1...5b3c6931 - 2144 commits from branch