Skip to content

Commit

Permalink
Merge pull request #85 from buildbarn/feature/build-logs
Browse files Browse the repository at this point in the history
Build Logs
  • Loading branch information
trey-ivy authored Feb 18, 2025
2 parents d3aaeb6 + 9920ec4 commit 46d807b
Show file tree
Hide file tree
Showing 20 changed files with 1,008 additions and 948 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ fragment BazelInvocationInfo on BazelInvocation {
id
buildUUID
}
buildLogs
profile {
id
name
Expand Down
15 changes: 10 additions & 5 deletions frontend/src/components/BazelInvocation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import styles from "../AppBar/index.module.css";
import React, { useState } from "react";
import PortalDuration from "@/components/PortalDuration";
import PortalCard from "@/components/PortalCard";
import { Space, Tabs, Typography } from "antd";
import { Space, Tabs, Tooltip, Typography } from "antd";
import type { TabsProps } from "antd/lib";
import {
BuildOutlined,
Expand All @@ -33,6 +33,7 @@ import {
CodeOutlined,
BranchesOutlined,
InfoCircleOutlined,
CopyFilled,
} from "@ant-design/icons";
import themeStyles from "@/theme/theme.module.css";
import BuildStepResultTag, {
Expand Down Expand Up @@ -78,6 +79,7 @@ const BazelInvocation: React.FC<{
stepLabel,
hostname,
isCiWorker,
buildLogs,

//relatedFiles,
} = invocationOverview;
Expand Down Expand Up @@ -127,7 +129,6 @@ const BazelInvocation: React.FC<{
});

//logs
var buildLogs = "tmp";
const logs: string = buildLogs ?? "no build log data found...";

//build the title
Expand Down Expand Up @@ -207,7 +208,7 @@ const BazelInvocation: React.FC<{
sourceControl.runID == ""
? true
: false;
const hideLogsTab: boolean = true;
const hideLogsTab: boolean = false;
const hideMemoryTab: boolean =
(memoryMetrics?.peakPostGcHeapSize ?? 0) == 0 &&
(memoryMetrics?.peakPostGcHeapSize ?? 0) == 0 &&
Expand Down Expand Up @@ -317,8 +318,12 @@ const BazelInvocation: React.FC<{
<PortalCard
type="inner"
icon={<FileSearchOutlined />}
titleBits={["Build Logs"]}
extraBits={["test"]}
titleBits={["Raw Build Logs"]}
extraBits={[
<Tooltip title="Bazel emits logs in ANSI format a screen at a time. They are presented here concatenated for your convenience.">
<ExclamationCircleOutlined />
</Tooltip>,
]}
>
<LogViewerCard log={logs} copyable={true} />
</PortalCard>
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/components/LogViewer/graphql.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { gql } from "@/graphql/__generated__";

export const GET_BUILD_LOGS = gql(/* GraphQl */ `
query GetBuildLogs ($invocationId: String!){
bazelInvocation(invocationId: $invocationId){
invocationID
buildLogs
}
}
`);
72 changes: 36 additions & 36 deletions frontend/src/components/LogViewer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
import React, { RefAttributes } from 'react';
import { Card, CardProps } from 'antd';
import { AnsiUp } from 'ansi_up';
import linkifyHtml from 'linkify-html';
import { JSX } from 'react/jsx-runtime';
import styles from './index.module.css';
import PortalAlert from '@/components/PortalAlert';
import React, { RefAttributes, useState } from "react";
import { Card, CardProps } from "antd";
import { AnsiUp } from "ansi_up";
import linkifyHtml from "linkify-html";
import { JSX } from "react/jsx-runtime";
import styles from "./index.module.css";
import PortalAlert from "@/components/PortalAlert";
import IntrinsicAttributes = JSX.IntrinsicAttributes;
import { GET_BUILD_LOGS } from "./graphql";
import { GetBuildLogsQueryVariables } from "@/graphql/__generated__/graphql";
import { useQuery } from "@apollo/client";

const ansi = new AnsiUp();
//large logs were causing a stack overflow, so setting a configurable max length and tailing the logs for that length
const MAX_LOG_LENGTH = 50000
const MAX_LOG_LENGTH = 50000;

const FILE_EXTENSIONS_IGNORE = ['.py', '.so'];
const FILE_EXTENSIONS_IGNORE = [".py", ".so"];

interface Props {
invocationId?: string | null;
log?: string | null;
copyable?: boolean;
}
const LogViewer: React.FC<Props> = ({ log }) => {

const LogViewer: React.FC<Props> = ({ log, invocationId }) => {
if (!log) {
return (
<PortalAlert message="There is no information to display" type="warning" showIcon className={styles.alert} />
<PortalAlert
message="There is no log information to display"
type="warning"
showIcon
className={styles.alert}
/>
);
} else {
const innerHTML = ansi.ansi_to_html(log);
return <pre dangerouslySetInnerHTML={{ __html: innerHTML }} />;
}
if (log.length > MAX_LOG_LENGTH) {
log = log.slice(0, MAX_LOG_LENGTH / 2) + "\n\n...\n\n**************LOG CONTENT TRUNCATED********************\n\n...\n\n" + log.slice(log.length - (MAX_LOG_LENGTH / 2), log.length)
}
const innerHTML =
linkifyHtml(ansi.ansi_to_html(log), {
target: '_blank',
validate: {
url: url => {
try {
new URL(url);
return !FILE_EXTENSIONS_IGNORE.some(fileExtension => {
const ignoredFileExtensionRegExp = new RegExp(`\\w\\${fileExtension}.*`);
return ignoredFileExtensionRegExp.test(url);
});
} catch (TypeError) {
return false;
}
},
},
})
return <pre dangerouslySetInnerHTML={{ __html: innerHTML }} />;
};

type LogViewerCardProps = Props & IntrinsicAttributes & CardProps & RefAttributes<HTMLDivElement>;
type LogViewerCardProps = Props &
IntrinsicAttributes &
CardProps &
RefAttributes<HTMLDivElement>;

export const LogViewerCard: React.FC<LogViewerCardProps> = ({ log, bordered, copyable, ...props }) => {
export const LogViewerCard: React.FC<LogViewerCardProps> = ({
log,
invocationId,
bordered,
copyable,
...props
}) => {
return (
<Card bordered={false} {...props}>
<LogViewer log={log} copyable={copyable} />
<LogViewer log={log} invocationId={invocationId} copyable={copyable} />
</Card>
);
};
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/graphql/__generated__/gql.ts

Large diffs are not rendered by default.

16 changes: 12 additions & 4 deletions frontend/src/graphql/__generated__/graphql.ts

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion frontend/src/graphql/__generated__/persisted-documents.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified internal/graphql/testdata/snapshot.db
Binary file not shown.
Loading

0 comments on commit 46d807b

Please sign in to comment.