com.aliyun.openservices.odps.console.commands.logview.GetTaskDetailsAction.java Source code

Java tutorial

Introduction

Here is the source code for com.aliyun.openservices.odps.console.commands.logview.GetTaskDetailsAction.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.
 */

package com.aliyun.openservices.odps.console.commands.logview;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import com.aliyun.odps.Instance;
import com.aliyun.odps.OdpsException;
import com.aliyun.openservices.odps.console.ODPSConsoleException;
import com.aliyun.openservices.odps.console.utils.ODPSConsoleUtils;

public class GetTaskDetailsAction extends LogViewBaseAction {

    public static final String ACTION_NAME = "list";

    private static class FuxiInstance {
        public String logid;
        public String id;
        public String status;
        public long startTime;
        public int duration;
    }

    private static class FuxiTask {
        public String name;
        public List<FuxiInstance> instances;
    }

    private static class FuxiJob {
        public String name;
        public List<FuxiTask> tasks;
    }

    private String taskName;
    private boolean raw = false;
    private boolean sortByDuration = false;
    private int limit = -1;
    private boolean reverseOrder = false;
    private boolean selectRunning = false;
    private boolean selectFailed = false;

    @SuppressWarnings("static-access")
    public Options getOptions() {
        Options options = super.getOptions();
        options.addOption(OptionBuilder.withDescription("sort by duration").withLongOpt("duration").create('d'));
        options.addOption(OptionBuilder.withDescription("maximum log process number").withLongOpt("limit").hasArg()
                .create('l'));
        options.addOption(OptionBuilder.withDescription("reverse the sort order of results").withLongOpt("reverse")
                .create('r'));
        options.addOption(
                OptionBuilder.withDescription("select running processes").withLongOpt("running").create('R'));
        options.addOption(
                OptionBuilder.withDescription("select failed processes").withLongOpt("failed").create('F'));
        return options;
    }

    public void configure(CommandLine cl) throws LogViewArgumentException {
        String[] args = cl.getArgs();
        if (args.length == 0) {
            throw new LogViewArgumentException("no instance id");
        } else if (args.length > 1) {
            throw new LogViewArgumentException("unexpected argument: " + args[1]);
        }
        String tokens[] = StringUtils.split(args[0], '/');
        ctx.setInstanceByName(tokens[0]);
        if (tokens.length == 2) {
            taskName = tokens[1];
        } else if (tokens.length > 2) {
            throw new LogViewArgumentException("invalid instance id: " + args[0]);
        }
        raw = cl.hasOption("raw");
        sortByDuration = cl.hasOption('d');
        if (cl.hasOption('l')) {
            limit = Integer.parseInt(cl.getOptionValue('l'));
        }
        reverseOrder = cl.hasOption('r');
        selectRunning = cl.hasOption('R');
        selectFailed = cl.hasOption('F');
    }

