Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Log TimelinePanel debugging info when opening the bug report modal #8502

Merged
merged 13 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/components/structures/TimelinePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@ if (DEBUG) {
debuglog = logger.log.bind(console, "TimelinePanel debuglog:");
}

/**
* Iterate across all of the timelineSets and timelines inside to expose all of
* the event IDs contained inside.
*
* @return An event ID list for every timeline in every timelineSet
*/
function serializeEventIdsFromTimelineSets(timelineSets): { [key: string]: string[] }[] {
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
const serializedEventIdsInTimelineSet = timelineSets.map((timelineSet) => {
const timelineMap = {};

const timelines = timelineSet.getTimelines();
const liveTimeline = timelineSet.getLiveTimeline();

timelines.forEach((timeline, index) => {
// Add a special label when it is the live timeline so we can tell
// it apart from the others
const isLiveTimeline = timeline === liveTimeline;
timelineMap[isLiveTimeline ? 'liveTimeline' : `${index}`] = timeline.getEvents().map(ev => ev.getId());
});

return timelineMap;
});

return serializedEventIdsInTimelineSet;
}

interface IProps {
// The js-sdk EventTimelineSet object for the timeline sequence we are
// representing. This may or may not have a room, depending on what it's
Expand Down Expand Up @@ -294,6 +320,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
cli.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
cli.on(MatrixEventEvent.Replaced, this.onEventReplaced);
cli.on(ClientEvent.Sync, this.onSync);
cli.on(ClientEvent.DumpDebugLogs, this.onDumpDebugLogs);
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
}

// TODO: [REACT-WARNING] Move into constructor
Expand Down Expand Up @@ -369,9 +396,57 @@ class TimelinePanel extends React.Component<IProps, IState> {
client.removeListener(MatrixEventEvent.Replaced, this.onEventReplaced);
client.removeListener(MatrixEventEvent.VisibilityChange, this.onEventVisibilityChange);
client.removeListener(ClientEvent.Sync, this.onSync);
client.removeListener(ClientEvent.Sync, this.onDumpDebugLogs);
}
}

