Skip to content

Commit

Permalink
Add device log functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
sudharsan-selvaraj committed Apr 10, 2024
1 parent 3e5d49c commit 41a995d
Show file tree
Hide file tree
Showing 17 changed files with 1,751 additions and 1,661 deletions.
2 changes: 2 additions & 0 deletions prisma/migrations/20240409102733_device_logs/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Session" ADD COLUMN "device_logs" TEXT;
75 changes: 38 additions & 37 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,50 @@ generator client {
}

model Build {
id String @id @default(uuid()) @map("id")
name String? @map("name")
sessions Session[] @relation("BuildToSession")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
id String @id @default(uuid()) @map("id")
name String? @map("name")
sessions Session[] @relation("BuildToSession")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
}

model Session {
id String @id @map("id")
buildId String? @map("build_id")
build Build? @relation("BuildToSession", fields: [buildId], references: [id])
name String? @map("name")
status String @default("running") @map("status")
id String @id @map("id")
buildId String? @map("build_id")
build Build? @relation("BuildToSession", fields: [buildId], references: [id])
name String? @map("name")
status String @default("running") @map("status")
desiredCapabilities String @map("desired_capabilities")
sessionCapabilities String @map("session_capabilities")
nodeId String @map("node_id")
hasLiveVideo Boolean @map("has_live_video")
videoRecording String? @map("video_recording")
startTime DateTime @default(now()) @map("start_time")
endTime DateTime? @map("end_time")
failureReason String? @map("failure_reason")
deviceUdid String @map("device_udid")
devicePlatform String @map("device_platform")
deviceVersion String @map("device_version")
deviceName String? @map("device_name")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
sessionLogs SessionLog[] @relation("SessionToSessionLog")
nodeId String @map("node_id")
hasLiveVideo Boolean @map("has_live_video")
videoRecording String? @map("video_recording")
deviceLogs String? @map("device_logs")
startTime DateTime @default(now()) @map("start_time")
endTime DateTime? @map("end_time")
failureReason String? @map("failure_reason")
deviceUdid String @map("device_udid")
devicePlatform String @map("device_platform")
deviceVersion String @map("device_version")
deviceName String? @map("device_name")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
sessionLogs SessionLog[] @relation("SessionToSessionLog")
}

model SessionLog {
id String @id @default(uuid()) @map("id")
sessionId String @map("session_id")
session Session @relation("SessionToSessionLog", fields: [sessionId], references: [id])
commandName String? @map("command_name")
url String @map("url")
method String @map("method")
title String @map("title")
subtitle String? @map("subtitle")
body String? @map("body")
response String @map("response")
screenshot String? @map("screenshot")
isSuccess Boolean? @map("is_success")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
id String @id @default(uuid()) @map("id")
sessionId String @map("session_id")
session Session @relation("SessionToSessionLog", fields: [sessionId], references: [id])
commandName String? @map("command_name")
url String @map("url")
method String @map("method")
title String @map("title")
subtitle String? @map("subtitle")
body String? @map("body")
response String @map("response")
screenshot String? @map("screenshot")
isSuccess Boolean? @map("is_success")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
}
1 change: 1 addition & 0 deletions src/CapabilityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export enum DEVICE_FARM_CAPABILITIES {
MIN_SDK = 'minSDK',
MAX_SDK = 'maxSDK',
FILTER_BY_HOST = 'filterByHost',
SAVE_DEVICE_LOGS = 'saveDeviceLogs',
}

