feat: add basic webui
This commit is contained in:
24
packages/observability/error.ts
Normal file
24
packages/observability/error.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { captureException } from '@sentry/nextjs';
|
||||
import { log } from './log';
|
||||
|
||||
export const parseError = (error: unknown): string => {
|
||||
let message = 'An error occurred';
|
||||
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else if (error && typeof error === 'object' && 'message' in error) {
|
||||
message = error.message as string;
|
||||
} else {
|
||||
message = String(error);
|
||||
}
|
||||
|
||||
try {
|
||||
captureException(error);
|
||||
log.error(`Parsing error: ${message}`);
|
||||
} catch (newError) {
|
||||
// biome-ignore lint/suspicious/noConsole: Need console here
|
||||
console.error('Error parsing error:', newError);
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
3
packages/observability/log.ts
Normal file
3
packages/observability/log.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { log as logtail } from '@logtail/next';
|
||||
|
||||
export const log = process.env.NODE_ENV === 'production' ? logtail : console;
|
||||
22
packages/observability/package.json
Normal file
22
packages/observability/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@konobangu/observability",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "git clean -xdf .cache .turbo dist node_modules",
|
||||
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
|
||||
},
|
||||
"dependencies": {
|
||||
"@logtail/next": "^0.1.7",
|
||||
"@konobangu/env": "workspace:*",
|
||||
"@sentry/nextjs": "^8.43.0",
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@konobangu/typescript-config": "workspace:*",
|
||||
"@types/node": "22.10.1",
|
||||
"@types/react": "19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
||||
66
packages/observability/status/index.tsx
Normal file
66
packages/observability/status/index.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'server-only';
|
||||
import { env } from '@konobangu/env';
|
||||
import type { BetterStackResponse } from './types';
|
||||
|
||||
export const Status = async () => {
|
||||
if (!env.BETTERSTACK_API_KEY || !env.BETTERSTACK_URL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let statusColor = 'bg-muted-foreground';
|
||||
let statusLabel = 'Unable to fetch status';
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
'https://uptime.betterstack.com/api/v2/monitors',
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${env.BETTERSTACK_API_KEY}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch status');
|
||||
}
|
||||
|
||||
const { data } = (await response.json()) as BetterStackResponse;
|
||||
|
||||
const status =
|
||||
data.filter((monitor) => monitor.attributes.status === 'up').length /
|
||||
data.length;
|
||||
|
||||
if (status === 0) {
|
||||
statusColor = 'bg-destructive';
|
||||
statusLabel = 'Degraded performance';
|
||||
} else if (status < 1) {
|
||||
statusColor = 'bg-warning';
|
||||
statusLabel = 'Partial outage';
|
||||
} else {
|
||||
statusColor = 'bg-success';
|
||||
statusLabel = 'All systems normal';
|
||||
}
|
||||
} catch {
|
||||
statusColor = 'bg-muted-foreground';
|
||||
statusLabel = 'Unable to fetch status';
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
className="flex items-center gap-3 font-medium text-sm"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={env.BETTERSTACK_URL}
|
||||
>
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span
|
||||
className={`absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 ${statusColor}`}
|
||||
/>
|
||||
<span
|
||||
className={`relative inline-flex h-2 w-2 rounded-full ${statusColor}`}
|
||||
/>
|
||||
</span>
|
||||
<span className="text-muted-foreground">{statusLabel}</span>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
62
packages/observability/status/types.ts
Normal file
62
packages/observability/status/types.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
export type BetterStackResponse = {
|
||||
data: {
|
||||
id: string;
|
||||
type: string;
|
||||
attributes: {
|
||||
url: string;
|
||||
pronounceable_name: string;
|
||||
auth_username: string;
|
||||
auth_password: string;
|
||||
monitor_type: string;
|
||||
monitor_group_id: unknown;
|
||||
last_checked_at: string;
|
||||
status:
|
||||
| 'down'
|
||||
| 'maintenance'
|
||||
| 'paused'
|
||||
| 'pending'
|
||||
| 'up'
|
||||
| 'validating';
|
||||
policy_id: unknown;
|
||||
required_keyword: unknown;
|
||||
verify_ssl: boolean;
|
||||
check_frequency: number;
|
||||
call: boolean;
|
||||
sms: boolean;
|
||||
email: boolean;
|
||||
push: boolean;
|
||||
team_wait: unknown;
|
||||
http_method: string;
|
||||
request_timeout: number;
|
||||
recovery_period: number;
|
||||
request_headers: unknown[];
|
||||
request_body: string;
|
||||
follow_redirects: boolean;
|
||||
remember_cookies: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
ssl_expiration: unknown;
|
||||
domain_expiration: unknown;
|
||||
regions: string[];
|
||||
expected_status_codes: unknown[];
|
||||
port: unknown;
|
||||
confirmation_period: number;
|
||||
paused_at: unknown;
|
||||
paused: boolean;
|
||||
maintenance_from: unknown;
|
||||
maintenance_to: unknown;
|
||||
maintenance_timezone: string;
|
||||
};
|
||||
relationships: {
|
||||
policy: {
|
||||
data: unknown;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
pagination: {
|
||||
first: string;
|
||||
last: string;
|
||||
prev: unknown;
|
||||
next: unknown;
|
||||
};
|
||||
};
|
||||
8
packages/observability/tsconfig.json
Normal file
8
packages/observability/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@konobangu/typescript-config/react-library.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user