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

feat: logs page v2 #2701

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open

feat: logs page v2 #2701

wants to merge 50 commits into from

Conversation

ogzhanolguncu
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu commented Dec 4, 2024

What does this PR do?

Fixes # (issue)

If there is not an issue for this, please create one first. This is used to tracking purposes and also helps use understand why this PR exists

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Test A
  • Test B

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a LogsChart component for visualizing log data with a bar chart.
    • Added a DatePickerWithRange component for selecting custom date ranges.
    • Implemented a ResponseStatus filter component for managing HTTP response status filters.
    • Launched a SearchCombobox for enhanced log search capabilities.
    • Added a Timeline component for selecting time ranges for log filtering.
    • Introduced a LogsFilters component to streamline log entry filtering.
    • New LogFooter, LogHeader, LogMetaSection, and LogSection components for detailed log entry views.
    • Added a LoadingRow component to display loading states in the logs table.
  • Improvements

    • Enhanced log querying capabilities with new search parameters and error handling.
    • Improved user interface with a responsive ResizablePanel for log details.
    • Updated the LogsTable for better performance with large datasets.
    • Enhanced timestamp display with a new TimestampInfo component.
  • Bug Fixes

    • Fixed issues related to log fetching and display, ensuring accurate representation of log data.
  • Documentation

    • Updated documentation to reflect new components and features introduced in this release.

ogzhanolguncu and others added 30 commits September 26, 2024 15:57
Add virtual list to table to prevent rendering lots of items at once.

Since we store items in the memory as we fetch more item, list might get
big enough to slow the page down, thats why we have to partially show
them.
Add debounce to combobox filters and add shortcut del/backspace to
remove combobox filters when focused
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
apps/dashboard/lib/trpc/routers/workspace/optIntoBeta.ts (1)

48-51: Consider improving type safety and audit logging

Two suggestions for improvement:

  1. Consider defining an explicit type for betaFeatures to ensure type safety:
interface BetaFeatures {
  rbac: boolean;
  identities: boolean;
  ratelimit: boolean;
  logsPage: boolean;
}
  1. The audit log description could be more specific about the feature being enabled:
-  description: `Opted ${workspace.id} into beta: ${input.feature}`,
+  description: `Enabled beta feature "${input.feature}" for workspace ${workspace.id}`,

Also applies to: 65-71

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6312d and c7f6e62.

📒 Files selected for processing (1)
  • apps/dashboard/lib/trpc/routers/workspace/optIntoBeta.ts (2 hunks)
🔇 Additional comments (3)
apps/dashboard/lib/trpc/routers/workspace/optIntoBeta.ts (3)

48-51: LGTM! Implementation follows existing patterns

The new case for "logsPage" is well-structured and consistent with the existing implementation pattern.


11-11: Verify workspace schema compatibility

The AI summary mentions changes to internal/db/src/schema/workspaces.ts. Let's verify that the schema properly supports the new logsPage beta feature.

Also applies to: 48-51

✅ Verification successful

Schema compatibility confirmed

The workspace schema properly supports the logsPage beta feature. The schema in internal/db/src/schema/workspaces.ts includes logsPage as an optional boolean field within the betaFeatures JSON column, which aligns with its usage in the opt-in router.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the workspace schema includes the logsPage feature
rg -t typescript "logsPage" internal/db/src/schema/workspaces.ts

# Check for any database migrations related to this change
fd -t f -e sql . db/migrations/

Length of output: 235


Script:

#!/bin/bash
# Let's try different approaches to locate the workspace schema and migrations

# Search for workspace schema files
fd workspace.*schema

# Search for workspace-related TypeScript files
fd -e ts workspace

# Search for migrations directory
fd migrations

# Search for logsPage feature across all files
rg "logsPage" 

Length of output: 1224


Script:

#!/bin/bash
# Let's examine the workspace schema implementation
cat internal/db/src/schema/workspaces.ts

# Also check for any recent changes to the schema
rg -B3 -A3 "logsPage" internal/db/src/schema/workspaces.ts

Length of output: 4670


11-11: Verify frontend compatibility with the new feature enum

The addition of "logsPage" to the feature enum is a breaking change that requires corresponding updates in the frontend code.

✅ Verification successful

Frontend is properly integrated with the new feature enum

