【Hadoop13】:MapReduce用户日志

前言

我们在编写MapReduce时,有时候需要打印一些日志信息,方便排查错误。例如,在Map任务中,发现某些数据格式错误,不仅仅是跳过这些错误的数据,还需要将错误数据打印到日志中。

YARN有一个日志聚合服务,可以去取到已完成的应用的任务日志,并且将其搬移到HDFS中,在那里任务日志被存储在一个容器文件中用于存档。我们在环境搭建的章节,已经开启了日志聚合服务。

使用日志

提交到YARN的任务,在执行时会产生一个日志文件(称作syslog),一个保存发送到标准输出数据的文件(称作stdout),一个保存标准错误的文件(称作stderr)。下面通过程序演示。

WordCountMapper代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class WordCountMapper extends Mapper<LongWritable, Text, Text, VIntWritable> {

// 定义一个Logger
// 这里使用的Commons Logging API
// 实际上可以使用任何能写入log4j日志的API都行
private static final Log LOG = LogFactory.getLog(WordCountMapper.class);

private static Text outKey = new Text();
private static VIntWritable outValue = new VIntWritable(1);

@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String str = value.toString();
// 将数据写入到syslog文件中
LOG.info(str);
// 将数据写入到stdout文件中
System.out.println(str);
// 将数据写入到stderr文件中
System.err.println(str);
for (String word : str.split(" ")) {
outKey.set(word);
context.write(outKey, outValue);
}
}
}

WordCountReducer代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class WordCountReducer extends Reducer<Text, VIntWritable, Text, VIntWritable> {

private static final Log LOG = LogFactory.getLog(WordCountReducer.class);

private static VIntWritable sum = new VIntWritable();

@Override
protected void reduce(Text key, Iterable<VIntWritable> values, Context context) throws IOException, InterruptedException {
int s = 0;
for (VIntWritable value : values) {
s += value.get();
}
// syslog文件
LOG.info("key:" + key.toString() + ", value:" + s);
// stdout文件
System.out.println("key:" + key.toString() + ", value:" + s);
// stderr文件
System.err.println("key:" + key.toString() + ", value:" + s);
sum.set(s);
context.write(key, sum);
}
}

WordCountRunner代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class WordCountRunner extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
if (args.length != 2) {
System.out.println("Usage: WordCountRunner <input path> <output path>");
System.exit(1);
}
Job job = Job.getInstance(this.getConf(), "WordCountExampleWithLog");
job.setJarByClass(WordCountRunner.class);

job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job, new Path(args[0]));

job.setMapperClass(WordCountMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(VIntWritable.class);

job.setReducerClass(WordCountReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(VIntWritable.class);

job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job, new Path(args[1]));

boolean success = job.waitForCompletion(true);
return success ? 0 : 1;
}

public static void main(String[] args) throws Exception {
int code = ToolRunner.run(new WordCountRunner(), args);
System.exit(code);
}
}

查看日志

打开YARN的ResourceManager管理页面(8088端口),找到FINISHED状态的任务。

将最下方的滚动条拖动到最右方,找到Tracking UI项,点击History链接。

在最下方的Successful中,显示了成功完成的Map任务数量和Reduce任务数量。可以分别查看对应的Map日志和Reduce日志。

这里以Map任务为例,点击3,如图所示。

点击logs,进入日志查看页面。

页面中显示了stderrstdout的日志信息,syslog日志由于内容比较多,可以点击超链接查看详情。

注意,默认的日志级别是INFO,因此DEBUG级别的消息不在syslog任务日志文件中出现。然而,有时候又希望看到这些消息。这时可以适当设置mapreduce.map.log.level或者mapreduce.reduce.log.level。例如,我们想将Map任务的日志级别设置为DEBUG,在提交任务时增加-D mapreduce.map.log.level=DEBUG参数即可。

小结

本章介绍了MapReduce中如何打印日志。可以使用将日志信息打印到stderrstdout以及syslog三个日志文件中,分别使用System.err.println()System.out.println()和日志组件的相关方法即可。

如果您觉得不错,请赞赏一下!