Skip to content

[FEAT]: System Logs #528

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

Merged
merged 55 commits into from
Sep 10, 2024
Merged

[FEAT]: System Logs #528

merged 55 commits into from
Sep 10, 2024

Conversation

VipinDevelops
Copy link
Contributor

@VipinDevelops VipinDevelops commented Aug 30, 2024

Acceptance Criteria Fulfillment

Created a System page on the app that checks whether the middleware system is fully healthy. Users should be able to view the related logs directly in the UI without needing to open the terminal or any other tool.

  • Add all necessary UI components.
  • Implement server-side event streaming.
  • Add status updates and stream with a timer.
  • Implement a watcher for file changes and stream updated content to the client.
  • Show all logs in real-time.

How it works?

we monitor services (API Server, Redis, Postgres, Sync Server) and stream real-time updates to the client. It checks each service's status through commands or API requests and reads logs when files change. When a service status changes or logs update, the client is notified via a server-sent event stream, keeping the UI updated with the latest information in realtime.

Proposed Changes (including videos or screenshots)

Screencast.from.2024-09-07.23-48-52.webm

Screenshot from 2024-09-07 23-44-07
Screenshot from 2024-09-07 08-20-12

@VipinDevelops VipinDevelops marked this pull request as ready for review August 30, 2024 02:18
@VipinDevelops VipinDevelops changed the title [FEAT]: Service Status [FEAT]: System Status Aug 30, 2024
@samad-yar-khan
Copy link
Contributor

@VipinDevelops why is the grid for log options re-rendering each time I open an overlay and close it ?

Uploading Screen Recording 2024-09-06 at 5.36.19 PM.mov…