function isCapabilityAlreadyPresent(caps: ISessionCapability, capabilityName: string) {
Expand Down
2 changes: 1 addition & 1 deletion src/modules
18 changes: 15 additions & 3 deletions web/src/api-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ export default class DeviceFarmApiService {
}

public static androidStreamingAppInstalled(udid: string, systemPort: number) {
return apiClient.makePOSTRequest('/installAndroidStreamingApp', {}, {udid, systemPort});
return apiClient.makePOSTRequest('/installAndroidStreamingApp', {}, { udid, systemPort });
}

public static createSession(udid: string, systemPort: number) {
return apiClient.makePOSTRequest('/appiumSession', {}, {udid, systemPort, origin: window.location.origin});
return apiClient.makePOSTRequest(
'/appiumSession',
{},
{ udid, systemPort, origin: window.location.origin },
);
}
public static installWDAOnDevice(udid: string) {
return apiClient.makePOSTRequest('/installiOSWDA', {}, { udid });
Expand Down Expand Up @@ -48,6 +52,14 @@ export default class DeviceFarmApiService {
}

public static closeSession(udid: string) {
return apiClient.makePOSTRequest('/closeSession', {}, {udid, origin: window.location.origin});
return apiClient.makePOSTRequest('/closeSession', {}, { udid, origin: window.location.origin });
}

public static async getDeviceLogs(sessionId: string) {
const response = await apiClient.makeGETRequest(
`/dashboard/session/${sessionId}/device_logs`,
{},
);
return response?.logs || [];
}
}
8 changes: 2 additions & 6 deletions web/src/components/build-container/build-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import AndroidIcon from '../../assets/android-new-icon.svg';
import AppleIcon from '../../assets/apple-new-icon.svg';
import { IBuild } from '../../interfaces/IBuild';
import { ISession } from '../../interfaces/ISession';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';

function BuildContainer({
selectedBuild,
Expand All @@ -18,8 +18,8 @@ function BuildContainer({
builds: IBuild[];
sessions: ISession[];
}) {
const path = window.location.pathname;
const navigate = useNavigate();
const { sessionId } = useParams();

function timeAgo(createdAt: string | number | Date) {
const currentDate = new Date();
Expand All @@ -42,10 +42,6 @@ function BuildContainer({
}
}

const buildId = path.match(/builds\/(.+?)\//)?.[1];
const sessionId = path.match(/session\/(.+?)$/)?.[1];
console.log({ buildId, sessionId });

return (
<div className="build-container">
<div className="build-header">
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/session/capabilities/capabilities.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
flex-direction: column;
max-width: 440px;
margin: 16px;
width:30%;
}

.tabs {
Expand All @@ -24,7 +25,7 @@
}

.tab-content {
max-height: 300px;
height: 100%;
overflow-y: auto;
}

Expand Down
31 changes: 25 additions & 6 deletions web/src/components/session/capabilities/capabilities.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { ISession } from '../../../interfaces/ISession';
import './capabilities.css';

Expand All @@ -14,6 +14,10 @@ enum ActiveTab {
function Capabilities({ session }: CapabilitiesProps) {
const [activeTab, setActiveTab] = useState<ActiveTab>(ActiveTab.DesiredCapabilities);

useEffect(() => {
setActiveTab(ActiveTab.DesiredCapabilities);
}, [session]);

const renderKeyValuePairs = (data: string) => {
const parsedData = JSON.parse(data);
return Object.entries(parsedData).map(([key, value]) => (
Expand All @@ -37,11 +41,13 @@ function Capabilities({ session }: CapabilitiesProps) {
<img
src={source}
style={{
maxHeight: '40%',
width: '250px',
height: 'auto',
margin: 'auto',
}}
/>
);
} else {
} else if (session.videoRecording) {
return (
<video
controls
Expand All @@ -50,14 +56,27 @@ function Capabilities({ session }: CapabilitiesProps) {
}`}
/>
);
} else {
return (
<div
style={{
width: '100%',
height: '300px',
paddingTop: '25%',
textAlign: 'center',
fontSize: '18px',
}}
>
<b>Video recording not available</b>
</div>
);
}
}

return (
<div className="capabilities">
{getVideoCompoment()}
console.log(session);
<div className="download">
{/* <div className="download">
<a
href={`${window.location.protocol + '//' + window.location.host}/device-farm/assets/${
session.videoRecording
Expand All @@ -66,7 +85,7 @@ function Capabilities({ session }: CapabilitiesProps) {
>
Download
</a>
</div>
</div> */}
<div className="tabs">
<div
className={`tab-header ${activeTab === ActiveTab.DesiredCapabilities ? 'active' : ''}`}
Expand Down
16 changes: 16 additions & 0 deletions web/src/components/session/session-logs/device-logs/device-log.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.device-logs {
background-color: #010409;
color: #e6edf4;
padding: 16px;
}

.log-line {
word-wrap: break-word;
padding-right: 10px;
margin-right: 10px;
}

.log-line-number {
color: #848d97;
margin-right: 10px;
}
21 changes: 21 additions & 0 deletions web/src/components/session/session-logs/device-logs/device-log.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IDeviceLogs } from '../../../../interfaces/IDeviceLogs';
import './device-log.css';

interface DeviceLogsProps {
deviceLogs: IDeviceLogs[] | null;
}

function DeviceLogs({ deviceLogs }: DeviceLogsProps) {
return (
<div className="device-logs">
{deviceLogs?.map((log, i) => (
<div className="log-line" key={`log-line-${i}`}>
<span className="log-line-number">{i + 1}</span>
{log.message}
</div>
))}
</div>
);
}

export default DeviceLogs;
4 changes: 2 additions & 2 deletions web/src/components/session/session-logs/session-logs.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
font-size: 12px;
display: flex;
flex-direction: column;
width: 100%;
width: 70%;
margin: 16px;
border: 1px solid #808080;
height: calc(100% - 30px);
}

.session-logs .tabs {
Expand Down Expand Up @@ -43,6 +44,5 @@
}

.session-logs .tab-content {
max-height: 400px;
overflow-y: auto;
}
20 changes: 17 additions & 3 deletions web/src/components/session/session-logs/session-logs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import './session-logs.css';
import { ISessionLogs } from '../../../interfaces/ISessionLogs';
import TextLogs from './text-logs/text-logs';
import DeviceFarmApiService from '../../../api-service';
import DeviceLogs from './device-logs/device-log';
import { IDeviceLogs } from '../../../interfaces/IDeviceLogs';
import { useParams } from 'react-router-dom';
import { ISession } from '../../../interfaces/ISession';

enum ActiveTab {
TextLogs = 'textLogs',
Expand All @@ -11,18 +15,27 @@ enum ActiveTab {
AppProfiling = 'appProfiling',
}

function SessionLogs({ sessionId }: any) {
function SessionLogs(props: { session: ISession }) {
const { session } = props;
const [url, setBaseUrl] = useState<string>();
const { sessionId } = useParams();
const [sessionLogs, setSessionLogs] = useState<ISessionLogs[]>([]);
const [deviceLogs, setDeviceLogs] = useState<IDeviceLogs[]>([]);
const [showImages, setShowImages] = useState(false);
const [showErrorsOnly, setShowErrorsOnly] = useState(false);
const [activeTab, setActiveTab] = useState<ActiveTab>(ActiveTab.TextLogs);

useEffect(() => {
async function init() {
try {
const sessionLogs = await DeviceFarmApiService.getSessionLogs(sessionId);
const sessionLogs = await DeviceFarmApiService.getSessionLogs(sessionId as string);
setSessionLogs(sessionLogs);
if (session.deviceLogs) {
const deviceLogs = await DeviceFarmApiService.getDeviceLogs(sessionId as string);
setDeviceLogs(deviceLogs);
} else {
setDeviceLogs([]);
}
const baseURL = window.location.protocol + '//' + window.location.host;
setBaseUrl(baseURL);
console.log('Base URL:', url);
Expand All @@ -31,7 +44,7 @@ function SessionLogs({ sessionId }: any) {
}
}
init();
}, []);
}, [sessionId, url]);

const handleTabClick = (tab: ActiveTab) => {
setActiveTab(tab);
Expand Down Expand Up @@ -94,6 +107,7 @@ function SessionLogs({ sessionId }: any) {
baseUrl={url}
/>
)}
{activeTab === ActiveTab.DeviceLogs && <DeviceLogs deviceLogs={deviceLogs} />}
</div>
</div>
);
Expand Down
5 changes: 5 additions & 0 deletions web/src/interfaces/IDeviceLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IDeviceLogs {
timestamp: string;
level: string;
message: string;
}
1 change: 1 addition & 0 deletions web/src/interfaces/ISession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface ISession {
hasLiveVideo: boolean;
videoRecording: string | null;
startTime: string;
deviceLogs: string;
endTime: string | null;
failureReason: string | null;
deviceUDID: string;
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/Session/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function Session() {
<SessionInfo session={selectedSession} />
<div className="session-body">
<Capabilities session={selectedSession} />
<SessionLogs sessionId={selectedSession.id} />
<SessionLogs session={selectedSession} />
</div>
</div>
)}
Expand Down
Loading

0 comments on commit 41a995d

Please sign in to comment.