// Licensed to Cloudera, Inc. under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. Cloudera, Inc. licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { ExecutionJob, fetchLogs } from '../../../apps/editor/execution/api'; import { EXECUTABLE_LOGS_UPDATED_TOPIC, ExecutableLogsUpdatedEvent } from '../../../apps/editor/execution/events'; import huePubSub from '../../../utils/huePubSub'; import SqlExecutable, { ExecutionStatus } from './sqlExecutable'; export interface ExecutionError { row: number; column: number; message: string; } export interface ExecutionLogsRaw { jobs: ExecutionJob[]; errors: string[]; } export default class ExecutionLogs { executable: SqlExecutable; fullLog = ''; logLines = 0; jobs: ExecutionJob[] = []; errors: ExecutionError[] = []; constructor(executable: SqlExecutable) { this.executable = executable; } notify(): void { huePubSub.publish(EXECUTABLE_LOGS_UPDATED_TOPIC, this); } reset(): void { this.fullLog = ''; this.logLines = 0; this.jobs = []; this.errors = []; this.notify(); } async fetchLogs(finalFetch?: boolean): Promise { const logDetails = await fetchLogs({ executable: this.executable, fullLog: this.fullLog, jobs: this.jobs }); if (logDetails.logs.indexOf('Unable to locate') === -1 || logDetails.isFullLogs) { this.fullLog = logDetails.logs; } else { this.fullLog += '\n' + logDetails.logs; } this.logLines = this.fullLog.split(/\r\n|\r|\n/).length; if (logDetails.jobs) { logDetails.jobs.forEach(job => { if (typeof job.percentJob === 'undefined') { job.percentJob = -1; } }); this.jobs = logDetails.jobs; } else { this.jobs = []; } huePubSub.publish(EXECUTABLE_LOGS_UPDATED_TOPIC, this); if (!finalFetch) { const delay = this.executable.getExecutionTime() > 45000 ? 5000 : 1000; const fetchLogsTimeout = window.setTimeout(async () => { // TODO: Fetch logs for ExecutionStatus.streaming? await this.fetchLogs( this.executable.status !== ExecutionStatus.running && this.executable.status !== ExecutionStatus.starting && this.executable.status !== ExecutionStatus.waiting ); }, delay); this.executable.addCancellable({ cancel: () => { window.clearTimeout(fetchLogsTimeout); } }); } } toJs(): ExecutionLogsRaw { return { jobs: this.jobs, errors: this.errors.map(err => err.message) }; } }