    @Override
    public void run() throws OdpsException, ODPSConsoleException {
        Instance inst = ctx.getInstance();
        if (taskName == null) {
            if (ctx.getTask() != null) {
                taskName = ctx.getTask();
            } else {
                taskName = deduceTaskName(inst);
            }
        }
        ctx.setTask(taskName);
        InputStream in = ctx.getTaskDetails(inst, taskName);
        if (raw) {
            byte buffer[] = new byte[5 * 1024];
            try {
                int sz = -1;
                while ((sz = in.read(buffer)) != -1) {
                    String s = new String(buffer, 0, sz, "UTF-8");
                    getWriter().writeResult(s);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            List<FuxiJob> jobs = loadJobsFromStream(in);
            ArrayList<FuxiInstance> flatInsts = new ArrayList<FuxiInstance>();
            for (FuxiJob job : jobs) {
                for (FuxiTask task : job.tasks) {
                    for (FuxiInstance instance : task.instances) {
                        // XXX: Cut off the redundant part of string:
                        // "Odps/JobName/TaskName#Id"
                        String[] tokens = StringUtils.split(instance.id, '/');
                        try {
                            String id = tokens[2];
                            if (selectRunning || selectFailed) {
                                if (selectRunning && instance.status.equals("Running")) {
                                    flatInsts.add(instance);
                                }
                                if (selectFailed && instance.status.equals("Failed")) {
                                    flatInsts.add(instance);
                                }
                            } else {
                                flatInsts.add(instance);
                            }
                            ctx.getLogDir().put(id, instance.logid);
                        } catch (IndexOutOfBoundsException e) {
                            throw new ODPSConsoleException("Bad fuxi instance id " + instance.id);
                        }
                    }
                }
            }
            if (sortByDuration) {
                Collections.sort(flatInsts, new Comparator<FuxiInstance>() {
                    public int compare(FuxiInstance a, FuxiInstance b) {
                        FuxiInstance t1, t2;
                        if (reverseOrder) {
                            t2 = a;
                            t1 = b;
                        } else {
                            t1 = a;
                            t2 = b;
                        }
                        return t1.duration - t2.duration;
                    }
                });
            }

            boolean first = true;
            for (int i = 0; i < flatInsts.size(); i++) {
                if (limit >= 0 && i >= limit) {
                    break;
                }
                if (first) {
                    // Print header
                    getWriter().writeResult(String.format("%1$-20s%2$-25s%3$-10s%4$-15s", "ProcessID", "StartTime",
                            "Duration", "Status"));
                    first = false;
                }
                FuxiInstance instance = flatInsts.get(i);
                String[] tokens = StringUtils.split(instance.id, '/');
                String startTimeStr = "-";
                if (instance.startTime > 0) {
                    startTimeStr = ODPSConsoleUtils.formatDate(new Date(instance.startTime * 1000));
                }
                getWriter().writeResult(String.format("%1$-20s%2$-25s%3$-10s%4$-15s", tokens[2], startTimeStr,
                        instance.duration + "s", instance.status));
            }
        }

    }

    @Override
    public String getActionName() {
        return ACTION_NAME;
    }

    @Override
    public String getHelpPrefix() {
        return "log list <instance id>";
    }

    // An huge hard-wired code parsing detail model from json

    private List<FuxiJob> loadJobsFromStream(InputStream in) throws ODPSConsoleException {
        JSONTokener tokener = new JSONTokener(new BufferedReader(new InputStreamReader(in)));
        try {
            JSONObject obj = new JSONObject(tokener);
            ArrayList<FuxiJob> jobs = new ArrayList<FuxiJob>();
            JSONObject mapReduceJson;
            try {
                mapReduceJson = obj.getJSONObject("mapReduce");
            } catch (JSONException e) {
                return jobs;
            }
            JSONArray jobsJson = mapReduceJson.getJSONArray("jobs");
            for (int i = 0; i < jobsJson.length(); i++) {
                jobs.add(getFuxiJobFromJson(jobsJson.getJSONObject(i)));
            }
            return jobs;
        } catch (JSONException e) {
            e.printStackTrace();
            throw new ODPSConsoleException("Bad json format");
        }
    }

    private FuxiJob getFuxiJobFromJson(JSONObject jobJson) throws JSONException {
        FuxiJob job = new FuxiJob();
        job.name = jobJson.getString("name");
        job.tasks = new ArrayList<FuxiTask>();
        JSONArray tasksJson = jobJson.getJSONArray("tasks");
        for (int i = 0; i < tasksJson.length(); i++) {
            job.tasks.add(getFuxiTaskFromJson(tasksJson.getJSONObject(i)));
        }
        return job;
    }

    private FuxiTask getFuxiTaskFromJson(JSONObject taskJson) throws JSONException {
        FuxiTask task = new FuxiTask();
        task.name = taskJson.getString("name");
        task.instances = new ArrayList<FuxiInstance>();
        JSONArray instancesJson = taskJson.getJSONArray("instances");
        for (int i = 0; i < instancesJson.length(); i++) {
            task.instances.add(getFuxiInstanceFromJson(instancesJson.getJSONObject(i)));
        }
        return task;
    }

    private FuxiInstance getFuxiInstanceFromJson(JSONObject instJson) throws JSONException {
        FuxiInstance inst = new FuxiInstance();
        inst.id = instJson.getString("id");
        inst.logid = instJson.getString("logId");
        inst.status = instJson.getString("status");
        inst.startTime = instJson.getLong("startTime");
        long endTime = instJson.getLong("endTime");
        inst.duration = (int) (endTime - inst.startTime);
        return inst;
    }
}