Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refine Sentry setup #1229

Merged
merged 8 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions configs/app/features/sentry.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,51 @@
import type { Feature } from './types';

import app from '../app';
import { getEnvValue } from '../utils';

const dsn = getEnvValue('NEXT_PUBLIC_SENTRY_DSN');
const instance = (() => {
const envValue = getEnvValue('NEXT_PUBLIC_APP_INSTANCE');
if (envValue) {
return envValue;
}

return app.host?.replace('.blockscout.com', '').replaceAll('-', '_');
})();
const environment = getEnvValue('NEXT_PUBLIC_APP_ENV') || 'production';
const release = getEnvValue('NEXT_PUBLIC_GIT_TAG');
const cspReportUrl = (() => {
try {
const url = new URL(getEnvValue('SENTRY_CSP_REPORT_URI') || '');

// https://docs.sentry.io/product/security-policy-reporting/#additional-configuration
url.searchParams.set('sentry_environment', environment);
release && url.searchParams.set('sentry_release', release);

return url.toString();
} catch (error) {
return;
}
})();

const title = 'Sentry error monitoring';

const config: Feature<{ dsn: string; environment: string | undefined; cspReportUrl: string | undefined; instance: string | undefined }> = (() => {
if (dsn) {
const config: Feature<{
dsn: string;
cspReportUrl: string | undefined;
instance: string;
release: string | undefined;
environment: string;
}> = (() => {
if (dsn && instance && environment) {
return Object.freeze({
title,
isEnabled: true,
dsn,
environment: getEnvValue('NEXT_PUBLIC_APP_ENV') || getEnvValue('NODE_ENV'),
cspReportUrl: getEnvValue('SENTRY_CSP_REPORT_URI'),
instance: getEnvValue('NEXT_PUBLIC_APP_INSTANCE'),
cspReportUrl,
instance,
release,
environment,
});
}

Expand Down
2 changes: 1 addition & 1 deletion configs/app/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const UI = Object.freeze({
isHidden: getEnvValue('NEXT_PUBLIC_HIDE_INDEXING_ALERT'),
},
maintenanceAlert: {
message: getEnvValue(process.env.NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE),
message: getEnvValue('NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE'),
},
explorers: {
items: parseEnvJson<Array<NetworkExplorer>>(getEnvValue('NEXT_PUBLIC_NETWORK_EXPLORERS')) || [],
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.eth
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/front
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Etherscan','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_HAS_BEACON_CHAIN=true
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.eth_goerli
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-c
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.localhost
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/front
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.main
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-c
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.main.L2
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-c
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_WEB3_WALLETS=['coinbase']
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.poa_core
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-c
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address','block':'/ethereum/poa/core/block'}}]

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.polygon
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-c
## misc

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
# NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x97fa753626b8d44011d0b9f9a947c735f20b6e895efdee49d7cda76a50001017
NEXT_PUBLIC_HAS_BEACON_CHAIN=false
Expand Down
1 change: 0 additions & 1 deletion configs/envs/.env.rootstock
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ NEXT_PUBLIC_VIEWS_BLOCK_HIDDEN_FIELDS=['burnt_fees','total_reward','nonce']
## misc

# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x97fa753626b8d44011d0b9f9a947c735f20b6e895efdee49d7cda76a50001017
NEXT_PUBLIC_HAS_BEACON_CHAIN=false
Expand Down
55 changes: 0 additions & 55 deletions configs/sentry/nextjs.ts

This file was deleted.

4 changes: 2 additions & 2 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,14 @@ const sentrySchema = yup
.string()
.when('NEXT_PUBLIC_SENTRY_DSN', {
is: (value: string) => Boolean(value),
then: (schema) => schema.required(),
then: (schema) => schema,
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_APP_INSTANCE cannot not be used without NEXT_PUBLIC_SENTRY_DSN'),
}),
NEXT_PUBLIC_APP_ENV: yup
.string()
.when('NEXT_PUBLIC_SENTRY_DSN', {
is: (value: string) => Boolean(value),
then: (schema) => schema.required(),
then: (schema) => schema,
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_APP_ENV cannot not be used without NEXT_PUBLIC_SENTRY_DSN'),
}),
});
Expand Down
4 changes: 2 additions & 2 deletions deploy/values/l2-optimism-goerli/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ frontend:
cpu: 200m
memory: 256Mi
env:
NEXT_PUBLIC_APP_ENV: stable
NEXT_PUBLIC_APP_INSTANCE: base_goerli
NEXT_PUBLIC_APP_ENV: development
NEXT_PUBLIC_APP_INSTANCE: main_L2
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE: validation
NEXT_PUBLIC_NETWORK_LOGO: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/base.svg
NEXT_PUBLIC_NETWORK_ICON: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/base.svg
Expand Down
4 changes: 2 additions & 2 deletions deploy/values/main/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ frontend:

NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE: validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM: https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_APP_ENV: stable
NEXT_PUBLIC_APP_INSTANCE: eth_goerli
NEXT_PUBLIC_APP_ENV: development
NEXT_PUBLIC_APP_INSTANCE: main
NEXT_PUBLIC_STATS_API_HOST: https://stats-test.k8s-dev.blockscout.com/
NEXT_PUBLIC_VISUALIZE_API_HOST: http://visualizer-svc.visualizer-testing.svc.cluster.local/
NEXT_PUBLIC_CONTRACT_INFO_API_HOST: https://contracts-info-test.k8s-dev.blockscout.com
Expand Down
4 changes: 2 additions & 2 deletions deploy/values/review-l2/values.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ frontend:
enabled: false
environment:
NEXT_PUBLIC_APP_ENV:
_default: preview
_default: development
NEXT_PUBLIC_APP_INSTANCE:
_default: base_goerli
_default: review_L2
NEXT_PUBLIC_NETWORK_NAME:
_default: "Base Göerli"
NEXT_PUBLIC_NETWORK_SHORT_NAME:
Expand Down
4 changes: 2 additions & 2 deletions deploy/values/review/values.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ frontend:
enabled: false
environment:
NEXT_PUBLIC_APP_ENV:
_default: preview
_default: development
NEXT_PUBLIC_APP_INSTANCE:
_default: eth_goerli
_default: review
NEXT_PUBLIC_NETWORK_NAME:
_default: Blockscout
NEXT_PUBLIC_NETWORK_ID:
Expand Down
4 changes: 2 additions & 2 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,8 @@ For the smart contract addresses which are [Safe{Core} accounts](https://safe.gl
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_SENTRY_DSN | `string` | Client key for your Sentry.io app | Required | - | `<your-secret>` |
| SENTRY_CSP_REPORT_URI | `string` | URL for sending CSP-reports to your Sentry.io app | - | - | `<your-secret>` |
| NEXT_PUBLIC_APP_ENV | `string` | Current app env (e.g development, review or production). Passed as `environment` property to Sentry config | - | `process.env.NODE_ENV` | `production` |
| NEXT_PUBLIC_APP_INSTANCE | `string` | Name of app instance. Used as custom tag `app_instance` value in the main Sentry scope | - | - | `wonderful_kepler` |
| NEXT_PUBLIC_APP_ENV | `string` | App env (e.g development, review or production). Passed as `environment` property to Sentry config | - | `production` | `production` |
| NEXT_PUBLIC_APP_INSTANCE | `string` | Name of app instance. Used as custom tag `app_instance` value in the main Sentry scope. If not provided, it will be constructed from `NEXT_PUBLIC_APP_HOST` | - | - | `wonderful_kepler` |

&nbsp;

Expand Down
7 changes: 6 additions & 1 deletion lib/hooks/useFetch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ export default function useFetch() {
};

if (!meta?.omitSentryErrorLog) {
Sentry.captureException(new Error('Client fetch failed'), { extra: { ...error, ...meta }, tags: { source: 'fetch' } });
Sentry.captureException(new Error('Client fetch failed'), { tags: {
source: 'fetch',
'source.resource': meta?.resource,
'status.code': error.status,
'status.text': error.statusText,
} });
}

return response.json().then(
Expand Down
7 changes: 6 additions & 1 deletion lib/hooks/useGetCsrfToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ export default function useGetCsrfToken() {
const csrfFromHeader = apiResponse.headers.get('x-bs-account-csrf');

if (!csrfFromHeader) {
Sentry.captureException(new Error('Unable to get csrf token'), { tags: { source: 'csrf_token' } });
Sentry.captureException(new Error('Client fetch failed'), { tags: {
source: 'fetch',
'source.resource': 'csrf',
'status.code': 500,
'status.text': 'Unable to obtain csrf token from header',
} });
return;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/hooks/useRedirectForInvalidAuthToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function useRedirectForInvalidAuthToken() {
const apiToken = cookies.get(cookies.NAMES.API_TOKEN);

if (apiToken && loginUrl) {
Sentry.captureException(new Error('Invalid api token'), { tags: { source: 'invalid_api_token' } });
Sentry.captureException(new Error('Invalid API token'), { tags: { source: 'invalid_api_token' } });
window.location.assign(loginUrl);
}
}
Expand Down
8 changes: 2 additions & 6 deletions configs/sentry/react.ts → lib/sentry/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';

import appConfig from 'configs/app';

Expand All @@ -13,11 +12,8 @@ export const config: Sentry.BrowserOptions | undefined = (() => {
return {
environment: feature.environment,
dsn: feature.dsn,
release: process.env.NEXT_PUBLIC_GIT_TAG || process.env.NEXT_PUBLIC_GIT_COMMIT_SHA,
integrations: [ new BrowserTracing() ],
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
release: feature.release,
enableTracing: false,

// error filtering settings
// were taken from here - https://docs.sentry.io/platforms/node/guides/azure-functions/configuration/filtering/#decluttering-sentry
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as Sentry from '@sentry/react';
import React from 'react';

import { config, configureScope } from 'configs/sentry/react';
import { config, configureScope } from './config';

export default function useConfigSentry() {
React.useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion nextjs/PageNextJs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import React from 'react';
import type { Route } from 'nextjs-routes';

import useAdblockDetect from 'lib/hooks/useAdblockDetect';
import useConfigSentry from 'lib/hooks/useConfigSentry';
import useGetCsrfToken from 'lib/hooks/useGetCsrfToken';
import * as metadata from 'lib/metadata';
import * as mixpanel from 'lib/mixpanel';
import useConfigSentry from 'lib/sentry/useConfigSentry';

type Props = Route & {
children: React.ReactNode;
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@
"@metamask/post-message-stream": "^7.0.0",
"@metamask/providers": "^10.2.1",
"@monaco-editor/react": "^4.4.6",
"@sentry/nextjs": "^7.12.1",
"@sentry/react": "^7.24.0",
"@sentry/tracing": "^7.24.0",
"@sentry/react": "^7.72.0",
"@slise/embed-react": "^2.2.0",
"@tanstack/react-query": "^4.0.10",
"@tanstack/react-query-devtools": "^4.0.10",
Expand Down
5 changes: 5 additions & 0 deletions pages/404.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as Sentry from '@sentry/react';
import React from 'react';

import type { NextPageWithLayout } from 'nextjs/types';
Expand All @@ -10,6 +11,10 @@ import LayoutError from 'ui/shared/layout/LayoutError';
const error = new Error('Not found', { cause: { status: 404 } });

const Page: NextPageWithLayout = () => {
React.useEffect(() => {
Sentry.captureException(new Error('Page not found'), { tags: { source: '404' } });
}, []);

return (
<PageNextJs pathname="/404">
<AppError error={ error }/>
Expand Down
Loading
Loading