The codebase analysis shows that the logsPage feature is properly integrated in the frontend:

  • Used in opt-in component (components/opt-in.tsx)
  • Properly gated in navigation (workspace-navigations.tsx)
  • Correctly checked in logs page (logs/page.tsx)
  • Complete logs functionality implementation exists (logs/ directory)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any frontend components or hooks that use this procedure
rg -t typescript -t tsx "optWorkspaceIntoBeta" apps/dashboard/

Length of output: 97


Script:

#!/bin/bash
# Search for any frontend components or hooks that use this procedure with correct file extensions
rg "optWorkspaceIntoBeta" apps/dashboard/ --type-add 'ts:*.{ts,tsx}' -t ts

Length of output: 364


Script:

#!/bin/bash
# Search for usage of the beta feature enum or opt-in functionality in frontend code
rg -A 3 "logsPage|optIntoBeta" apps/dashboard/ --type-add 'ts:*.{ts,tsx}' -t ts

# Also check for any components or pages related to logs functionality
fd -e tsx -e ts . apps/dashboard/ -x rg -l "logs?"

Length of output: 5838

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (11)
apps/dashboard/styles/tailwind/base.css (2)

14-19: LGTM! Consider adding color documentation.

The chart color variables are well-structured using HSL format. The semantic naming and color choices provide good visual distinction for data visualization.

Consider adding a comment block above these variables documenting their intended usage in charts (e.g., which chart types or data series should use which colors).


136-150: Consider using CSS variables for color values.

The code block styling implementation is clean, but the line number color is hardcoded using rgba. Consider using a CSS variable for better theme consistency.

 code .line::before {
   content: counter(step);
   counter-increment: step;
   width: 1rem;
   margin-right: 1.5rem;
   display: inline-block;
   text-align: right;
-  color: rgba(115, 138, 148, 0.4);
+  color: var(--content-subtle);
 }
apps/dashboard/app/(app)/logs/query-state.ts (3)

13-13: Consider reordering status codes logically.

The status codes array mixes success (200) and error codes (400, 500). Consider reordering them for better readability:

-export const STATUSES = [400, 500, 200] as const;
+export const STATUSES = [200, 400, 500] as const;

12-12: Consider exporting TIMELINE_OPTIONS constant.

Since TIMELINE_OPTIONS is used in the Timeline type definition, it should be exported for consistency and potential reuse.

-const TIMELINE_OPTIONS = ["1h", "3h", "6h", "12h", "24h"] as const;
+export const TIMELINE_OPTIONS = ["1h", "3h", "6h", "12h", "24h"] as const;

17-25: Add JSDoc comments for better type documentation.

Consider adding JSDoc comments to document the purpose and constraints of each field in the QuerySearchParams type.

+/**
+ * Search parameters for filtering logs
+ */
 export type QuerySearchParams = {
+  /** Host to filter logs by */
   host: string;
+  /** Specific request ID to search for */
   requestId: string;
+  /** HTTP method to filter by */
   method: string;
+  /** URL path pattern to match */
   path: string;
+  /** Array of HTTP status codes to filter by */
   responseStatuses: ResponseStatus[];
+  /** Start timestamp in milliseconds */
   startTime: number;
+  /** Optional end timestamp in milliseconds */
   endTime?: number;
 };
apps/dashboard/app/(app)/logs/components/filters/components/response-status.tsx (1)

14-18: Consider expanding HTTP status code coverage

The current implementation has several limitations:

  1. Missing 3XX (Redirection) status codes
  2. Using string IDs that are later converted to numbers
  3. Oversimplified grouping of status codes

Consider this improved implementation:

 const checkboxItems = [
-  { id: "500", label: "Error", description: "5XX error codes" },
-  { id: "200", label: "Success", description: "2XX success codes" },
-  { id: "400", label: "Warning", description: "4XX warning codes" },
+  { id: 500, label: "Server Error", description: "5XX server error codes" },
+  { id: 200, label: "Success", description: "2XX success codes" },
+  { id: 400, label: "Client Error", description: "4XX client error codes" },
+  { id: 300, label: "Redirection", description: "3XX redirection codes" },
 ];
apps/dashboard/app/(app)/logs/page.tsx (1)

28-30: Enhance the error message for better user experience

Consider providing a more user-friendly error message when workspace is not found.

-    return <div>Workspace with tenantId: {tenantId} not found</div>;
+    return <div className="text-center p-4">
+      <h2 className="text-lg font-semibold">Workspace Not Found</h2>
+      <p className="text-gray-600">The requested workspace could not be found. Please check your access permissions.</p>
+    </div>;
apps/dashboard/app/(app)/logs/components/logs-table-loading-row.tsx (1)

