add contract logs

This commit is contained in:
Jonathan Rainville 2018-08-09 15:33:07 -04:00 committed by Iuri Matias
parent 11e15d57ad
commit 245beeeb59
10 changed files with 245 additions and 102 deletions

View File

@ -76,6 +76,13 @@ export const processLogs = {
failure: (error) => action(PROCESS_LOGS[FAILURE], {error})
};
export const CONTRACT_LOGS = createRequestTypes('CONTRACT_LOGS');
export const contractLogs = {
request: () => action(CONTRACT_LOGS[REQUEST]),
success: (contractLogs) => action(CONTRACT_LOGS[SUCCESS], {contractLogs}),
failure: (error) => action(CONTRACT_LOGS[FAILURE], {error})
};
export const CONTRACTS = createRequestTypes('CONTRACTS');
export const contracts = {
request: () => action(CONTRACTS[REQUEST]),

View File

@ -56,6 +56,10 @@ export function fetchProcessLogs(payload) {
return get(`/process-logs/${payload.processName}`);
}
export function fetchContractLogs() {
return get(`/contracts/logs`);
}
export function fetchContracts() {
return get('/contracts');
}

View File

@ -8,6 +8,7 @@ import {
} from "tabler-react";
import ContractContainer from '../containers/ContractContainer';
import ContractLoggerContainer from '../containers/ContractLoggerContainer';
import ContractProfileContainer from '../containers/ContractProfileContainer';
const ContractLayout = (props) => (
@ -48,11 +49,20 @@ const ContractLayout = (props) => (
>
Profile
</List.GroupItem>
<List.GroupItem
className="d-flex align-items-center"
to={`/embark/contracts/${props.match.params.contractName}/logger`}
icon="chevrons-right"
RootComponent={withRouter(NavLink)}
>
Logger
</List.GroupItem>
</List.Group>
</div>
</Grid.Col>
<Grid.Col md={9}>
<Switch>
<Route exact path="/embark/contracts/:contractName/logger" component={ContractLoggerContainer} />
<Route exact path="/embark/contracts/:contractName/profiler" component={ContractProfileContainer} />
<ContractContainer />
</Switch>

View File

@ -0,0 +1,47 @@
import PropTypes from "prop-types";
import React from 'react';
import {
Page,
Grid, Table
} from "tabler-react";
const ContractLogger = ({contractName, contractLogs}) => (
<Page.Content title={contractName + ' Logger'}>
<Grid.Row>
<Grid.Col>
<Table
responsive
className="card-table table-vcenter text-nowrap"
headerItems={[
{content: "Function name"},
{content: "Params"},
{content: "Transaction hash"},
{content: "Gas Used"},
{content: "Block number"},
{content: "Status"}
]}
bodyItems={
contractLogs.map((log) => {
return ([
{content: log.functionName},
{content: log.paramString},
{content: log.transactionHash},
{content: log.gasUsed},
{content: log.blockNumber},
{content: log.status}
]);
})
}
/>
</Grid.Col>
</Grid.Row>
</Page.Content>
);
ContractLogger.propTypes = {
contractName: PropTypes.string.isRequired,
contractLogs: PropTypes.array.isRequired
};
export default ContractLogger;

View File

@ -0,0 +1,42 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {withRouter} from 'react-router-dom';
import {contractLogs as contractLogsAction} from '../actions';
import ContractLogger from '../components/ContractLogger';
// import DataWrapper from "../components/DataWrapper";
import {getContractLogsByContract} from "../reducers/selectors";
class ContractProfileContainer extends Component {
componentDidMount() {
if (this.props.contractLogs.length === 0) {
this.props.fetchContractLogs(this.props.match.params.contractName);
}
}
render() {
return (
<ContractLogger contractLogs={this.props.contractLogs} contractName={this.props.match.params.contractName}/>
);
}
}
function mapStateToProps(state, props) {
return {
contractLogs: getContractLogsByContract(state, props.match.params.contractName)
};
}
ContractProfileContainer.propTypes = {
contractLogs: PropTypes.array,
fetchContractLogs: PropTypes.func,
match: PropTypes.object
};
export default withRouter(connect(
mapStateToProps,
{
fetchContractLogs: contractLogsAction.request
}
)(ContractProfileContainer));

View File

@ -11,6 +11,7 @@ const entitiesDefaultState = {
processLogs: [],
contracts: [],
contractProfiles: [],
contractLogs: [],
commands: [],
messages: [],
messageChannels: [],
@ -27,6 +28,9 @@ const sorter = {
processLogs: function(a, b) {
return a.timestamp - b.timestamp;
},
contractLogs: function(a, b) {
return a.timestamp - b.timestamp;
},
messages: function(a, b) {
return a.time - b.time;
}

View File

@ -46,6 +46,11 @@ export function getProcessLogsByProcess(state, processName) {
return state.entities.processLogs.filter((processLog => processLog.name === processName));
}
export function getContractLogsByContract(state, contractName) {
return state.entities.contractLogs;
// return state.entities.processLogs.filter((processLog => processLog.name === processName));
}
export function getContracts(state) {
return state.entities.contracts;
}

View File

@ -4,7 +4,7 @@ import {eventChannel} from 'redux-saga';
import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects';
const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs,
contracts, contract, contractProfile, messageSend, messageVersion, messageListen} = actions;
contracts, contract, contractProfile, messageSend, messageVersion, messageListen, contractLogs} = actions;
function *doRequest(entity, apiFn, payload) {
const {response, error} = yield call(apiFn, payload);
@ -24,6 +24,7 @@ export const fetchTransactions = doRequest.bind(null, transactions, api.fetchTra
export const fetchProcesses = doRequest.bind(null, processes, api.fetchProcesses);
export const postCommand = doRequest.bind(null, commands, api.postCommand);
export const fetchProcessLogs = doRequest.bind(null, processLogs, api.fetchProcessLogs);
export const fetchContractLogs = doRequest.bind(null, contractLogs, api.fetchContractLogs);
export const fetchContracts = doRequest.bind(null, contracts, api.fetchContracts);
export const fetchContract = doRequest.bind(null, contract, api.fetchContract);
export const fetchContractProfile = doRequest.bind(null, contractProfile, api.fetchContractProfile);
@ -64,6 +65,10 @@ export function *watchFetchProcessLogs() {
yield takeEvery(actions.PROCESS_LOGS[actions.REQUEST], fetchProcessLogs);
}
export function *watchFetchContractLogs() {
yield takeEvery(actions.CONTRACT_LOGS[actions.REQUEST], fetchContractLogs);
}
export function *watchFetchContract() {
yield takeEvery(actions.CONTRACT[actions.REQUEST], fetchContract);
}
@ -146,6 +151,7 @@ export default function *root() {
fork(watchFetchAccount),
fork(watchFetchProcesses),
fork(watchFetchProcessLogs),
fork(watchFetchContractLogs),
fork(watchListenToProcessLogs),
fork(watchFetchBlock),
fork(watchFetchTransactions),

View File

@ -86,7 +86,9 @@ exports.serve = function(ipc, host, port, ws){
let server = http.createServer((req, res) => {
let reqBody = [];
req.on('data', (b) => { reqBody.push(b); })
req.on('data', (b) => {
reqBody.push(b);
})
.on('end', () => {
reqBody = Buffer.concat(reqBody).toString();
if (reqBody) {

View File

@ -2,10 +2,12 @@ const utils = require('../../utils/utils.js');
class ConsoleListener {
constructor(embark, options) {
this.embark = embark;
this.logger = embark.logger;
this.ipc = options.ipc;
this.events = embark.events;
this.addressToContract = [];
this.logs = [];
this.contractsConfig = embark.config.contractsConfig;
this.contractsDeployed = false;
this.outputDone = false;
@ -13,6 +15,7 @@ class ConsoleListener {
this.events.on('outputDone', () => {
this.outputDone = true;
});
this._registerAPI();
this.events.on("contractsDeployed", () => {
this.contractsDeployed = true;
@ -91,12 +94,25 @@ class ConsoleListener {
gasUsed = utils.hexToNumber(gasUsed);
blockNumber = utils.hexToNumber(blockNumber);
this.logs.push(Object.assign({}, request, {name, functionName, paramString}));
this.logger.info(`Blockchain>`.underline + ` ${name}.${functionName}(${paramString})`.bold + ` | ${transactionHash} | gas:${gasUsed} | blk:${blockNumber} | status:${status}`);
} else {
this.logger.info(JSON.stringify(request));
}
});
}
_registerAPI() {
const apiRoute = '/embark-api/contracts/logs';
this.embark.registerAPICall(
'get',
apiRoute,
(req, res) => {
res.send(JSON.stringify(this.logs));
}
);
}
}
module.exports = ConsoleListener;