const startWatchers = () => {
LOG_FILES.forEach((logFile) => {
const watcher = watch(logFile.path, async (eventType) => {
if (eventType === 'change' && !streamClosed) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put this 'change' string in a const or Enum.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I will Make an Enum

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === 'status-update') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, these string literals should be stored as const or Enums

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

) : (
<FlexBox col gap={2}>
{Object.keys(services).map((serviceName) => {
const ServiceName = serviceName as ServiceNames;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var name should be camelcase

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do it

@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 6, 2024

@VipinDevelops why is the grid for log options re-rendering each time I open an overlay and close it ?

Uploading Screen Recording 2024-09-06 at 5.36.19 PM.mov…

Interesting I haven't added anything in the overlay that might cause Rerendering no state changes and all, can you share the video you tried uploading, please?

Comment on lines 14 to 16
export type ServiceStatusState = {
[key in ServiceNames]: Service;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional:
can be easily written as Record<ServiceNames, Service>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure will do that

services: ServiceStatusState;
loading: boolean;
error?: string;
active: string | null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not string,

saw it being implemented like
const active = useSelector((s) => s.service.active) as ServiceNames;

so initialize it as

active: ServiceNames | null;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then use can remove typecasting from here:
const active = useSelector((s) => s.service.active)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am removing this state to minimize the rerender I will pass the active service name as prop to the overlay page

},
active: null,
loading: true,
error: undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined is usually never a good state to initliase with.
use null instead.

it means an 'intentional empty value'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure will do that

Comment on lines 37 to 35
type SetStatusPayload = {
statuses: { [key in ServiceNames]: Status };
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional, use Record<ServiceNames, Status>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

name: 'services',
initialState,
reducers: {
setActiveService: (state, action: PayloadAction<string | null>) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Payload wont't pe string if you implement previous comments.
instead ServiceNames

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure


const { addPage } = useOverlayPage();

const ServiceTitle: { [key: string]: string } = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Record<ServiceNames, string>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it

Comment on lines 128 to 138
<Box
component="span"
sx={{
display: 'inline-block',
marginLeft: '6px',
width: '10px',
height: '10px',
borderRadius: '50%',
backgroundColor: isUp ? '#28a745' : '#dc3545'
}}
></Box>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional]:
if empty component, <Box .... />

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it

Comment on lines 8 to 17
export type ServiceStatus = {
[key in ServiceNames]: { isUp: boolean };
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional:
Record<ServiceNames, {isUp: boolean}>

const containerRef = useRef<HTMLDivElement>(null);

const services = useSelector(
(state: { service: { services: ServiceStatusState } }) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why add type to state, it's derived directly, no need to pass it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update

@e-for-eshaan
Copy link
Contributor

we can implement the CLI color theme for the borders of the log-cards
image image image image image image

@VipinDevelops
Copy link
Contributor Author

we can implement the CLI color theme for the borders of the log-cards image image image image image image

For Sure Sounds like a nice idea

width: '10px',
height: '10px',
borderRadius: '50%',
backgroundColor: isUp ? '#28a745' : '#dc3545'
Copy link
Contributor

@e-for-eshaan e-for-eshaan Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am assuming this is the online-offline dot on the right of log-title

we have some theme colors inbuilt.

search for how we use theme.colors.success.main and theme.colors.error.main in our code-base.

you won't have to create your own colors (mostly!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great thanks for letting me know , we can use similar colors for log as well but I was thinking the colors are useful because in CLI we have a lot of logs at once but in this case we only show log for one service at a time does these make sense in here ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, i don't understand your comment, re-explain?

the colors that you hardcoded (green and red) can be replaced with our own thematic colors of success and error. that's all i wanted you to change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got you eshan sorry I miss understood

@VipinDevelops
Copy link
Contributor Author

@VipinDevelops why is the grid for log options re-rendering each time I open an overlay and close it ?

Uploading Screen Recording 2024-09-06 at 5.36.19 PM.mov…

Hey @samad-yar-khan You were right Actually I was using a state to update the Active service that caused extra rerenders I removed it and used props instead and now the page render is minimal similar to any other page in the project and it only rerenders when there is a new event pushed and state updated

@VipinDevelops
Copy link
Contributor Author

we can implement the CLI color theme for the borders of the log-cards image image image image image image

Hey @e-for-eshaan this is what you meant right?
image
Looks good?

@e-for-eshaan
Copy link
Contributor

e-for-eshaan commented Sep 6, 2024

No, i meant borders for these, the green ones can be replaced with their respective colors
image

@VipinDevelops
Copy link
Contributor Author

Ohk Got it I will update it ASAP

@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 6, 2024

How about now @e-for-eshaan ? you like it Looking colorful right
image

@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 7, 2024

Hey @e-for-eshaan and @samad-yar-khan ,

Thank you so much for your review—it helped improve the PR's quality alot. I’ve made the requested changes and would appreciate your taking another look.

Thanks again! 😄

@VipinDevelops VipinDevelops changed the title [FEAT]: System Status [FEAT]: System Logs Sep 7, 2024
@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 7, 2024

I would appreciate your reviews as well, @adnanhashmi09 and @shivam-bit. 😄

Copy link
Contributor

@shivam-bit shivam-bit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VipinDevelops please go through Flexbox & Line components with their props.


useEffect(() => {
if (!serviceName) {
router.push('/system');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't hardcode /system , instead use ROUTES.SYSTEM.PATH.
Check codebase for usage of ROUTES

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay use this ROUTES.SYSTEM_LOGS.PATH

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea

const containerRef = useRef<HTMLDivElement>(null);
const services = useSelector((state) => state.service.services);
const logs = useMemo(() => {
return serviceName ? services[serviceName]?.logs || [] : [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on prop types serviceName isn't optional, so it will be always true.
so simply use services[serviceName]?.logs || []

Copy link
Contributor Author

@VipinDevelops VipinDevelops Sep 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in that case we don't even have to redirect to system-status right

Comment on lines 29 to 41
<Box
ref={containerRef}
sx={{
padding: '16px 24px',
borderRadius: 2,
overflowY: 'auto',
maxHeight: '750px',
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
lineHeight: 1.6,
marginTop: '8px'
}}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use FlexBox,
Most of the styling will be done automatically.

Comment on lines 45 to 54
<Typography
key={index}
style={{
marginBottom: '8px',
fontFamily: 'monospace',
padding: '2px'
}}
>
{log}
</Typography>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use our custom <Line> component.
Most of the styling will be done automatically.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am quite sure we already have this const map declared somewhere.
in the cli folder for sure, or check resources.ts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VipinDevelops i think it you can use import { ServiceNames } from '@/constants/service';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shivam-bit You mean no changes in this we can use it, right?

sx={{
fontWeight: '500',
fontSize: '0.95em',
color: isUp ? '#28a745' : '#dc3545',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use theme.colors.success.main and theme.colors.secondary.main
Import useTheme from mui

<FlexBox col relative fullWidth flexGrow={1}>
<FlexBox
alignCenter
sx={{ width: '100%', paddingTop: '8px' }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather then giving width:100% use fullwidth prop on Flexbox
also you can use paddingTop={1} directly on Flexbox

Comment on lines 102 to 120
<CardRoot
key={serviceName}
onClick={() => handleCardClick(serviceKey)}
sx={{
transition: 'box-shadow 0.2s ease',
'&:hover': {
boxShadow: '0 4px 15px rgba(0, 0, 0, 0.1)'
},
backgroundColor: 'rgba(255, 255, 255, 0.05)',
borderRadius: '12px',
border: `1px solid ${
isUp ? borderColor : alpha(theme.colors.error.main, 0.3)
}`,
padding: '16px',
cursor: 'pointer',
position: 'relative',
overflow: 'hidden'
}}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather then using CardRoot use Button, it will work same way with most styling issues sorted for you.

showEvenIfNoTeamSelected={true}
isLoading={loading}
>
{isGithubIntegrated ? <SystemStatus /> : <Loader />}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think system log has to do anything with github integration.

Comment on lines 85 to 93
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<CircularProgress color="primary" size={50} />
</Box>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use <Flexbox alignCenter justifyCenter/> instes of Box`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or <Flexbox centered/>

@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 7, 2024

@VipinDevelops please go through Flexbox & Line components with their props.

Hey @shivam-bit Thanks alot man amazing comments, Here you mean I should Pass props in the FlexBox and Line to provide them styles right ?

@shivam-bit
Copy link
Contributor

@VipinDevelops please go through Flexbox & Line components with their props.

Hey @shivam-bit Thanks alot man amazing comments, Here you mean I should Pass props in the FlexBox and Line to provide them styles right ?

yes correct @VipinDevelops

@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 7, 2024

Hey @shivam-bit, thank you so much for suggesting custom components! Using them really takes away the pain of writing a lot of CSS.
I've made the changes you requested—please take a look.
Thanks again! :)

Comment on lines 130 to 148
<Line
sx={{
fontWeight: '500',
fontSize: '0.95em',
color: isUp ? '#28a745' : '#dc3545',
lineHeight: '1.4'
}}
fontWeight={'500'}
fontSize={'0.95em'}
lineHeight={'1.4'}
white
>
Status:
</Line>
<Line
fontWeight={'500'}
fontSize={'0.95em'}
lineHeight={'1.4'}
color={
isUp
? theme.colors.success.main
: theme.colors.error.main
}
marginLeft={'8px'}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VipinDevelops prefer to use something like <Line bold bigish white>

Copy link
Contributor Author

@VipinDevelops VipinDevelops Sep 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh yeah forgot this one


return (
<FlexBox col gap={2} padding={'16px'}>
<Line bold white fontSize="24px" marginBottom={2}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rathe then fontSize="24px" use huge

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I thought this one looks too small but if you suggest I will update it

<Divider sx={{ mb: 2, backgroundColor: theme.colors.secondary.light }} />

{loading ? (
<FlexBox justifyCenter alignCenter minHeight={'50vh'}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think anywhere we are showing loader with minHeight={'50vh'} , please look into other places where we are showing a loader, or fill as a flexbox prop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep you are correct Sure

@VipinDevelops
Copy link
Contributor Author

VipinDevelops commented Sep 8, 2024

Hey @shivam-bit Please take a look, I made the requested Changes
(btw using custom components is like using tailwind with MUI that's Nice combination 😄 )

@shivam-bit
Copy link
Contributor

@VipinDevelops LGTM!!🚀🚀

@e-for-eshaan
Copy link
Contributor

Big stuff @VipinDevelops 🚀 ! Approved!

Copy link
Contributor

@samad-yar-khan samad-yar-khan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@adnanhashmi09 adnanhashmi09 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff vipin 🚀

@jayantbh jayantbh merged commit 592647b into middlewarehq:main Sep 10, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants