Преглед изворни кода

Merge pull request #758 from smiclea/download-all-logs

Add ability to download all logs at once
Daniel Vincze пре 3 година
родитељ
комит
5cbafca2a1

+ 22 - 0
src/components/smart/LogsPage/DownloadsContent.tsx

@@ -22,9 +22,11 @@ import type { Log as LogType } from "@src/@types/Log";
 import { Close } from "@src/components/ui/TextInput";
 import DatetimePicker from "@src/components/ui/DatetimePicker";
 import StatusIcon from "@src/components/ui/StatusComponents/StatusIcon";
+import Button from "@src/components/ui/Button";
 
 import { ThemeProps } from "@src/components/Theme";
 import downloadImage from "./images/download.svg";
+import LoadingButton from "@src/components/ui/LoadingButton";
 
 const Wrapper = styled.div<any>`
   display: flex;
@@ -108,6 +110,7 @@ type Props = {
     endDate?: Date | null
   ) => void;
   generatingDiagnostics: boolean;
+  downloadingAll: boolean;
 };
 @observer
 class DownloadsContent extends React.Component<Props, State> {
@@ -229,6 +232,25 @@ class DownloadsContent extends React.Component<Props, State> {
           <StatusIcon status="UNSCHEDULED" />
           Start and End times must be set in server&apos;s timezone
         </InfoUtc>
+        {this.props.downloadingAll ? (
+          <LoadingButton style={{ marginTop: "32px" }}>
+            Generating Logs ...
+          </LoadingButton>
+        ) : (
+          <Button
+            style={{ marginTop: "32px" }}
+            onClick={() => {
+              this.props.onDownloadClick(
+                "__all__",
+                this.state.startDate,
+                this.state.endDate
+              );
+            }}
+          >
+            Download All Logs
+          </Button>
+        )}
+
         {this.renderLogs()}
       </Wrapper>
     );

+ 6 - 0
src/components/smart/LogsPage/LogsPage.tsx

@@ -126,6 +126,11 @@ class LogsPage extends React.Component<Record<string, never>, State> {
     startDate?: Date | null,
     endDate?: Date | null
   ) {
+    if (logName === "__all__") {
+      logStore.downloadAll(startDate, endDate);
+      return;
+    }
+
     if (logName === "__diagnostics__") {
       logStore.downloadDiagnostics();
       return;
@@ -171,6 +176,7 @@ class LogsPage extends React.Component<Record<string, never>, State> {
           <TabContent>
             <DownloadContent
               logs={logStore.logs}
+              downloadingAll={logStore.downloadingAllLogs}
               onDownloadClick={(l, s, e) => {
                 this.handleDownloadClick(l, s, e);
               }}

+ 60 - 20
src/stores/LogStore.ts

@@ -24,9 +24,40 @@ import configLoader from "@src/utils/Config";
 import apiCaller from "@src/utils/ApiCaller";
 import DateUtils from "@src/utils/DateUtils";
 import DomUtils from "@src/utils/DomUtils";
+import ObjectUtils from "@src/utils/ObjectUtils";
 import notificationStore from "./NotificationStore";
 
 const MAX_STREAM_LINES = 200;
+
+const generateUrlForLog = (
+  logName: string,
+  startDate?: Date | null,
+  endDate?: Date | null
+): string => {
+  const token = cookie.get("token") || "null";
+  let url = `${configLoader.config.servicesUrls.coriolisLogs}/${logName}?auth_type=keystone&auth_token=${token}`;
+  if (startDate) {
+    url += `&start_date=${DateUtils.toUnix(startDate)}`;
+  }
+  if (endDate) {
+    url += `&end_date=${DateUtils.toUnix(endDate)}`;
+  }
+  return url;
+};
+
+const downloadDiagnosticsIntoZip = async (zipRef: JSZip): Promise<void> => {
+  const baseUrl = `${configLoader.config.servicesUrls.coriolis}/${apiCaller.projectId}`;
+  const [diagnosticsResp, replicasResp, migrationsResp] = await Promise.all([
+    apiCaller.send({ url: `${baseUrl}/diagnostics` }),
+    apiCaller.send({ url: `${baseUrl}/replicas?show_deleted=true` }),
+    apiCaller.send({ url: `${baseUrl}/migrations?show_deleted=true` }),
+  ]);
+
+  zipRef.file("diagnostics.json", JSON.stringify(diagnosticsResp.data));
+  zipRef.file("replicas.json", JSON.stringify(replicasResp.data));
+  zipRef.file("migrations.json", JSON.stringify(migrationsResp.data));
+};
+
 class LogStore {
   @observable logs: Log[] = [];
 
@@ -36,6 +67,8 @@ class LogStore {
 
   @observable generatingDiagnostics = false;
 
+  @observable downloadingAllLogs = false;
+
   @action async getLogs(options?: { showLoading?: boolean }) {
     if (options && options.showLoading) {
       this.loading = true;
@@ -55,36 +88,43 @@ class LogStore {
     }
   }
 
+  @action async downloadAll(startDate?: Date | null, endDate?: Date | null) {
+    this.downloadingAllLogs = true;
+    await ObjectUtils.waitFor(() => this.logs.length > 0);
+    const logFilesResponses = await Promise.all(
+      this.logs.map(async log => ({
+        name: log.log_name,
+        content: await apiCaller.send({
+          url: generateUrlForLog(log.log_name, startDate, endDate),
+        }),
+      }))
+    );
+    const zip = new JSZip();
+    logFilesResponses.forEach(response => {
+      zip.file(`${response.name}.log`, response.content.data);
+    });
+    await downloadDiagnosticsIntoZip(zip);
+    const zipContent = await zip.generateAsync({ type: "blob" });
+    saveAs(zipContent, "logs.zip");
+    runInAction(() => {
+      this.downloadingAllLogs = false;
+    });
+  }
+
   @action download(
     logName: string,
     startDate?: Date | null,
     endDate?: Date | null
   ) {
-    const token = cookie.get("token") || "null";
-    let url = `${configLoader.config.servicesUrls.coriolisLogs}/${logName}?auth_type=keystone&auth_token=${token}`;
-    if (startDate) {
-      url += `&start_date=${DateUtils.toUnix(startDate)}`;
-    }
-    if (endDate) {
-      url += `&end_date=${DateUtils.toUnix(endDate)}`;
-    }
-
-    DomUtils.executeDownloadLink(url);
+    DomUtils.executeDownloadLink(
+      generateUrlForLog(logName, startDate, endDate)
+    );
   }
 
   @action async downloadDiagnostics() {
     this.generatingDiagnostics = true;
-    const baseUrl = `${configLoader.config.servicesUrls.coriolis}/${apiCaller.projectId}`;
-    const [diagnosticsResp, replicasResp, migrationsResp] = await Promise.all([
-      apiCaller.send({ url: `${baseUrl}/diagnostics` }),
-      apiCaller.send({ url: `${baseUrl}/replicas?show_deleted=true` }),
-      apiCaller.send({ url: `${baseUrl}/migrations?show_deleted=true` }),
-    ]);
-
     const zip = new JSZip();
-    zip.file("diagnostics.json", JSON.stringify(diagnosticsResp.data));
-    zip.file("replicas.json", JSON.stringify(replicasResp.data));
-    zip.file("migrations.json", JSON.stringify(migrationsResp.data));
+    await downloadDiagnosticsIntoZip(zip);
     const zipContent = await zip.generateAsync({ type: "blob" });
     saveAs(zipContent, "diagnostics.zip");
     runInAction(() => {