Skip to content
This repository has been archived by the owner on Mar 10, 2023. It is now read-only.

Commit

Permalink
Added React metrics component
Browse files Browse the repository at this point in the history
Show metrics for function invocation for 1hr and 24hr periods. The metrics component resolves #189

Signed-off-by: jagreehal <[email protected]>
  • Loading branch information
jagreehal authored and alexellis committed Dec 6, 2018
1 parent 20e7969 commit d3bb7e2
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 70 deletions.
35 changes: 29 additions & 6 deletions dashboard/client/src/api/functionsApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ class FunctionsApi {
this.cachedFunctions = {};
}

parseFunctionResponse({ data }, user) {
parseFunctionResponse({
data
}, user) {
data.sort((a, b) => {
if (
!a ||
Expand Down Expand Up @@ -118,14 +120,35 @@ class FunctionsApi {
// fetch functions if cache not found
this.fetchFunctions(user).then(() => {
const fn = this.cachedFunctions[key];
fn !== undefined
? resolve(fn)
: reject(new Error(`Function ${key} not found`));
fn !== undefined ?
resolve(fn) :
reject(new Error(`Function ${key} not found`));
});
});
}

fetchFunctionLog({ commitSHA, repoPath, functionName }) {
async fetchFunctionInvocation(params) {
const {
user,
functionName,
timePeriod
} = params;
try {
const url = `${this.apiBaseUrl}/system-metrics?function=${user}-${functionName}&metrics_window=${timePeriod}`;
const result = await axios
.get(url);
return result.data;
} catch (error) {
console.error('Error fetching function invocation', params, error);
return null;
}
}

fetchFunctionLog({
commitSHA,
repoPath,
functionName
}) {
const url = `${
this.apiBaseUrl
}/pipeline-log?commitSHA=${commitSHA}&repoPath=${repoPath}&function=${functionName}`;
Expand All @@ -135,4 +158,4 @@ class FunctionsApi {
}
}

export const functionsApi = new FunctionsApi();
export const functionsApi = new FunctionsApi();
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faAward, faCloudDownloadAlt, faUserSecret } from '@fortawesome/free-solid-svg-icons';
import {
faAward,
faCloudDownloadAlt,
faUserSecret
} from '@fortawesome/free-solid-svg-icons';

import { FunctionOverviewPanel } from '../FunctionOverviewPanel'
import { ReplicasProgress } from "../ReplicasProgress";
import { FunctionInvocation } from '../FunctionInvocation';
import { FunctionOverviewPanel } from '../FunctionOverviewPanel';
import { ReplicasProgress } from '../ReplicasProgress';

import { Button } from 'reactstrap';

Expand All @@ -27,7 +32,14 @@ const renderContainerImage = image => {
}
};

const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFModal }) => {
const FunctionDetailSummary = ({
changeFunctionInvocationTimePeriod,
fn,
functionInvocationData,
handleShowBadgeModal,
handleShowRunOnMyOFModal
}) => {
console.log('functionInvocation', functionInvocationData);
const to = `${fn.shortName}/log?repoPath=${fn.gitOwner}/${
fn.gitRepo
}&commitSHA=${fn.gitSha}`;
Expand All @@ -39,21 +51,24 @@ const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFMo
renderValue() {
return (
<div className="d-flex align-items-start">
<div>
{ fn.shortName }
</div>
<div>{fn.shortName}</div>
<div className="ml-auto">
<Button outline size="xs" title="Run on my OpenFaaS" onClick={handleShowRunOnMyOFModal}>
<Button
outline
size="xs"
title="Run on my OpenFaaS"
onClick={handleShowRunOnMyOFModal}
>
<FontAwesomeIcon icon={faCloudDownloadAlt} />
</Button>
</div>
</div>
)
},
);
}
},
{
label: 'Image:',
value: renderContainerImage(fn.image),
value: renderContainerImage(fn.image)
},
{
label: 'Endpoint:',
Expand All @@ -62,16 +77,14 @@ const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFMo
<a href={fn.endpoint} target="_blank">
{fn.endpoint}
</a>
)
},
);
}
},
{
label: 'Replicas:',
renderValue() {
return (
<ReplicasProgress fn={fn} className="" />
)
},
return <ReplicasProgress fn={fn} className="" />;
}
}
];

Expand All @@ -81,7 +94,7 @@ const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFMo
renderValue() {
return (
<a href={`https://github.com/${repo}`} target="_blank">
{ repo }
{repo}
</a>
);
}
Expand All @@ -90,29 +103,33 @@ const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFMo
label: 'SHA:',
renderValue() {
return (
<a
href={`${fn.gitRepoURL}/commit/${fn.gitSha}`}
target="_blank"
>
{ fn.gitSha }
<a href={`${fn.gitRepoURL}/commit/${fn.gitSha}`} target="_blank">
{fn.gitSha}
</a>
)
},
);
}
},
{
label: 'Deploy Time:',
value: fn.sinceDuration,
},
value: fn.sinceDuration
}
];