private onDumpDebugLogs = (): void => {
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
const roomId = this.props.timelineSet.room.roomId;
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
// This includes state and hidden events which we don't render
const eventIdList = this.state.events.map((ev) => ev.getId());

// Get the list of actually rendered events seen in the DOM.
let renderedEventIds;
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
const messagePanel = this.messagePanel.current;
if (messagePanel) {
const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as HTMLElement;
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
if (messagePanelNode) {
const actuallyRenderedEvents = messagePanelNode.querySelectorAll('[data-event-id]');
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
renderedEventIds = [...actuallyRenderedEvents].map((renderedEvent) => {
return renderedEvent.getAttribute('data-txn-id') || renderedEvent.getAttribute('data-event-id');
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
});
}
}

let serializedEventIdsFromTimelineSets;
let serializedEventIdsFromThreadsTimelineSets;
const serializedThreadsMap = {};
const client = MatrixClientPeg.get();
if (client) {
const room = client.getRoom(roomId);
const timelineSets = room.getTimelineSets();
const threadsTimelineSets = room.threadsTimelineSets;

serializedEventIdsFromTimelineSets = serializeEventIdsFromTimelineSets(timelineSets);
serializedEventIdsFromThreadsTimelineSets = serializeEventIdsFromTimelineSets(threadsTimelineSets);

room.getThreads().forEach((thread) => {
serializedThreadsMap[thread.id] = thread.events.map(ev => ev.getId());
});
}

logger.debug(
`TimelinePanel(${this.context.timelineRenderingType}): Debugging info for ${roomId}\n` +
`\tevents(${eventIdList.length})=${JSON.stringify(eventIdList)}\n` +
`\trenderedEventIds(${renderedEventIds ? renderedEventIds.length : 0})=` +
`${JSON.stringify(renderedEventIds)}\n` +
`\tserializedEventIdsFromTimelineSets=${JSON.stringify(serializedEventIdsFromTimelineSets)}\n` +
`\tserializedEventIdsFromThreadsTimelineSets=` +
`${JSON.stringify(serializedEventIdsFromThreadsTimelineSets)}\n` +
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confusingly, room.threadsTimelineSets-> serializedEventIdsFromThreadsTimelineSets are only created and used for the ThreadPanel where threads are listed not an individual thread.

Thought it was relevant to log but could also be dropped or moved to ThreadPanel in the future instead.

`\tserializedThreadsMap=${JSON.stringify(serializedThreadsMap)}`,
);
Copy link
Contributor Author

@MadLittleMods MadLittleMods May 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These logs look like:

TimelinePanel(Room): Debugging info for !ifHvTosMVvhbsCtKis:my.synapse.server
	events(12)=["$DTQzlOAB9zGXQ--Y9zPo9YK0KdMEeIMJL9kFPf9QE0U","$j_i8bX6Tid06awSNOeWCyYqst0wSCPJGguSX9iUGSWk","$6ZR11pNK8fPt5_TzwwGZEgopaJLgdEChB55ivlIqfDo","$lmgREseqLT0SINbDnE7hpkccIcuWGRUNh7g1utnaq0c","$d9lV1zkkxJtoJzMyvDVa9LyXZA7YwYhUlm9n30jqNI8","$pwd02EGS2HDdvwVn5EKaQEqANf49QFB-OJiOpGkCMB8","$QO5e_sIq83DM8JySRiB0-32lwVrNpReUv33UZ8rGRGo","$Rhe9LSKBgf49ejxKNN7N5ve2Nzqykr0EAtq4hnKMWiA","$t14H6JO0200h9z6_BYRykEDWvZhhNTTt50t5Ex2g_2o","$WeO6B-ea3FxTokjFixc0UghC0osRSP6vykVVwhHbJhw","$BWFwOdh4QmmUpEHNdjAYXEXM5jue3ZcTtLKhc7YIusw","$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY"]
	renderedEventIds(6)=["$DTQzlOAB9zGXQ--Y9zPo9YK0KdMEeIMJL9kFPf9QE0U","$Rhe9LSKBgf49ejxKNN7N5ve2Nzqykr0EAtq4hnKMWiA","$t14H6JO0200h9z6_BYRykEDWvZhhNTTt50t5Ex2g_2o","$WeO6B-ea3FxTokjFixc0UghC0osRSP6vykVVwhHbJhw","$BWFwOdh4QmmUpEHNdjAYXEXM5jue3ZcTtLKhc7YIusw","$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY"]
	serializedEventIdsFromTimelineSets=[{"liveTimeline":["$DTQzlOAB9zGXQ--Y9zPo9YK0KdMEeIMJL9kFPf9QE0U","$j_i8bX6Tid06awSNOeWCyYqst0wSCPJGguSX9iUGSWk","$6ZR11pNK8fPt5_TzwwGZEgopaJLgdEChB55ivlIqfDo","$lmgREseqLT0SINbDnE7hpkccIcuWGRUNh7g1utnaq0c","$d9lV1zkkxJtoJzMyvDVa9LyXZA7YwYhUlm9n30jqNI8","$pwd02EGS2HDdvwVn5EKaQEqANf49QFB-OJiOpGkCMB8","$QO5e_sIq83DM8JySRiB0-32lwVrNpReUv33UZ8rGRGo","$Rhe9LSKBgf49ejxKNN7N5ve2Nzqykr0EAtq4hnKMWiA","$t14H6JO0200h9z6_BYRykEDWvZhhNTTt50t5Ex2g_2o","$WeO6B-ea3FxTokjFixc0UghC0osRSP6vykVVwhHbJhw","$BWFwOdh4QmmUpEHNdjAYXEXM5jue3ZcTtLKhc7YIusw","$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY"]}]
	serializedEventIdsFromThreadsTimelineSets=[]
	serializedThreadsMap={"$BWFwOdh4QmmUpEHNdjAYXEXM5jue3ZcTtLKhc7YIusw":[],"$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY":["$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY","$c-6O4zVYEpEuXU5bWfqFtJXXKXARxJDn64BO_9HnP4A"]}
	
TimelinePanel(Thread): Debugging info for !ifHvTosMVvhbsCtKis:my.synapse.server
	events(2)=["$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY","$c-6O4zVYEpEuXU5bWfqFtJXXKXARxJDn64BO_9HnP4A"]
	renderedEventIds(2)=["$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY","$c-6O4zVYEpEuXU5bWfqFtJXXKXARxJDn64BO_9HnP4A"]
	serializedEventIdsFromTimelineSets=[{"liveTimeline":["$DTQzlOAB9zGXQ--Y9zPo9YK0KdMEeIMJL9kFPf9QE0U","$j_i8bX6Tid06awSNOeWCyYqst0wSCPJGguSX9iUGSWk","$6ZR11pNK8fPt5_TzwwGZEgopaJLgdEChB55ivlIqfDo","$lmgREseqLT0SINbDnE7hpkccIcuWGRUNh7g1utnaq0c","$d9lV1zkkxJtoJzMyvDVa9LyXZA7YwYhUlm9n30jqNI8","$pwd02EGS2HDdvwVn5EKaQEqANf49QFB-OJiOpGkCMB8","$QO5e_sIq83DM8JySRiB0-32lwVrNpReUv33UZ8rGRGo","$Rhe9LSKBgf49ejxKNN7N5ve2Nzqykr0EAtq4hnKMWiA","$t14H6JO0200h9z6_BYRykEDWvZhhNTTt50t5Ex2g_2o","$WeO6B-ea3FxTokjFixc0UghC0osRSP6vykVVwhHbJhw","$BWFwOdh4QmmUpEHNdjAYXEXM5jue3ZcTtLKhc7YIusw","$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY"]}]
	serializedEventIdsFromThreadsTimelineSets=[]
	serializedThreadsMap={"$BWFwOdh4QmmUpEHNdjAYXEXM5jue3ZcTtLKhc7YIusw":[],"$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY":["$VknYvjxNw2HKifHp_8C5F_WqDMXBTfdDYYT3-AVnNhY","$c-6O4zVYEpEuXU5bWfqFtJXXKXARxJDn64BO_9HnP4A"]}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any other info that would be useful to have?

};

