Repository navigation
feat(analytics): print session events and participant sessions under --experimental-auth - #1024
Merged
Merged
Conversation
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 9, 2026 02:57
ef763a7 to
77c654f
Compare
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
2 times, most recently
from
October 9, 2026 05:11
32f6772 to
279bb7d
Compare
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 9, 2026 05:11
77c654f to
1663a2f
Compare
Topherhindman
marked this pull request as ready for review
October 9, 2026 06:27
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
from
October 9, 2026 20:26
279bb7d to
bbfc89f
Compare
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
2 times, most recently
from
October 9, 2026 20:50
d8e9433 to
bcb53de
Compare
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
from
October 9, 2026 20:50
bbfc89f to
a17eb17
Compare
This was referenced Oct 9, 2026
rektdeckard
approved these changes
Oct 10, 2026
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 10, 2026 03:11
bcb53de to
ae6a1dd
Compare
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
2 times, most recently
from
October 10, 2026 03:12
411b38b to
79dae47
Compare
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 10, 2026 03:12
ae6a1dd to
2d0e47e
Compare
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
from
October 10, 2026 03:48
79dae47 to
9b007b1
Compare
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 10, 2026 03:48
2d0e47e to
9c1422c
Compare
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
from
October 10, 2026 04:21
9b007b1 to
39ae30b
Compare
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
2 times, most recently
from
October 10, 2026 04:37
2759435 to
9eb6d33
Compare
Topherhindman
force-pushed
the
devx-798-cli-session-metrics
branch
2 times, most recently
from
October 10, 2026 04:53
0eb7b58 to
d73b173
Compare
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 10, 2026 04:53
9eb6d33 to
e200807
Compare
Picks up ListSessionEvents as the server now serves it: the request filters by repeated types (AnalyticsEventType names), a participantSessionId (PA_...) and a sortOrder, and pages by keyset cursor with no total. Each event gains the participant session it is about, and its payload is the server's allowlist of fields, which no longer includes an API call's twirpErrorMessage. With a participantSessionId and no types, the read defaults to the eleven event types the dashboard's participant events table shows, track events included, rather than the session's seven. Also picks up the participants change: each ParticipantInfo carries its participant sessions, at most 50, one per connection, each with its participantSessionId (was participantId), client (OS, browser, device, SDK, connection type and time), location, region and duration. ParticipantInfo loses roomId, and GetParticipant and its ParticipantDetail are gone. And the session list row loses bandwidthIn, bandwidthOut and connectionSeconds: the server never filled them on list rows, and GetSession's detail still carries all three. Nothing hand-written reads the removed fields or calls the removed RPC (the session renderer reads bandwidth and connection time from the detail, and the legacy analytics command decodes its own response type), so only oapi.gen.go changes. Generated from livekit/public-api-server@6e037c6
The Public API now returns each participant with its participant sessions, one per connection, each with the client it connected from. `lk analytics session participant list` and `lk analytics session get` print them in a second table after the participants: the participant's identity, the participant session id (PA_...), when it joined and left, how long it lasted, the client (OS, browser, device model and SDK version, each only when reported), the transport and how long it took to connect, and the location. A participant whose participant sessions couldn't be read has no rows there; with none at all the table is left out. --json still prints the API's rows as sent, participant sessions nested.
ListSessionEvents returns one page of a session's events, such as participants joining and leaving or tracks being published, and the cursor for the next. EventOptions embeds PageOptions and adds the types to keep, one participant session to follow and the sort order. Types are friendly names: LiveKit's analytics event types in lowercase, such as participant_joined or track_published, which EventTypeNames lists and EventTypeName makes from the API's. Validate rejects an unknown type, with the names it knows, an unknown sort order, a negative limit, or a participant session id that doesn't start with PA_ (an identity passed by mistake) before any request is sent. Events are the generated type, their allowlisted payload marshalling back to the API's own JSON. An unknown session is NotFound.
`lk analytics session events SESSION_ID` prints a page of the session's
events, one line per event: its time to the millisecond, its type by
its friendly name, the participant identity and participant session
(PA_...) it is about, or dashes for a room event or an API call, and
its payload as key=value pairs sorted by key, clipped on a line. --json
prints {items, nextCursor} with the events as the API sent them.
With no --type it prints the dashboard's seven defaults. --type is
repeatable and takes the API's event types in lowercase, such as
track_published; an unknown one fails before the project lookup and
lists the names it knows. --participant takes a participant session id,
as `session participant list` now prints it, and refuses an identity.
--sort-order asc|desc orders by time, oldest first by default. --limit
(default 50, the server's page size) and a hidden --cursor page through
it, and a next page says to re-run with its --cursor: the user's own
command already repeats the types, participant session and order a
cursor was made for.
An empty page says why: no events of the types or for the participant
session asked for, none kept (events last 60 days), or no more pages.
An unknown session says there's no such session in the project, and a
permission denial says the user doesn't have access to the project,
through sessionReadError. Events are a READ-level read with no user
data recording gate, so there is no recording-off case.
Only the Public API serves session events, so the command runs only
under --experimental-auth, through sessionRead, with the signed-in
user's session token, and refuses to run otherwise before reading its
arguments.
…ipant's help --participant's help pointed at `session participant list` without the `lk analytics` prefix. It now names the full command, like the events description and other lk hints.
The server's API_CALL payload allowlist no longer includes twirpErrorMessage, so the events render fixture no longer sends it.
… eleven With a participant session and no types, the server now returns the eleven event types the dashboard's participant events table shows, track events included, not the session's seven. The events command's description, its --type and --participant help, and EventOptions.Types now say so.
…ssions An event's participant identity, and payload values such as a participant's name or metadata, are what a participant chose, and the events read printed them as they came, so in a terminal an escape sequence in one could set the window title or clear the screen. The same went for what a participant's client reported about itself in the participant sessions table: its OS, browser, device, SDK version and connection type. The identity and participant session id now go through dashText, and are measured after stripping so the payloads still line up. payloadValue strips a value's control characters before deciding whether to quote it; a value it prints as JSON has them escaped already, but loses any DEL or C1 control too. The participant sessions table runs its identity, participant session id, client fields, connection type and location through dashText or oneLine.
Topherhindman
force-pushed
the
devx-800-cli-participant-sessions-events
branch
from
October 10, 2026 05:03
e200807 to
0a431da
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes DEVX-800
Stacked on #1023.
Depends on livekit/public-api-server#56.
lk analytics session events SESSION_IDprints a page of a session's events, such as participants joining and leaving or tracks being published.lk analytics session participant listandlk analytics session getnow also print each participant's participant sessions, one per connection, with the client it connected from. Both run only under--experimental-auth.What changed
Regenerated client (
chore(public)):oapi.gen.gois regenerated from livekit/public-api-server@6e037c6, livekit/public-api-server#56's merge commit onmain. It picks up three server changes:ListSessionEventsfilters by repeatedtypes(AnalyticsEventTypenames), aparticipantSessionId(PA_...) and asortOrder, and pages by keyset cursor with no total. Each event names the participant session it's about, and its payload is the server's allowlist of fields, which no longer includes an API call'stwirpErrorMessage. With aparticipantSessionIdand no types, the read defaults to the eleven types the dashboard's participant events table shows, track events included.ParticipantInfocarries its participant sessions, at most 50, one per connection. Each has itsparticipantSessionId, client (OS, browser, device, SDK, connection type and time), location, region and duration.ParticipantInfolosesroomId, andGetParticipantis gone.bandwidthIn,bandwidthOutandconnectionSeconds. The server never filled them on list rows, andGetSession's detail still carries all three.Nothing hand-written reads the removed fields or calls the removed RPC, so only
oapi.gen.gochanges.Client (
feat(public)):ListSessionEventsreturns one page of a session's events and the cursor for the next.EventOptionsembedsPageOptionsand adds the types to keep, one participant session to follow, and the sort order.participant_joinedortrack_published.EventTypeNameslists them, andEventTypeNamemakes one from the API's.Validaterejects an unknown type (listing the names it knows), an unknown sort order, a negative limit, or a participant session id that doesn't start withPA_, before any request is sent. That last one catches an identity passed by mistake.Command (
feat(analytics)):session participant listandsession getprint a second table after the participants. It shows the identity, the participant session id, when it joined and left, how long it lasted, the client (OS, browser, device model and SDK version, each only when reported), the transport and how long it took to connect, and the location. A participant whose participant sessions couldn't be read has no rows there. With none at all, the table is left out.--jsonstill prints the API's rows as sent, participant sessions nested.key=valuepairs sorted by key, clipped on a line.--jsonprints{items, nextCursor}with the events as the API sent them.--type, the command prints the dashboard's seven defaults:participant_joined,participant_left,participant_active,participant_resumed,room_created,room_endedandapi_call. With--participantand no--type, it prints the dashboard's eleven participant types: the four participant events plustrack_muted,track_unmuted,track_published,track_unpublished,track_subscribed,track_subscribe_requestedandtrack_subscribe_failed.--typeis repeatable. An unknown one fails before the project lookup and lists the names it knows.--participanttakes a participant session id, aslk analytics session participant listnow prints it, and refuses an identity.--sort-order asc|descorders by time, oldest first by default. The next-page hint says to re-run with its--cursor. The user's own command already repeats the types, participant session and order the cursor was made for.sessionReadError: an unknown session says there's no such session in the project, and names the project, and a permission denial says the user doesn't have access to the project. Events are a read-level read with no user data recording gate, so there's no recording-off case.--experimental-auth, throughsessionRead.Usage
--limitdefaults to 50, the server's page size.--cursoris hidden.The participant sessions table that
session participant listandsession getprint after the participants:Since review
Testing
go build ./...,go vet ./pkg/... ./cmd/lk/andgo test ./pkg/... ./cmd/lk/pass on every commit.pkg/public:TestListSessionEvents,TestSessionEventJSON,TestListSessionEventsRejectsBadOptions,TestEventTypeNamesandTestListSessionEventsUnknownSession.pkg/public/render:TestSessionParticipantsPageNoSessions,TestSessionEventsText,TestEventPayloadClips,TestSessionEventsEmptyandTestSessionEventsJSON.TestSessionDetailTextandTestSessionParticipantsPagenow also check the participant sessions table.cmd/lk:TestSessionEventsCommand,TestSessionEventsRequiresExperimentalAuth,TestEventOptions(an identity passed to--participantis refused),TestFetchSessionEvents(each empty-page reason),TestFetchSessionEventsJSONandTestFetchSessionEventsErrors.job_entrypoint's span events, which these reads return. Metrics are the known exception: the aggregator files several token and TTS series under one name, which the dashboard avoids by deriving usage from the transcript and traces.Not in this PR
lk analytics session participant get: there isn't one.lk room participantcovers looking up one participant.