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

experimental: tracing panel #3168

Merged
merged 33 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9b9ebed
add new panel under feature flag
Light2Dark Dec 11, 2024
266d895
add experimental tracing panel
Light2Dark Dec 14, 2024
466fa99
run_id in the backend
mscolnick Dec 14, 2024
b20bffd
hook up the frontend and add some helper funcs
Light2Dark Dec 15, 2024
ce5a196
remove comments
Light2Dark Dec 15, 2024
25d7c22
correct timestamp logic and run ordering
Light2Dark Dec 15, 2024
cef77c2
consolidate docs
Light2Dark Dec 16, 2024
f413faa
dynamic spec generation and refactor some ui components
Light2Dark Dec 17, 2024
94d8cf2
add signals from vega to react component
Light2Dark Dec 17, 2024
67287ff
some refactoring and style changes
Light2Dark Dec 17, 2024
2b44a1b
refactor spec component
Light2Dark Dec 17, 2024
38261f9
remove cell tooltip text
Light2Dark Dec 17, 2024
de6db53
minor refactor
Light2Dark Dec 17, 2024
6077d1c
add some fe tests
Light2Dark Dec 18, 2024
fbf099f
enable scroll and fix vega warnings
Light2Dark Dec 18, 2024
4e65d1b
fix fe timestamp test
Light2Dark Dec 18, 2024
f64214b
reduce hover rerender
Light2Dark Dec 18, 2024
bf6471d
add no traces view
Light2Dark Dec 19, 2024
0b57319
only lookup run_id during a run and unset
Light2Dark Dec 19, 2024
3497d92
add some tests
Light2Dark Dec 19, 2024
f876b40
default chart position to above and refactor
Light2Dark Dec 19, 2024
c624d3f
add small run_id_context test
Light2Dark Dec 20, 2024
718262d
proper reference
Light2Dark Dec 20, 2024
c93e5e0
change icons and optimize chevron
Light2Dark Dec 21, 2024
9e00ea1
fix get run_id_context for error'ed cells
Light2Dark Dec 21, 2024
bac6009
add chart dark mode and colour based on status
Light2Dark Dec 21, 2024
11e278c
add some typesafety for chart spec
Light2Dark Dec 21, 2024
c3615ab
add backend test
Light2Dark Dec 21, 2024
fbe256a
fix hover not cleared
Light2Dark Dec 21, 2024
cf12519
set actions to false and prevent re-post-init
Light2Dark Dec 22, 2024
af524f7
fix idle status cell_runs
Light2Dark Dec 22, 2024
0d6b70e
edit comment
Light2Dark Dec 22, 2024
578e512
remove debug log
Light2Dark Dec 22, 2024
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
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ NODE_OPTIONS=--max_old_space_size=8192 NODE_ENV=development make fe -B
| `py` | Setup | Editable python install; only need to run once |
| `install-all` | Setup | Install everything; takes a long time due to editable install |
| `fe` | Build | Package frontend into `marimo/` |
| `fe-codegen` | Build | Build [api specification](./development_docs/openapi.md) |
| `wheel` | Build | Build wheel |
| `check` | Test | Run all checks |
| `check-test` | Test | Run all checks and tests |
Expand Down
7 changes: 7 additions & 0 deletions development_docs/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,10 @@ marimo development openapi | openapi-spec-validator -
```bash
make fe-codegen
```

You will then need to reinstall the package in `/frontend`:

```bash
cd frontend
pnpm update @marimo-team/marimo-api
```
23 changes: 23 additions & 0 deletions frontend/src/components/buttons/clear-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* Copyright 2024 Marimo. All rights reserved. */

import { cn } from "@/utils/cn";

interface ClearButtonProps {
className?: string;
dataTestId?: string;
onClick: () => void;
}

