diagnostics_actions.jsx 3.48 KB
Newer Older
1 2
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
3

4
import {Client4} from 'mattermost-redux/client';
5 6 7
import {getConfig} from 'mattermost-redux/selectors/entities/general';

import store from 'stores/redux_store.jsx';
8

9 10 11 12 13 14
const SUPPORTS_CLEAR_MARKS = isSupported([performance.clearMarks]);
const SUPPORTS_MARK = isSupported([performance.mark]);
const SUPPORTS_MEASURE_METHODS = isSupported([
    performance.measure,
    performance.getEntries,
    performance.getEntriesByName,
15
    performance.clearMeasures,
16 17
]);

18
export function trackEvent(category, event, props) {
19
    Client4.trackEvent(category, event, props);
20
}
21 22 23 24 25 26 27 28

/**
 * Takes an array of string names of performance markers and invokes
 * performance.clearMarkers on each.
 * @param   {array} names of markers to clear
 *
 */
export function clearMarks(names) {
29
    if (!isDevMode() || !SUPPORTS_CLEAR_MARKS) {
30 31 32 33 34 35
        return;
    }
    names.forEach((name) => performance.clearMarks(name));
}

export function mark(name) {
36
    if (!isDevMode() || !SUPPORTS_MARK) {
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
        return;
    }
    performance.mark(name);
}

/**
 * Takes the names of two markers and invokes performance.measure on
 * them. The measured duration (ms) and the string name of the measure is
 * are returned.
 *
 * @param   {string} name1 the first marker
 * @param   {string} name2 the second marker
 *
 * @returns {[number, string]} Either the measured duration (ms) and the string name
 * of the measure are returned or -1 and and empty string is returned if
 * in dev. mode or one of the marker can't be found.
 *
 */
export function measure(name1, name2) {
56
    if (!isDevMode() || !SUPPORTS_MEASURE_METHODS) {
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
        return [-1, ''];
    }

    // Check for existence of entry name to avoid DOMException
    const performanceEntries = performance.getEntries();
    if (![name1, name2].every((name) => performanceEntries.find((item) => item.name === name))) {
        return [-1, ''];
    }

    const displayPrefix = '🐐 Mattermost: ';
    const measurementName = `${displayPrefix}${name1} - ${name2}`;
    performance.measure(measurementName, name1, name2);
    const lastDuration = mostRecentDurationByEntryName(measurementName);

    // Clean up the measures we created
    performance.clearMeasures(measurementName);
    return [lastDuration, measurementName];
}

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
export function trackLoadTime() {
    if (!isSupported([performance.timing.loadEventEnd, performance.timing.navigationStart])) {
        return;
    }

    // Must be wrapped in setTimeout because loadEventEnd property is 0
    // until onload is complete, also time added because analytics
    // code isn't loaded until a subsequent window event has fired.
    const tenSeconds = 10000;
    setTimeout(() => {
        const {loadEventEnd, navigationStart} = window.performance.timing;
        const pageLoadTime = loadEventEnd - navigationStart;
        trackEvent('performance', 'page_load', {duration: pageLoadTime});
    }, tenSeconds);
}

92 93 94
function mostRecentDurationByEntryName(entryName) {
    const entriesWithName = performance.getEntriesByName(entryName);
    return entriesWithName.map((item) => item.duration)[entriesWithName.length - 1];
95 96 97 98 99 100 101 102 103 104 105 106 107
}

function isSupported(checks) {
    for (let i = 0, len = checks.length; i < len; i++) {
        const item = checks[i];
        if (typeof item === 'undefined') {
            return false;
        }
    }
    return true;
}

function isDevMode() {
108 109 110 111
    const config = getConfig(store.getState());

    return config.EnableDeveloper === 'true';
}