/**
   * Log the task failure
   *
   * @param taskId the task that failed
   * @param taskType the type of the task
   * @param time the time of the failure
   * @param error the error the task failed with
   * @param failedDueToAttempt The attempt that caused the failure, if any
   */
  public void logTaskFailed(
      TaskID taskId, String taskType, long time, String error, TaskAttemptID failedDueToAttempt) {
    if (disableHistory) {
      return;
    }

    JobID id = taskId.getJobID();
    if (!this.jobId.equals(id)) {
      throw new RuntimeException("JobId from task: " + id + " does not match expected: " + jobId);
    }

    if (null != writers) {
      String failedAttempt = failedDueToAttempt == null ? "" : failedDueToAttempt.toString();
      log(
          writers,
          RecordTypes.Task,
          new Keys[] {
            Keys.TASKID, Keys.TASK_TYPE,
            Keys.TASK_STATUS, Keys.FINISH_TIME,
            Keys.ERROR, Keys.TASK_ATTEMPT_ID
          },
          new String[] {
            taskId.toString(),
            taskType,
            Values.FAILED.name(),
            String.valueOf(time),
            error,
            failedAttempt
          });
    }
  }
  /**
   * Log finish time of task.
   *
   * @param taskId task id
   * @param taskType MAP or REDUCE
   * @param finishTime finish timeof task in ms
   */
  public void logTaskFinished(TaskID taskId, String taskType, long finishTime, Counters counters) {

    if (disableHistory) {
      return;
    }

    JobID id = taskId.getJobID();
    if (!this.jobId.equals(id)) {
      throw new RuntimeException("JobId from task: " + id + " does not match expected: " + jobId);
    }

    if (null != writers) {
      log(
          writers,
          RecordTypes.Task,
          new Keys[] {
            Keys.TASKID, Keys.TASK_TYPE,
            Keys.TASK_STATUS, Keys.FINISH_TIME,
            Keys.COUNTERS
          },
          new String[] {
            taskId.toString(),
            taskType,
            Values.SUCCESS.name(),
            String.valueOf(finishTime),
            counters.makeEscapedCompactString()
          });
    }
  }
  /**
   * Update the finish time of task.
   *
   * @param taskId task id
   * @param finishTime finish time of task in ms
   */
  public void logTaskUpdates(TaskID taskId, long finishTime) {
    if (disableHistory) {
      return;
    }

    JobID id = taskId.getJobID();
    if (!this.jobId.equals(id)) {
      throw new RuntimeException("JobId from task: " + id + " does not match expected: " + jobId);
    }

    if (null != writers) {
      log(
          writers,
          RecordTypes.Task,
          new Keys[] {Keys.TASKID, Keys.FINISH_TIME},
          new String[] {taskId.toString(), String.valueOf(finishTime)});
    }
  }
  /**
   * Log start time of task (TIP).
   *
   * @param taskId task id
   * @param taskType MAP or REDUCE
   * @param startTime startTime of tip.
   */
  public void logTaskStarted(
      TaskID taskId, String taskType, long startTime, String splitLocations) {
    if (disableHistory) {
      return;
    }

    JobID id = taskId.getJobID();
    if (!this.jobId.equals(id)) {
      throw new RuntimeException("JobId from task: " + id + " does not match expected: " + jobId);
    }

    if (null != writers) {
      log(
          writers,
          RecordTypes.Task,
          new Keys[] {
            Keys.TASKID, Keys.TASK_TYPE,
            Keys.START_TIME, Keys.SPLITS
          },
          new String[] {taskId.toString(), taskType, String.valueOf(startTime), splitLocations});
    }
  }