Files
flipper/desktop/app/src/utils/info.tsx
Anton Nikolaev 25ae4a0535 Include information about selected device, app and plugin into analytics events and error reports
Summary:
This diff generalises computation of the currently selected plugin, app, device etc. and adds this information to all the analytics events and error reports.

Slicing of events by os, device, app or selected plugin can be very useful. This is especially true for errors which often affects only certain types of devices, e.g. android only or physical devices only. Having such information can help to narrow down such issues.

Reviewed By: passy

Differential Revision: D28511441

fbshipit-source-id: ed9dc57927c70ed8cc6fe093e21604eae54c2f60
2021-05-19 05:17:41 -07:00

152 lines
3.8 KiB
TypeScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import os from 'os';
import isProduction, {isTest} from './isProduction';
import fs from 'fs-extra';
import {getStaticPath} from './pathUtils';
import type {State, Store} from '../reducers/index';
import {deconstructClientId} from './clientUtils';
import {sideEffect} from './sideEffect';
import {Logger} from '../fb-interfaces/Logger';
type PlatformInfo = {
arch: string;
platform: string;
unixname: string;
versions: {
[key: string]: string | undefined;
};
};
export type SelectionInfo = {
plugin: string | null;
pluginName: string | null;
pluginVersion: string | null;
app: string | null;
os: string | null;
device: string | null;
deviceName: string | null;
deviceSerial: string | null;
deviceType: string | null;
archived: boolean | null;
};
export type Info = PlatformInfo & {
selection: SelectionInfo;
};
let platformInfo: PlatformInfo | undefined;
let selection: SelectionInfo = {
plugin: null,
pluginName: null,
pluginVersion: null,
app: null,
os: null,
device: null,
deviceName: null,
deviceSerial: null,
deviceType: null,
archived: null,
};
export default (store: Store, _logger: Logger) => {
return sideEffect(
store,
{
name: 'recomputeSelectionInfo',
throttleMs: 0,
noTimeBudgetWarns: true,
runSynchronously: true,
fireImmediately: true,
},
(state) => ({
connections: state.connections,
loadedPlugins: state.plugins.loadedPlugins,
}),
(state, _store) => {
selection = getSelectionInfo(state.connections, state.loadedPlugins);
},
);
};
/**
* This method builds up some metadata about the users environment that we send
* on bug reports, analytic events, errors etc.
*/
export function getInfo(): Info {
if (!platformInfo) {
platformInfo = {
arch: process.arch,
platform: process.platform,
unixname: os.userInfo().username,
versions: {
electron: process.versions.electron,
node: process.versions.node,
platform: os.release(),
},
};
}
return {
...platformInfo,
selection,
};
}
let APP_VERSION: string | undefined;
export function getAppVersion(): string {
return (APP_VERSION =
APP_VERSION ??
process.env.FLIPPER_FORCE_VERSION ??
(isTest()
? '0.0.0'
: (isProduction()
? fs.readJsonSync(getStaticPath('package.json'), {
throws: false,
})?.version
: require('../../package.json').version) ?? '0.0.0'));
}
export function stringifyInfo(info: Info): string {
const lines = [
`Platform: ${info.platform} ${info.arch}`,
`Unixname: ${info.unixname}`,
`Versions:`,
];
for (const key in info.versions) {
lines.push(` ${key}: ${String(info.versions[key])}`);
}
return lines.join('\n');
}
export function getSelectionInfo(
connections: State['connections'],
loadedPlugins: State['plugins']['loadedPlugins'],
): SelectionInfo {
const selectedApp = connections.selectedApp;
const clientIdParts = selectedApp ? deconstructClientId(selectedApp) : null;
const loadedPlugin = connections.selectedPlugin
? loadedPlugins.get(connections.selectedPlugin)
: null;
return {
plugin: connections.selectedPlugin || null,
pluginName: loadedPlugin?.name || null,
pluginVersion: loadedPlugin?.version || null,
app: clientIdParts?.app || null,
device: connections.selectedDevice?.title || null,
deviceName: clientIdParts?.device || null,
deviceSerial: connections.selectedDevice?.serial || null,
deviceType: connections.selectedDevice?.deviceType || null,
os: connections.selectedDevice?.os || null,
archived: connections.selectedDevice?.isArchived || false,
};
}