1-16: Consider extracting grid layout configuration

The grid column sizes are currently hardcoded and duplicated from the parent table. Consider extracting these values into shared constants to maintain consistency and prevent synchronization issues.

+const GRID_LAYOUT = "grid-cols-[166px_72px_20%_1fr]";
+
 export const LoadingRow = () => (
-  <div className="absolute w-full font-mono grid grid-cols-[166px_72px_20%_1fr] text-[13px] leading-[14px] mb-[1px] h-[26px]">
+  <div className={`absolute w-full font-mono grid ${GRID_LAYOUT} text-[13px] leading-[14px] mb-[1px] h-[26px]`}>
apps/dashboard/app/(app)/logs/components/logs-table.tsx (3)

12-14: Consider moving constants to a shared configuration file

These table-related constants might be needed by other components (like LoadingRow). Consider moving them to a shared configuration file to maintain consistency across components.


27-32: Consider optimizing virtualizer configuration

The current configuration works but could be enhanced:

  1. Consider adjusting overscan based on viewport size for better performance
  2. Memoize the estimateSize callback to prevent unnecessary recalculations
+const estimateSize = () => ROW_HEIGHT;
+
 const virtualizer = useVirtualizer({
   count: isLoading ? SKELETON_ROWS : logs?.length ?? 0,
   getScrollElement: () => parentRef.current,
-  estimateSize: () => ROW_HEIGHT,
+  estimateSize,
-  overscan: 5,
+  overscan: Math.ceil(window.innerHeight / ROW_HEIGHT),
 });

66-182: Optimize rendering performance

Consider the following performance optimizations:

  1. Memoize complex className calculations
  2. Extract inline styles to constants
  3. Use CSS Grid template areas for layout
+const VIRTUAL_ITEM_STYLE = (start: number) => ({
+  position: 'absolute',
+  top: `${start}px`,
+  width: '100%',
+});
+
+const useLogStyles = (log: Log, selectedLog: Log | null) => {
+  return useMemo(() => ({
+    className: cn(
+      "font-mono grid grid-cols-[166px_72px_20%_1fr]",
+      "text-[13px] leading-[14px] mb-[1px] rounded-[5px]",
+      "h-[26px] cursor-pointer absolute top-0 left-0 w-full",
+      "hover:bg-background-subtle/90 pl-1",
+      STATUS_STYLES[getStatusClass(log.response_status)],
+      selectedLog && {
+        "opacity-50": selectedLog.request_id !== log.request_id,
+        "opacity-100": selectedLog.request_id === log.request_id,
+      }
+    ),
+    style: VIRTUAL_ITEM_STYLE(virtualRow.start),
+  }), [log, selectedLog]);
+};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c7f6e62 and 92ed909.

📒 Files selected for processing (11)
  • apps/dashboard/app/(app)/logs/components/chart.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/components/filters/components/response-status.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/components/log-details/components/log-footer.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/components/logs-table-loading-row.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/components/logs-table.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/logs-page.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/page.tsx (1 hunks)
  • apps/dashboard/app/(app)/logs/query-state.ts (1 hunks)
  • apps/dashboard/components/timestamp-info.tsx (1 hunks)
  • apps/dashboard/styles/tailwind/base.css (3 hunks)
  • apps/dashboard/styles/tailwind/typography.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/app/(app)/logs/components/log-details/components/log-footer.tsx
  • apps/dashboard/app/(app)/logs/logs-page.tsx
  • apps/dashboard/components/timestamp-info.tsx
  • apps/dashboard/app/(app)/logs/components/chart.tsx
🧰 Additional context used
📓 Learnings (1)
apps/dashboard/app/(app)/logs/components/logs-table.tsx (1)
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2143
File: apps/dashboard/app/(app)/logs/logs-page.tsx:77-83
Timestamp: 2024-12-03T14:17:08.016Z
Learning: The `<LogsTable />` component already implements virtualization to handle large datasets efficiently.
🔇 Additional comments (14)
apps/dashboard/styles/tailwind/base.css (1)

66-71: LGTM! Dark mode colors are well-balanced.

The dark mode chart colors maintain good visibility while preserving the semantic relationship with their light mode counterparts.

apps/dashboard/styles/tailwind/typography.css (1)

149-149: LGTM! Backtick is more appropriate for code snippets.

The change from single quote to backtick is more semantically correct for code snippets.

apps/dashboard/app/(app)/logs/query-state.ts (3)

33-34: Consider timezone handling for date ranges.

Using Date.now() directly might lead to timezone-related issues. Consider using a more robust date handling approach.


37-41: Add time range validation.

The current implementation doesn't validate if startTime is before endTime.


10-10: Verify usage of PickKeys type.

The PickKeys utility type appears to be unused in the current file.

apps/dashboard/app/(app)/logs/components/filters/components/response-status.tsx (4)

1-13: LGTM! Clean imports and well-defined interface.

The imports are appropriate and the CheckboxItemProps interface is well-typed with clear property names.


25-35: Fix state update race condition in handleItemChange

The function uses stale state when updating search params.


50-69: Enhance accessibility for the filter popover

The popover needs proper ARIA attributes and keyboard navigation.


73-86: LGTM! Well-structured checkbox component.

The CheckboxItem component follows good practices:

  • Proper HTML semantics with labels
  • Good accessibility support
  • Clear visual hierarchy
apps/dashboard/app/(app)/logs/page.tsx (5)

1-12: LGTM: Clean initialization with proper imports

The imports are well-organized and the searchParamsCache initialization follows the nuqs library pattern correctly.


14-19: Remove unused params type annotation

The params property is defined in the type annotation but not used in the function.


48-50: Avoid exposing internal error details to users

The error message still includes internal details that should not be exposed to users.


52-52: LGTM: Clean component rendering

The LogsPage component is rendered with appropriate props for initial data and workspace identification.


36-46: Verify log fetching parameters handling

The log fetching includes multiple optional parameters. Let's verify the parameter handling in the clickhouse API.

@chronark
Copy link
Collaborator

chronark commented Dec 4, 2024

CleanShot 2024-12-04 at 16 33 25@2x
the separators are sometimes full width and sometimes not

@chronark
Copy link
Collaborator

chronark commented Dec 4, 2024

CleanShot 2024-12-04 at 16 34 15@2x
meta field has weird corners, probably missing an overflow-hidden

Copy link
Collaborator

@chronark chronark left a comment

Choose a reason for hiding this comment

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

CleanShot 2024-12-04 at 16 43 11@2x

We should not parse the body into key-values, and more importantly we should't uppercase their keys, it loses the information that this was actually json, and while we always expect json, the user might mess up and send us something invalid.

I'm good with optimistically calling JSON.stringify(JSON.parse(body), null, 2) in a try catch to try and format it nicely but falling back to displaying the raw string

<div className="p-2 flex items-center">Time</div>
<div className="p-2 flex items-center">Status</div>
<div className="p-2 flex items-center">Request</div>
<div className="p-2 flex items-center">Message</div>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
<div className="p-2 flex items-center">Message</div>
<div className="p-2 flex items-center">Response Body</div>

<div className="grid grid-cols-[166px_72px_20%_1fr] text-sm font-medium text-[#666666]">
<div className="p-2 flex items-center">Time</div>
<div className="p-2 flex items-center">Status</div>
<div className="p-2 flex items-center">Request</div>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
<div className="p-2 flex items-center">Request</div>
<div className="p-2 flex items-center">Path</div>

@ogzhanolguncu
Copy link
Contributor Author

CleanShot 2024-12-04 at 16 43 11@2x

We should not parse the body into key-values, and more importantly we should't uppercase their keys, it loses the information that this was actually json, and while we always expect json, the user might mess up and send us something invalid.

I'm good with optimistically calling JSON.stringify(JSON.parse(body), null, 2) in a try catch to try and format it nicely but falling back to displaying the raw string

I agree, yeah. Let's do this.

@ogzhanolguncu
Copy link
Contributor Author

CleanShot 2024-12-04 at 16 33 25@2x the separators are sometimes full width and sometimes not

Those are actually padded from left on purpose, but we can change that if we are not happy.

@chronark
Copy link
Collaborator

chronark commented Dec 4, 2024

CleanShot 2024-12-04 at 16 33 25@2x the separators are sometimes full width and sometimes not

Those are actually padded from left on purpose, but we can change that if we are not happy.

It looks a bit off and unintentional, but maybe that's just me
It's a nitpick really and might change with vitors design anyways

let's keep it as is for now to move quickly

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.

2 participants