package com.github.minyk.morphlinesmr.job;
import com.github.minyk.morphlinesmr.counter.MorphlinesMRCounters;
import com.github.minyk.morphlinesmr.metrics.MorphlinesMRMetrics;
import info.ganglia.gmetric4j.gmetric.GMetric;
import info.ganglia.gmetric4j.gmetric.GMetricSlope;
import info.ganglia.gmetric4j.gmetric.GMetricType;
import info.ganglia.gmetric4j.gmetric.GangliaException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.util.StringUtils;
import java.io.IOException;
public class MorphlinesJob extends Job {
private static final Log LOG = LogFactory.getLog(MorphlinesJob.class);
private GMetric ganglia;
private boolean reportGanglia = false;
private MorphlinesJob() throws IOException {
super();
}
private MorphlinesJob(JobConf jobConf) throws IOException {
super(jobConf);
}
private MorphlinesJob(JobConf jobConf, String server, int port, GMetric.UDPAddressingMode mode ) throws IOException {
super(jobConf);
ganglia = new GMetric(server, port, mode, 1);
reportGanglia = true;
}
@Override
public boolean monitorAndPrintJob() throws IOException, InterruptedException {
String lastReport = null;
Job.TaskStatusFilter filter;
Configuration clientConf = getConfiguration();
filter = Job.getTaskOutputFilter(clientConf);
JobID jobId = getJobID();
LOG.info("Running job: " + jobId);
int eventCounter = 0;
boolean profiling = getProfileEnabled();
Configuration.IntegerRanges mapRanges = getProfileTaskRange(true);
Configuration.IntegerRanges reduceRanges = getProfileTaskRange(false);
int progMonitorPollIntervalMillis =
Job.getProgressPollInterval(clientConf);
/* make sure to report full progress after the job is done */
boolean reportedAfterCompletion = false;
boolean reportedUberMode = false;
while (!isComplete() || !reportedAfterCompletion) {
if (isComplete()) {
reportedAfterCompletion = true;
} else {
Thread.sleep(progMonitorPollIntervalMillis);
}
if (getStatus().getState() == JobStatus.State.PREP) {
continue;
}
if (!reportedUberMode) {
reportedUberMode = true;
LOG.info("Job " + jobId + " running in uber mode : " + isUber());
}
String report =
(" map " + StringUtils.formatPercent(mapProgress(), 0)+
" reduce " +
StringUtils.formatPercent(reduceProgress(), 0));
if (!report.equals(lastReport)) {
LOG.info(report);
// Report to ganglia
if(reportGanglia) {
gangliaMetric();
}
lastReport = report;
}
TaskCompletionEvent[] events =
getTaskCompletionEvents(eventCounter, 10);
eventCounter += events.length;
printTaskEvents(events, filter, profiling, mapRanges, reduceRanges);
}
boolean success = isSuccessful();
if (success) {
LOG.info("Job " + jobId + " completed successfully");
} else {
LOG.info("Job " + jobId + " failed with state " + getStatus().getState() +
" due to: " + getStatus().getFailureInfo());
}
Counters counters = getCounters();
if (counters != null) {
LOG.info(counters.toString());
}
if(reportGanglia) {
gangliaMetricClean();
}
return success;
}
private void printTaskEvents(TaskCompletionEvent[] events,
Job.TaskStatusFilter filter, boolean profiling, Configuration.IntegerRanges mapRanges,
Configuration.IntegerRanges reduceRanges) throws IOException, InterruptedException {
for (TaskCompletionEvent event : events) {
switch (filter) {
case NONE:
break;
case SUCCEEDED:
if (event.getStatus() ==
TaskCompletionEvent.Status.SUCCEEDED) {
LOG.info(event.toString());
}
break;
case FAILED:
if (event.getStatus() ==
TaskCompletionEvent.Status.FAILED) {
LOG.info(event.toString());
// Displaying the task diagnostic information
TaskAttemptID taskId = event.getTaskAttemptId();
String[] taskDiagnostics = getTaskDiagnostics(taskId);
if (taskDiagnostics != null) {
for (String diagnostics : taskDiagnostics) {
System.err.println(diagnostics);
}
}
}
break;
case KILLED:
if (event.getStatus() == TaskCompletionEvent.Status.KILLED){
LOG.info(event.toString());
}
break;
case ALL:
LOG.info(event.toString());
break;
}
}
}
public static MorphlinesJob getInstance() throws IOException {
return MorphlinesJob.getInstance(new Configuration());
}
public static MorphlinesJob getInstance(Configuration conf) throws IOException {
JobConf jobConf = new JobConf(conf);
return new MorphlinesJob(jobConf);
}
public static MorphlinesJob getInstance(Configuration conf, String server, int port, GMetric.UDPAddressingMode mode) throws IOException {
JobConf jobConf = new JobConf(conf);
return new MorphlinesJob(jobConf, server, port, mode);
}
public static MorphlinesJob getInstance(Configuration conf, String jobName) throws IOException {
MorphlinesJob result = getInstance(conf);
result.setJobName(jobName);
return result;
}
public static MorphlinesJob getInstance(Configuration conf, String jobName, String server, int port, GMetric.UDPAddressingMode mode) throws IOException {
MorphlinesJob result = getInstance(conf, server, port, mode);
result.setJobName(jobName);
return result;
}
private void gangliaMetric() {
int tmax = 60;
int dmax = 0;
String jobName = this.getJobName();
try {
CounterGroup counterGroup = this.getCounters().getGroup(MorphlinesMRCounters.COUNTERGROUP);
ganglia.announce(jobName + ".Map.InputRecords", String.valueOf(this.getCounters().findCounter(TaskCounter.MAP_INPUT_RECORDS).getValue()), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
ganglia.announce(jobName + ".Reduce.OutputRecords", String.valueOf(this.getCounters().findCounter(TaskCounter.REDUCE_OUTPUT_RECORDS).getValue()), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
ganglia.announce(MorphlinesMRMetrics.getExceptionRecordName(jobName), String.valueOf(counterGroup.findCounter(MorphlinesMRCounters.Mapper.COUNTER_EXCEPTIOIN).getValue()), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
ganglia.announce(MorphlinesMRMetrics.getProcessedRecordName(jobName), String.valueOf(counterGroup.findCounter(MorphlinesMRCounters.Mapper.COUNTER_PROCESSED).getValue()), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
} catch (GangliaException e) {
LOG.warn("Cannot report metric to ganglia: " + e.getMessage());
} catch (IOException ioe) {
LOG.warn("Cannot read Counters: " + ioe.getMessage());
}
}
private void gangliaMetricClean() {
int tmax = 60;
int dmax = 0;
String jobName = this.getJobName();
try {
ganglia.announce(jobName + ".Map.InputRecords", String.valueOf(0), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
ganglia.announce(jobName + ".Reduce.OutputRecords", String.valueOf(0), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
ganglia.announce(MorphlinesMRMetrics.getExceptionRecordName(jobName), String.valueOf(0), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
ganglia.announce(MorphlinesMRMetrics.getProcessedRecordName(jobName), String.valueOf(0), GMetricType.INT32, "EA", GMetricSlope.BOTH, tmax, dmax, "morphlines-mr");
} catch (GangliaException e) {
LOG.warn("Cannot report metric to ganglia: " + e.getMessage());
}
}
}