private onMessageListUnfillRequest = (backwards: boolean, scrollToken: string): void => {
// If backwards, unpaginate from the back (i.e. the start of the timeline)
const dir = backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS;
Expand Down
10 changes: 10 additions & 0 deletions src/components/views/dialogs/BugReportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ limitations under the License.

import React from 'react';

import { MatrixClientPeg } from '../../../MatrixClientPeg';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
Expand Down Expand Up @@ -65,6 +66,15 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
downloadProgress: null,
};
this.unmounted = false;

const client = MatrixClientPeg.get();
// Get all of the extra info dumped to the console when someone is about
// to send debug logs. Since this is a fire and forget action, we do
// this when the bug report dialog is opened instead of when we submit
// logs because we have no signal to know when all of the various
// components have finished logging. Someone could potentially send logs
// before we fully dump everything but it's probably unlikely.
client.dumpDebugLogs();
}

public componentWillUnmount() {
Expand Down
4 changes: 4 additions & 0 deletions src/components/views/rooms/EventTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,8 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
"data-has-reply": !!replyChain,
"data-layout": this.props.layout,
"data-self": isOwnEvent,
"data-txn-id": this.props.mxEvent.getTxnId(),
"data-event-id": this.props.mxEvent.getId(),
"onMouseEnter": () => this.setState({ hover: true }),
"onMouseLeave": () => this.setState({ hover: false }),
}, [
Expand Down Expand Up @@ -1437,6 +1439,8 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
"data-scroll-tokens": scrollToken,
"data-layout": this.props.layout,
"data-self": isOwnEvent,
"data-txn-id": this.props.mxEvent.getTxnId(),
"data-event-id": this.props.mxEvent.getId(),
"data-has-reply": !!replyChain,
"onMouseEnter": () => this.setState({ hover: true }),
"onMouseLeave": () => this.setState({ hover: false }),
Expand Down