Accept Trace file and export a metric
Summary: This diff adds support to pass a path to the trace file to the headless Flipper. The headless Flipper then exports the metrics out of it. Reviewed By: passy Differential Revision: D15337067 fbshipit-source-id: 61aca1ffd58e879dafe6aa176f058f7b11460952
This commit is contained in:
committed by
Facebook Github Bot
parent
b8f3729752
commit
89ebb11520
@@ -29,6 +29,12 @@ test('test makeObjectSerializable function for unnested object with no Set and M
|
||||
expect(output2).toEqual(obj2);
|
||||
});
|
||||
|
||||
test('makeObjectSerializable function for unnested object with values which returns false when put in an if condition', () => {
|
||||
const obj2 = {key1: 0, key2: ''};
|
||||
const output2 = makeObjectSerializable(obj2);
|
||||
expect(output2).toEqual(obj2);
|
||||
});
|
||||
|
||||
test('test deserializeObject function for unnested object with no Set and Map', () => {
|
||||
let obj = {key1: 'value1', key2: 'value2'};
|
||||
const output = deserializeObject(obj);
|
||||
|
||||
@@ -6,32 +6,26 @@
|
||||
*/
|
||||
import type {FlipperPlugin, FlipperDevicePlugin} from 'flipper';
|
||||
import {serialize} from './serialization';
|
||||
import type {MiddlewareAPI} from '../reducers';
|
||||
import type {State as PluginStatesState} from '../reducers/pluginStates';
|
||||
import type {State} from '../reducers/index.js';
|
||||
import fs from 'fs';
|
||||
import type {ExportType} from './exportData';
|
||||
import {deserializeObject} from './serialization';
|
||||
|
||||
export type MetricType = {[metricName: string]: number};
|
||||
type MetricPluginType = {[pluginID: string]: MetricType};
|
||||
export type ExportMetricType = {[clientID: string]: MetricPluginType};
|
||||
|
||||
export default async function exportMetrics(
|
||||
store: MiddlewareAPI,
|
||||
export async function exportMetrics(
|
||||
pluginStates: PluginStatesState,
|
||||
pluginsMap: Map<string, Class<FlipperDevicePlugin<> | FlipperPlugin<>>>,
|
||||
): Promise<string> {
|
||||
const state = store.getState();
|
||||
const metrics: ExportMetricType = {};
|
||||
for (let key in state.pluginStates) {
|
||||
const pluginStateData = state.pluginStates[key];
|
||||
for (let key in pluginStates) {
|
||||
const pluginStateData = pluginStates[key];
|
||||
const arr = key.split('#');
|
||||
const pluginName = arr.pop();
|
||||
const clientID = arr.join('#');
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
|
||||
> = new Map([]);
|
||||
state.plugins.clientPlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
});
|
||||
state.plugins.devicePlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
});
|
||||
const metricsReducer: ?(
|
||||
persistedState: any,
|
||||
) => Promise<MetricType> = pluginsMap.get(pluginName)?.metricsReducer;
|
||||
@@ -49,3 +43,65 @@ export default async function exportMetrics(
|
||||
}
|
||||
return Promise.resolve(serialize(metrics));
|
||||
}
|
||||
|
||||
export async function exportMetricsWithoutTrace(
|
||||
state: State,
|
||||
pluginStates: PluginStatesState,
|
||||
): Promise<?string> {
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
Class<FlipperDevicePlugin<> | FlipperPlugin<>>,
|
||||
> = new Map([]);
|
||||
state.plugins.clientPlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
});
|
||||
state.plugins.devicePlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
});
|
||||
|
||||
const metrics = await exportMetrics(pluginStates, pluginsMap);
|
||||
return metrics;
|
||||
}
|
||||
|
||||
function parseJSON(str: string): ?any {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export async function exportMetricsFromTrace(
|
||||
trace: string,
|
||||
state: State,
|
||||
): Promise<?string> {
|
||||
const data = fs.readFileSync(trace, 'utf8');
|
||||
const parsedJSONData = parseJSON(data);
|
||||
if (!parsedJSONData) {
|
||||
return Promise.reject(
|
||||
new Error('Please pass the file which has a valid JSON'),
|
||||
);
|
||||
}
|
||||
const importedData: ExportType = deserializeObject(parsedJSONData);
|
||||
const importedStore = importedData.store;
|
||||
if (!importedStore) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'No store in the imported file, thus exiting without exporting metrics.',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const {pluginStates} = importedStore;
|
||||
|
||||
if (!pluginStates) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
'No pluginStates in the imported file, thus exiting without exporting metrics.',
|
||||
),
|
||||
);
|
||||
}
|
||||
const metrics = await exportMetricsWithoutTrace(state, pluginStates);
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,10 @@ export function makeObjectSerializable(obj: any): any {
|
||||
}
|
||||
const serializedKey = dict.get(key);
|
||||
const serializedValue = dict.get(value);
|
||||
if (serializedValue && serializedKey) {
|
||||
if (
|
||||
typeof serializedKey !== 'undefined' &&
|
||||
typeof serializedValue !== 'undefined'
|
||||
) {
|
||||
obj = {...obj, [serializedKey]: serializedValue};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user