Skip to content

Commit

Permalink
msglist: Hasty logging code, for long waits with placeholders.
Browse files Browse the repository at this point in the history
In steady state, these changes should be reverted or structured a
bit better; it feels a bit haphazard.

If the placeholders are still visible after 10 seconds, send a log
to Sentry with all the events the WebView has received, with
timestamps of receipt. Redact any `auth` fields by replacing the
value with "redacted", and redact any `content` fields by extracting
just the opening tag for the "message-loading" div so we can see if
it has the "hidden" class.

But we want to debug #4156 ASAP,

[1]: https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/.23M4156.20Message.20List.20placeholders/near/921700
  • Loading branch information
chrisbobbe committed Jul 1, 2020
1 parent d345d71 commit aef73e6
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 0 deletions.
158 changes: 158 additions & 0 deletions src/webview/js/generatedEs3.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,91 @@ export default `
var compiledWebviewJs = (function (exports) {
'use strict';
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
var inlineApiRoutes = ['^/user_uploads/', '^/thumbnail$', '^/avatar/'].map(function (r) {
return new RegExp(r);
});
Expand Down Expand Up @@ -127,6 +212,73 @@ var compiledWebviewJs = (function (exports) {
return true;
};
var isTrackingLongLoad = true;
var eventsDuringLongLoad = [];
var logLongLoad = function logLongLoad() {
if (eventsDuringLongLoad === null) {
throw new Error();
}
var loggableEvents = eventsDuringLongLoad.map(function (eventWithTimestamp) {
var placeholdersDivTagFromContent = function placeholdersDivTagFromContent(content) {
var match = new RegExp('<div id="message-loading" class="(?:hidden)?">').exec(content);
return match !== null ? match[0] : null;
};
var content = eventWithTimestamp.content,
auth = eventWithTimestamp.auth,
rest = _objectWithoutProperties(eventWithTimestamp, ["content", "auth"]);
switch (eventWithTimestamp.type) {
case 'content':
{
return _objectSpread2({}, rest, {
auth: 'redacted',
content: placeholdersDivTagFromContent(eventWithTimestamp.content)
});
}
case 'read':
case 'ready':
case 'fetching':
return rest;
case 'typing':
{
return _objectSpread2({}, rest, {
content: placeholdersDivTagFromContent(eventWithTimestamp.content)
});
}
default:
return {
type: eventWithTimestamp.type,
timestamp: eventWithTimestamp.timestamp
};
}
});
sendMessage({
type: 'warn',
details: {
loggableEvents: loggableEvents
}
});
};
var maybeLogLongLoad = function maybeLogLongLoad() {
var placeholdersDiv = document.getElementById('message-loading');
if (placeholdersDiv && !placeholdersDiv.classList.contains('hidden')) {
logLongLoad();
}
isTrackingLongLoad = false;
eventsDuringLongLoad = null;
};
setTimeout(maybeLogLongLoad, 10000);
var showHideElement = function showHideElement(elementId, show) {
var element = document.getElementById(elementId);
Expand Down Expand Up @@ -479,6 +631,12 @@ var compiledWebviewJs = (function (exports) {
var updateEvents = JSON.parse(decodedData);
updateEvents.forEach(function (uevent) {
eventUpdateHandlers[uevent.type](uevent);
if (isTrackingLongLoad && eventsDuringLongLoad !== null) {
eventsDuringLongLoad.push(_objectSpread2({}, uevent, {
timestamp: Date.now()
}));
}
});
scrollEventsDisabled = false;
};
Expand Down
69 changes: 69 additions & 0 deletions src/webview/js/js.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* @flow strict-local */
/* eslint-disable no-useless-return */
import type { Auth } from '../../types';
import type { JSONable } from '../../utils/jsonable';
import type {
WebViewUpdateEvent,
WebViewUpdateEventContent,
Expand All @@ -10,6 +11,7 @@ import type {
WebViewUpdateEventMessagesRead,
} from '../webViewHandleUpdates';
import type { MessageListEvent } from '../webViewEventHandlers';
import { ensureUnreachable } from '../../types';

import rewriteImageUrls from './rewriteImageUrls';

Expand Down Expand Up @@ -156,6 +158,66 @@ window.onerror = (message: string, source: string, line: number, column: number,
return true;
};

let isTrackingLongLoad = true;
let eventsDuringLongLoad: Array<{ ...WebViewUpdateEvent, timestamp: number }> | null = [];

const logLongLoad = () => {
if (eventsDuringLongLoad === null) {
throw new Error();
}
const loggableEvents: JSONable[] = eventsDuringLongLoad.map(eventWithTimestamp => {
const placeholdersDivTagFromContent = (content: string) => {
const match = new RegExp('<div id="message-loading" class="(?:hidden)?">').exec(content);
return match !== null ? match[0] : null;
};
// $FlowFixMe (some events don't have content or auth)
const { content, auth, ...rest } = eventWithTimestamp; /* eslint-disable-line no-unused-vars */
switch (eventWithTimestamp.type) {
case 'content': {
return {
...rest,
auth: 'redacted',
content: placeholdersDivTagFromContent(eventWithTimestamp.content),
};
}
case 'read':
case 'ready':
case 'fetching':
return rest;
case 'typing': {
return {
...rest,
content: placeholdersDivTagFromContent(eventWithTimestamp.content),
};
}
default:
ensureUnreachable(eventWithTimestamp);
return {
type: eventWithTimestamp.type,
timestamp: eventWithTimestamp.timestamp,
};
}
});

sendMessage({
type: 'warn',
details: {
loggableEvents,
},
});
};

const maybeLogLongLoad = () => {
const placeholdersDiv = document.getElementById('message-loading');
if (placeholdersDiv && !placeholdersDiv.classList.contains('hidden')) {
logLongLoad();
}
isTrackingLongLoad = false;
eventsDuringLongLoad = null;
};

setTimeout(maybeLogLongLoad, 10000);

const showHideElement = (elementId: string, show: boolean) => {
const element = document.getElementById(elementId);
if (element) {
Expand Down Expand Up @@ -609,6 +671,13 @@ const handleMessageEvent: MessageEventListener = e => {
updateEvents.forEach((uevent: WebViewUpdateEvent) => {
// $FlowFixMe
eventUpdateHandlers[uevent.type](uevent);
if (isTrackingLongLoad && eventsDuringLongLoad !== null) {
// $FlowFixMe the spread seems to confuse Flow, but this is likely correct
eventsDuringLongLoad.push({
...uevent,
timestamp: Date.now(),
});
}
});
scrollEventsDisabled = false;
};
Expand Down

0 comments on commit aef73e6

Please sign in to comment.