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

Commit

Permalink
hotfix: logging, apm, ga (#866)
Browse files Browse the repository at this point in the history
  • Loading branch information
moshmage authored Feb 13, 2023
2 parents fbb817c + d30666d commit 7f10396
Show file tree
Hide file tree
Showing 64 changed files with 1,526 additions and 360 deletions.
23 changes: 22 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,25 @@ NEXT_PUBLIC_PROPOSAL_ACCEPTED=
NEXT_PUBLIC_PROPOSAL_REJECTED=

# Google Analytics Measurement ID
NEXT_PUBLIC_GA_MEASUREMENT_ID=
NEXT_PUBLIC_GA_MEASUREMENT_ID=

# API log level: 0 none, 1 error, 2 warn, 3 info, 4 trace, 5 log, 6 debug
LOG_LEVEL=6

# Elastic APM integration secret token
ELASTIC_APM_SECRET_TOKEN=

# Elastic APM integration server url
ELASTIC_APM_SERVER_URL=

# Elastic APM integration service name
ELASTIC_APM_SERVICE_NAME=

# true|false - Enable Elastic APM integration
ELASTIC_APM_ACTIVE=

# Elastic APM _local_ log level
ELASTIC_APM_LOG_LEVEL=

# true|false - should we index Logger.trace() into elastic
ELASTIC_INDEX_STACK_TRACE=
1 change: 0 additions & 1 deletion components/bounties/list-active-networks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export default function ListActiveNetworks() {
<h4 className="mt-1">{t("most-active-networks")}</h4>
<Link href={"/networks"}>
<a
target="_blank"
className="text-decoration-none text-primary mt-2"
rel="noreferrer"
>
Expand Down
13 changes: 6 additions & 7 deletions components/connect-wallet-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ import {changeShowWeb3} from "../contexts/reducers/update-show-prop";
export default function ConnectWalletButton({children = null, asModal = false, forceLogin = false,}) {
const { t } = useTranslation(["common", "connect-wallet-button"]);

const {dispatch, state: { loading, connectedChain },} = useAppState();
const {dispatch, state} = useAppState();
const [showModal, setShowModal] = useState(false);

const {state} = useAppState();

const { connectWallet } = useAuthentication();

async function handleLogin() {
Expand All @@ -35,11 +33,12 @@ export default function ConnectWalletButton({children = null, asModal = false, f
if (!state.Service?.active)
return;

if (+state.connectedChain?.id === +state.Settings?.requiredChain?.id) {
if (
(+state.connectedChain?.id || +window?.ethereum?.chainId) ===
+state.Settings?.requiredChain?.id
) {
connectWallet();
} else {
console.log('no connected chain?', connectedChain, state.Settings?.requiredChain);

dispatch(changeChain.update({...state.connectedChain, id: state.Settings?.requiredChain?.id}));
setShowModal(false);
}
Expand All @@ -64,7 +63,7 @@ export default function ConnectWalletButton({children = null, asModal = false, f


if (asModal) {
if (loading?.isLoading) return <></>;
if (state?.loading?.isLoading) return <></>;

return (
<Modal
Expand Down
77 changes: 36 additions & 41 deletions components/main-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {ReactElement, ReactNode, useEffect, useState} from "react";
import {Defaults} from "@taikai/dappkit";
import {useRouter} from "next/router";

import ExternalLinkIcon from "assets/icons/external-link-icon";
import HelpIcon from "assets/icons/help-icon";
import LogoPlaceholder from "assets/icons/logo-placeholder";
import PlusIcon from "assets/icons/plus-icon";
Expand Down Expand Up @@ -45,7 +46,7 @@ export default function MainNav() {
const { searchNetworks } = useApi();
const { getURLWithNetwork } = useNetworkTheme();

const noNeedNetworkInstance = ["/networks", "/new-network", "/bounty-hall", "/leaderboard"].includes(pathname);
const noNeedNetworkInstance = ["/networks", "/new-network", "/explore", "/leaderboard"].includes(pathname);
const fullLogoUrl = state.Service?.network?.active?.fullLogo;

useEffect(() => {
Expand Down Expand Up @@ -74,7 +75,21 @@ export default function MainNav() {
if(!window.ethereum) return dispatch(changeShowWeb3(true))
return dispatch(changeShowCreateBounty(true))

}
}

function LinkExplore() {
return (
<InternalLink
className="mt-1"
href={"/explore"}
blank={!noNeedNetworkInstance}
label={<Translation label={"main-nav.explorer"} />}
nav
uppercase
icon={!noNeedNetworkInstance ? <ExternalLinkIcon className="mb-1" width={12} height={12} />:null}
/>
);
}

function LinkNetworks() {
return(
Expand All @@ -101,7 +116,9 @@ export default function MainNav() {
function LinkBounties() {
return (
<InternalLink
href={"/bounty-hall"}
href={getURLWithNetwork("/bounties", {
network: state.Service?.network?.active?.name,
})}
label={<Translation label={"main-nav.nav-avatar.bounties"} />}
nav
uppercase
Expand All @@ -110,41 +127,17 @@ export default function MainNav() {
}

const brandLogo = !noNeedNetworkInstance ? (
<InternalLink
href={getURLWithNetwork("/", {
network: state.Service?.network?.active?.name,
})}
icon={
fullLogoUrl ? (
<img
src={`${state.Settings?.urls?.ipfs}/${fullLogoUrl}`}
width={104}
height={40}
/>
) : (
<LogoPlaceholder />
)
}
className="brand"
nav
active
brand
/>
): (
<InternalLink
href={'/'}
icon={
<img
src={`/images/Bepro_Logo_Light.svg`}
width={104}
height={40}
/>
}
className="brand"
nav
active
brand
fullLogoUrl ? (
<img
src={`${state.Settings?.urls?.ipfs}/${fullLogoUrl}`}
width={104}
height={40}
/>
) : (
<LogoPlaceholder />
)
) : (
<img src={`/images/Bepro_Logo_Light.svg`} width={104} height={40} />
);

return (
Expand All @@ -163,7 +156,6 @@ export default function MainNav() {
<li>
<LinkBounties />
</li>

<li>
<InternalLink
href={getURLWithNetwork("/curators", {
Expand All @@ -180,18 +172,21 @@ export default function MainNav() {
<li>
<LinkLeaderBoard />
</li>
<li>
<LinkExplore />
</li>
</ul>
)) || (
<ul className="nav-links">
<li>
<LinkBounties />
</li>
<li>
<LinkNetworks/>
</li>
<li>
<LinkLeaderBoard />
</li>
<li>
<LinkExplore />
</li>
</ul>
)}
</div>
Expand Down
5 changes: 4 additions & 1 deletion components/transaction-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {toastInfo} from "contexts/reducers/change-toaster";
import {CopyValue} from "helpers/copy-value";
import {formatStringToCurrency} from "helpers/formatNumber";
import {truncateAddress} from "helpers/truncate-address";
import { isValidUrl } from "helpers/validateUrl";

import {BlockTransaction, Transaction} from "interfaces/transaction";

Expand Down Expand Up @@ -99,7 +100,9 @@ export default function TransactionModal({
}

function getEtherScanHref(tx: string) {
return `${state.Settings?.urls?.blockScan}/${tx}`;
const url = state.Settings?.urls?.blockScan
const validUrl = isValidUrl(url) ? url : `https://${url}`
return `${validUrl}/${tx}`;
}

return (
Expand Down
6 changes: 3 additions & 3 deletions components/web3-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ export default function WebThreeDialog() {

useEffect(() => {
if (![
"/explore",
"/leaderboard",
"/networks",
getURLWithNetwork("/").pathname,
getURLWithNetwork("/bounties").pathname,
getURLWithNetwork("/curators").pathname,
getURLWithNetwork("/oracle").pathname,
getURLWithNetwork("/oracle/new-bounties").pathname,
getURLWithNetwork("/oracle/ready-to-merge").pathname,
"/[network]/bounty",
"/[network]",
].includes(router.pathname))
Expand Down
9 changes: 9 additions & 0 deletions elastic-apm-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require(`dotenv`).config();

module.exports = {
serverUrl: process.env.ELASTIC_APM_SERVER_URL, // E.g. https://my-deployment-name.apm.us-west2.gcp.elastic-cloud.com
secretToken: process.env.ELASTIC_APM_SECRET_TOKEN,
serviceName: process.env.ELASTIC_APM_SERVICE_NAME,
active: process.env.ELASTIC_APM_ACTIVE === "true",
logLevel: process.env.ELASTIC_APM_LOG_LEVEL
}
2 changes: 2 additions & 0 deletions helpers/error-messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const UNAUTHORIZED = `Unauthorized`;
export const INVALID_JWT_TOKEN = `Invalid JWT Token`;
8 changes: 8 additions & 0 deletions helpers/validateUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (err) {
return false;
}
}
5 changes: 4 additions & 1 deletion middleware/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {LogAccess} from "./log-access";
import withCors from "./withCors";
import WithJwt from "./withJwt";

const withProtected = (handler) => withCors(WithJwt(handler))
export {withCors, WithJwt, withProtected}
const RouteMiddleware = (handler) => LogAccess(withCors(WithJwt(handler)));

export {withCors, WithJwt, withProtected, RouteMiddleware};
32 changes: 32 additions & 0 deletions middleware/log-access.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {NextApiHandler, NextApiRequest, NextApiResponse} from "next";

import {debug, log, Logger} from "../services/logging";

export const LogAccess = (handler: NextApiHandler) => {
return async (req: NextApiRequest, res: NextApiResponse) => {
const {url, method} = req as any;
const _query = Object.fromEntries(new URLSearchParams(url.split('?')[1]));
const query = Object.keys(_query).length ? _query : null;
const body = req?.body || null;

const pathname = url.split('/api')[1].replace(/\?.+/g, '');

const rest = (query || body) ? ({ ... query ? {query} : {}, ... body ? {body} : {}}) : '';

log(`${method} access`, pathname);
if (rest)
debug(`${method} access-payload`, pathname, rest);

try {
await handler(req, res);

if (res.statusCode >= 400)
Logger.warn(`Answered with ${res.statusCode}`, res.statusMessage)

debug(`${method} access-end`, pathname)
} catch (e) {
Logger.error(e, `${method}`, pathname, e?.toString(), rest);
}
Logger.changeActionName(``); // clean action just in case;
}
}
53 changes: 14 additions & 39 deletions middleware/withCors.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,27 @@
import Cors from 'cors'
import getConfig from "next/config";

import { info, error } from 'services/logging';

const { publicRuntimeConfig } = getConfig();

const cors = Cors({
methods: ['GET', 'PUT', 'POST'],
origin: [publicRuntimeConfig?.urls?.home || 'http://localhost:3000'],
})

const ignorePaths = ['health', 'ip'];

function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
const WithCors = (handler) =>
(req, res) =>
new Promise((resolve, reject) => {

const next = (e) => {
if (e instanceof Error)
reject(e);
resolve(null)
}

return resolve(result)
})
})
}

function runLogger(req, e = null) {
const {url, method} = req as any;
const search = Object(new URLSearchParams(url.split('?')[1]));
const pathname = url.split('/api')[1].replace(/\?.+/g, '');

if (!ignorePaths.some(k => pathname.includes(k)))
info('Access', {method, pathname, search,});

if (e)
error(e?.message);
}

const withCors = (handler) => {
return async (req, res) => {
runLogger(req);
runMiddleware(req, res, cors)
.then(()=>{
return handler(req, res);
}).catch((e)=>{
runLogger(req, e?.message || e.toString());
return res.status(401).write('Unautorized');
})
};
};

export default withCors;
cors(req, res, next);

}).then(() => handler(req, res))


export default WithCors;
Loading

0 comments on commit 7f10396

Please sign in to comment.