export const ClearButton: React.FC<ClearButtonProps> = (props) => (
<button
type="button"
data-testid={props.dataTestId}
className={cn(
"text-xs font-semibold text-accent-foreground",
props.className,
)}
onClick={props.onClick}
>
Clear
</button>
);
4 changes: 2 additions & 2 deletions frontend/src/components/editor/cell/CellStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export const CellStatusComponent: React.FC<CellStatusComponentProps> = ({
return null;
};

const ElapsedTime = (props: { elapsedTime: string }) => {
export const ElapsedTime = (props: { elapsedTime: string }) => {
return (
<span className="tracking-wide font-semibold">{props.elapsedTime}</span>
);
Expand All @@ -346,7 +346,7 @@ const LastRanTime = (props: { lastRanTime: number }) => {
);
};

function formatElapsedTime(elapsedTime: number | null) {
export function formatElapsedTime(elapsedTime: number | null) {
if (elapsedTime === null) {
return "";
}
Expand Down
13 changes: 5 additions & 8 deletions frontend/src/components/editor/chrome/panels/logs-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from "react";
import { FileTextIcon } from "lucide-react";
import { CellLink } from "../../links/cell-link";
import { PanelEmptyState } from "./empty-state";
import { ClearButton } from "@/components/buttons/clear-button";

interface Props {
className?: string;
Expand Down Expand Up @@ -35,13 +36,7 @@ export const LogsPanel: React.FC = () => {
return (
<>
<div className="flex flex-row justify-end px-2 py-1">
<button
data-testid="clear-logs-button"
className="text-xs font-semibold text-accent-foreground"
onClick={clearLogs}
>
Clear
</button>
<ClearButton dataTestId="clear-logs-button" onClick={clearLogs} />
</div>
<div className="overflow-auto flex-1">
<LogViewer logs={logs} className="min-w-[300px]" />
Expand Down Expand Up @@ -84,7 +79,9 @@ function formatLog(log: CellLog) {

return (
<>
<span className="flex-shrink-0 text-[var(--gray-10)]">[{timestamp}]</span>
<span className="flex-shrink-0 text-[var(--gray-10)] dark:text-[var(--gray-11)]">
[{timestamp}]
</span>
<span className={cn("flex-shrink-0", color)}>{level}</span>
<span className="flex-shrink-0 text-[var(--gray-10)]">
(<CellLink cellId={log.cellId} />)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* Copyright 2024 Marimo. All rights reserved. */
import { Tracing } from "@/components/tracing/tracing";
import React from "react";

export const TracingPanel: React.FC = () => {
return <Tracing />;
};
9 changes: 9 additions & 0 deletions frontend/src/components/editor/chrome/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
NotebookPenIcon,
BoxIcon,
BotMessageSquareIcon,
ActivityIcon,
} from "lucide-react";

export type PanelType =
Expand All @@ -22,6 +23,7 @@ export type PanelType =
| "variables"
| "outline"
| "dependencies"
| "tracing"
| "packages"
| "documentation"
| "snippets"
Expand Down Expand Up @@ -94,6 +96,13 @@ export const PANELS: PanelDescriptor[] = [
tooltip: "Notebook logs",
position: "sidebar",
},
{
type: "tracing",
Icon: ActivityIcon,
tooltip: "Tracing",
position: "sidebar",
hidden: !getFeatureFlag("tracing"),
},
{
type: "snippets",
Icon: SquareDashedBottomCodeIcon,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/editor/chrome/wrapper/app-chrome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { IfCapability } from "@/core/config/if-capability";
import { PackagesPanel } from "../panels/packages-panel";
import { ChatPanel } from "@/components/chat/chat-panel";
import { TooltipProvider } from "@radix-ui/react-tooltip";
import { TracingPanel } from "../panels/tracing-panel";

const LazyTerminal = React.lazy(() => import("@/components/terminal/terminal"));

Expand Down Expand Up @@ -153,6 +154,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
{selectedPanel === "scratchpad" && <ScratchpadPanel />}
{selectedPanel === "chat" && <ChatPanel />}
{selectedPanel === "logs" && <LogsPanel />}
{selectedPanel === "tracing" && <TracingPanel />}
</TooltipProvider>
</div>
</Suspense>
Expand Down
106 changes: 106 additions & 0 deletions frontend/src/components/tracing/tracing-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* Copyright 2024 Marimo. All rights reserved. */
import type { CellId } from "@/core/cells/ids";
import type { CellRun } from "@/core/cells/runs";
import type { ResolvedTheme } from "@/theme/useTheme";
import type { TopLevelSpec } from "vega-lite";

export const REACT_HOVERED_CELLID = "hoveredCellId";
export const VEGA_HOVER_SIGNAL = "cellHover";

export type ChartPosition = "sideBySide" | "above";
export interface ChartValues {
cell: CellId;
cellNum: number;
startTimestamp: string;
endTimestamp: string;
elapsedTime: string;
status: CellRun["status"];
}

const cellNumField = "cellNum" satisfies keyof ChartValues;
const cellField = "cell" satisfies keyof ChartValues;
const startTimestampField = "startTimestamp" satisfies keyof ChartValues;
const endTimestampField = "endTimestamp" satisfies keyof ChartValues;
const statusField = "status" satisfies keyof ChartValues;

export function createGanttBaseSpec(
chartValues: ChartValues[],
hiddenInputElementId: string,
chartPosition: ChartPosition,
theme: ResolvedTheme,
): TopLevelSpec {
return {
$schema: "https://vega.github.io/schema/vega-lite/v5.json",
background: theme === "dark" ? "black" : undefined,
mark: {
type: "bar",
cornerRadius: 2,
},
params: [
{
name: REACT_HOVERED_CELLID,
bind: { element: `#${hiddenInputElementId}` },
},
{
name: VEGA_HOVER_SIGNAL,
select: {
type: "point",
on: "mouseover",
fields: [cellField],
clear: "mouseout",
},
},
],
height: { step: 23 },
encoding: {
y: {
field: cellNumField,
scale: { paddingInner: 0.2 },
sort: { field: cellNumField },
title: "cell",
axis: chartPosition === "sideBySide" ? null : undefined,
},
x: {
field: startTimestampField,
type: "temporal",
axis: { orient: "top", title: null },
},
x2: {
field: endTimestampField,
type: "temporal",
},
tooltip: [
{
field: startTimestampField,
type: "temporal",
timeUnit: "dayhoursminutesseconds",
title: "Start",
},
{
field: endTimestampField,
type: "temporal",
timeUnit: "dayhoursminutesseconds",
title: "End",
},
],
size: {
value: {
expr: `${REACT_HOVERED_CELLID} == toString(datum.cell) ? 19.5 : 18`,
},
},
color: {
field: statusField,
scale: { domain: ["success", "error"], range: ["#37BE5F", "red"] },
legend: null,
},
},
data: {
values: chartValues,
},
config: {
view: {
stroke: "transparent",
},
},
};
}
66 changes: 66 additions & 0 deletions frontend/src/components/tracing/tracing.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* Copyright 2024 Marimo. All rights reserved. */
import { describe, it, expect, beforeAll, afterAll, vi } from "vitest";
import { formatChartTime } from "./tracing";

describe("formatChartTime", () => {
beforeAll(() => {
// Mock Date to always use UTC
vi.spyOn(global.Date.prototype, "getFullYear").mockImplementation(function (
this: Date,
) {
return this.getUTCFullYear();
});
vi.spyOn(global.Date.prototype, "getMonth").mockImplementation(function (
this: Date,
) {
return this.getUTCMonth();
});
vi.spyOn(global.Date.prototype, "getDate").mockImplementation(function (
this: Date,
) {
return this.getUTCDate();
});
vi.spyOn(global.Date.prototype, "getHours").mockImplementation(function (
this: Date,
) {
return this.getUTCHours();
});
vi.spyOn(global.Date.prototype, "getMinutes").mockImplementation(function (
this: Date,
) {
return this.getUTCMinutes();
});
vi.spyOn(global.Date.prototype, "getSeconds").mockImplementation(function (
this: Date,
) {
return this.getUTCSeconds();
});
vi.spyOn(global.Date.prototype, "getMilliseconds").mockImplementation(
function (this: Date) {
return this.getUTCMilliseconds();
},
);
});

afterAll(() => {
vi.restoreAllMocks();
});

it("should handle a timestamp with milliseconds correctly", () => {
const timestamp = 1_704_067_200.123;
const formattedTime = formatChartTime(timestamp);
expect(formattedTime).toBe("2024-01-01 00:00:00.123");
});

it("should handle a timestamp at the start of the year correctly", () => {
const timestamp = 1_704_067_200;
const formattedTime = formatChartTime(timestamp);
expect(formattedTime).toBe("2024-01-01 00:00:00.000");
});

it("should handle a timestamp at the end of the year correctly", () => {
const timestamp = 1_704_067_199;
const formattedTime = formatChartTime(timestamp);
expect(formattedTime).toBe("2023-12-31 23:59:59.000");
});
});
Loading
Loading