Added metrics argument to headless inorder to export metrics

Summary:
This diff makes headless flipper accept `metrics` argument. Once this is passed. The headless flipper will terminate to export the metrics of the plugins, the type of the export looks like the following.

```
export type MetricType = {[metricName: string]: number};
type MetricPluginType = {[pluginID: string]: MetricType};
export type ExportMetricType = {[clientID: string]: MetricPluginType};

```

This diff, uses the store to export the metrics. I will modify the logic to accept the data which gets exported through `exportData`

Reviewed By: passy

Differential Revision: D14933499

fbshipit-source-id: dade5b7bc59ea4beb6d16c5ef471737e8597358a
This commit is contained in:
Pritesh Nandgaonkar
2019-04-25 07:34:02 -07:00
committed by Facebook Github Bot
parent 7bbb8c10c4
commit afd729deb6
5 changed files with 101 additions and 11 deletions

View File

@@ -46,8 +46,7 @@ public final class ExampleActions {
}
public static void sendGetRequest() {
final Request request =
new Request.Builder().url("https://api.github.com/repos/facebook/yoga").get().build();
final Request request = new Request.Builder().url("https://api.github.com/repos/facebook/yoga").get().build();
FlipperSampleApplication.sOkHttpClient
.newCall(request)
.enqueue(

View File

@@ -14,6 +14,8 @@ import dispatcher from '../src/dispatcher/index.js';
import {init as initLogger} from '../src/fb-stubs/Logger.js';
import reducers from '../src/reducers/index.js';
import {exportStore} from '../src/utils/exportData.js';
import exportMetrics from '../src/utils/exportMetrics.js';
// $FlowFixMe this file exist, trust me, flow!
import setup from '../static/setup.js';
@@ -50,6 +52,12 @@ yargs
describe: 'Enable verbose logging',
type: 'boolean',
});
yargs.option('metrics', {
alias: 'metrics',
default: false,
describe: 'Will export metrics instead of data when flipper terminates',
type: 'boolean',
});
},
startFlipper,
)
@@ -59,6 +67,7 @@ yargs
function startFlipper({
dev,
verbose,
metrics,
exit,
'insecure-port': insecurePort,
'secure-port': securePort,
@@ -100,12 +109,21 @@ function startFlipper({
// TODO(T42325892): Investigate why the export stalls without exiting the
// current eventloop task here.
setTimeout(() => {
if (metrics) {
exportMetrics(store)
.then(payload => {
originalConsole.log(payload);
process.exit();
})
.catch(console.error);
} else {
exportStore(store)
.then(({serializedString}) => {
originalConsole.log(serializedString);
process.exit();
})
.catch(console.error);
}
}, 10);
}
return next(action);
@@ -122,9 +140,14 @@ function startFlipper({
if (exit == 'sigint') {
process.on('SIGINT', async () => {
try {
if (metrics) {
const payload = await exportMetrics(store);
originalConsole.log(payload);
} else {
const {serializedString, errorArray} = await exportStore(store);
errorArray.forEach(console.error);
originalConsole.log(serializedString);
}
} catch (e) {
console.error(e);
}

View File

@@ -83,6 +83,9 @@ export class FlipperBasePlugin<
method: string,
data: Object,
) => $Shape<PersistedState>;
static exportMetrics: ?(
persistedState: PersistedState,
) => Promise<Map<string, number | string>>;
static exportPersistedState: ?(
callClient: (string, ?Object) => Promise<Object>,
persistedState: ?PersistedState,

View File

@@ -107,6 +107,19 @@ export default class extends FlipperPlugin<State, *, PersistedState> {
responses: {},
};
static exportMetrics = (
persistedState: PersistedState,
): Promise<Map<string, number | string>> => {
const failures = Object.keys(persistedState.responses).reduce(function(
previous,
key,
) {
return previous + (persistedState.responses[key].status >= 400);
},
0);
return Promise.resolve(new Map([['NUMBER_NETWORK_FAILURES', failures]]));
};
static persistedStateReducer = (
persistedState: PersistedState,
method: string,

View File

@@ -0,0 +1,52 @@
/**
* Copyright 2018-present Facebook.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @format
*/
import type {MiddlewareAPI} from '../reducers';
import {serialize} from './serialization.js';
import type {FlipperPlugin, FlipperDevicePlugin} from 'flipper';
type MetricType = Map<string, Map<string, string | number>>;
export type ExportMetricType = Map<string, MetricType>;
export default async function exportMetrics(
store: MiddlewareAPI,
): Promise<string> {
const state = store.getState();
let metrics: ExportMetricType = new Map();
for (let key in state.pluginStates) {
const pluginStateData = state.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 exportMetrics1: ?(
persistedState: any,
) => Promise<Map<string, string | number>> = pluginsMap.get(pluginName)
?.exportMetrics;
if (pluginsMap.has(pluginName) && exportMetrics1) {
const metricMap = await exportMetrics1(pluginStateData);
const pluginMap = new Map([[pluginName, metricMap]]);
if (!metrics.get(clientID)) {
metrics.set(clientID, pluginMap);
continue;
}
const prevMetricMap = metrics.get(clientID);
// $FlowFixMe: prevMetricMap cannot be null, because clientID is added only when the pluingMetricMap is available
metrics.set(clientID, new Map([...prevMetricMap, ...pluginMap]));
}
}
return Promise.resolve(serialize(metrics));
}