const deployIcon = <FontAwesomeIcon icon="info-circle" className="mr-3" />;
const gitIcon = (
<span>
<FontAwesomeIcon icon="code-branch" className="mr-3" />
{ fn.gitPrivate && <FontAwesomeIcon icon={faUserSecret} className="mr-3" /> }
{fn.gitPrivate && (
<FontAwesomeIcon icon={faUserSecret} className="mr-3" />
)}
</span>
);
const invocationsIcon = <FontAwesomeIcon icon="bolt" className="mr-3 mr-lg-2 d-inline-block d-lg-none d-xl-inline-block" />;
const invocationsIcon = (
<FontAwesomeIcon
icon="bolt"
className="mr-3 mr-lg-2 d-inline-block d-lg-none d-xl-inline-block"
/>
);
const deployButton = (
<Button outline color="secondary" size="xs" tag={Link} to={to}>
<FontAwesomeIcon icon="folder-open" className="mr-2" />
Expand All @@ -128,7 +145,7 @@ const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFMo

return (
<div className="FunctionDetailSummary fn-detail-summary row">
<div className="col-lg-5 pb-3 pb-lg-0">
<div className="col-lg-4 pb-3 pb-lg-0">
<FunctionOverviewPanel
headerText="Deployment"
headerIcon={deployIcon}
Expand All @@ -137,41 +154,44 @@ const FunctionDetailSummary = ({ fn, handleShowBadgeModal, handleShowRunOnMyOFMo
<FunctionOverviewPanel.MetaList list={deployMeta} />
</FunctionOverviewPanel>
</div>
<div className="col-lg-5 pb-3 pb-lg-0">
<div className="col-lg-4 pb-3 pb-lg-0">
<FunctionOverviewPanel
headerText="Git"
headerIcon={gitIcon}
button={gitButton}
>
<FunctionOverviewPanel.MetaList list={gitMeta} sizes={{
xs: 12,
sm: 3,
md: 2,
lg: 4,
xl: 3,
}} />
<FunctionOverviewPanel.MetaList
list={gitMeta}
sizes={{ xs: 12, sm: 3, md: 2, lg: 5, xl: 4 }}
/>
</FunctionOverviewPanel>
</div>
<div className="col-lg-2">
<div className="col-lg-4">
<FunctionOverviewPanel
headerText="Invocations"
headerIcon={invocationsIcon}
bodyClassName="d-flex justify-content-center align-items-center"
>
<h1 className="font-weight-bold">
{ fn.invocationCount }
</h1>
{functionInvocationData ? (
<FunctionInvocation
functionInvocationData={functionInvocationData}
changeFunctionInvocationTimePeriod={
changeFunctionInvocationTimePeriod
}
/>
) : (
<h1 className="font-weight-bold text-center">
{fn.invocationCount}
</h1>
)}
</FunctionOverviewPanel>
</div>
</div>
);
};

FunctionDetailSummary.propTypes = {
fn: PropTypes.object.isRequired,
handleShowBadgeModal: PropTypes.func.isRequired,
fn: PropTypes.object.isRequired,
handleShowBadgeModal: PropTypes.func.isRequired
};

export {
FunctionDetailSummary
};
export { FunctionDetailSummary };
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.nav-link.active {
border-bottom: 5px solid #007bff;
}
82 changes: 82 additions & 0 deletions dashboard/client/src/components/FunctionInvocation/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from 'react';
import {
Badge,
ListGroup,
ListGroupItem,
Nav,
NavLink,
Progress
} from 'reactstrap';

import './FunctionInvocation.css';

const OPTIONS = {
'1hr': '60m',
'24hr': '1440m'
};

export class FunctionInvocation extends React.Component {
state = {
selected: '1hr'
};

render() {
const { functionInvocationData } = this.props;
let { success, failure } = functionInvocationData;
const navLinks = Object.keys(OPTIONS).map(option => {
return (
<NavLink
key={option}
href="#"
active={option === this.state.selected}
onClick={() => this.navLinkClickHandle(option)}
>
{option}
</NavLink>
);
});

const total = success + failure;
const successPercent = (success / total) * 100;
const failurePercent = (failure / total) * 100;

return (
<div className="">
<Nav className="d-flex justify-content-center">
<span className="d-flex align-items-center mr-4 font-weight-bold">
Period:
</span>
{navLinks}
</Nav>
<div>
<Progress multi={true} className="mt-3 d-flex justify-content-center">
<Progress bar={true} color="success" value={successPercent} />
<Progress bar={true} color="danger" value={failurePercent} />
</Progress>
<span className="font-weight-bold">{total}</span> invocations
</div>
<ListGroup className="mt-3 m0 flex-row">
<ListGroupItem className="d-flex flex-fill flex-column align-items-center">
<h5 className="m-0">
<Badge color="success">{success}</Badge>
</h5>
<span>Success</span>
</ListGroupItem>
<ListGroupItem className="d-flex flex-fill flex-column align-items-center">
<h5 className="m0">
<Badge color="danger">{failure}</Badge>
</h5>
<span>Error</span>
</ListGroupItem>
</ListGroup>
</div>
);
}

navLinkClickHandle = option => {
this.setState({
selected: option
});
this.props.changeFunctionInvocationTimePeriod(OPTIONS[option]);
};
}
Loading

0 comments on commit d3bb7e2

Please sign in to comment.