一.引言
使用 Spark 运行任务打日志经常遇到一个问题就是日志太多,除了自己的 print 日志之外,还有很多 Executor、client 的日志,一方面任务运行期间会占用更多的机器存储,其次也不方便查询自己的 print 日志。下面介绍下常用的日志系统与使用方法。
二.常用日志系统
编辑
常见的日志系统是 Log4j 和 SLF4J,以 Log4j 为例,针对某个任务设置 logLevel 使用如下语法:
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
其中 Level 包含如下几种类型:
LogLevel | Level | Use |
OFF | 2147483647 | 关闭所有日志记录 |
FATAL | 50000 | 如其翻译,致命的错误 |
ERROR | 40000 | 错误信息提示,一般需要 Try Catch |
WARN | 30000 | 潜在错误提示 |
INFO | 20000 | 正常日志信息 |
DEBUG | 10000 | 细粒度日志,用于应用调试 |
TRACE | 5000 | 比调试更细粒度的日志信息 |
ALL | -2147483648 | 打开所有日志记录 |
protected Level(int level, String levelStr, int syslogEquivalent) { super(level, levelStr, syslogEquivalent); } public static final Level OFF = new Level(2147483647, "OFF", 0); public static final Level FATAL = new Level(50000, "FATAL", 0); public static final Level ERROR = new Level(40000, "ERROR", 3); public static final Level WARN = new Level(30000, "WARN", 4); public static final Level INFO = new Level(20000, "INFO", 6); public static final Level DEBUG = new Level(10000, "DEBUG", 7); public static final Level TRACE = new Level(5000, "TRACE", 7); public static final Level ALL = new Level(-2147483648, "ALL", 7);
每一个 level 类都对应一个 level 的 int 字符,如果设置 logLevel 在 DEBUG 级别,则低于其对应 level = 10000 的 TRACE、ALL 类型的日志则不予显示,所以可以根据自己的需求设定 level 级别。Log4j 一般建议使用的类型是 ERROR、WARNING、INFO、DEBUG。
三.Spark Logging
使用 Log4j 或者 SLF4j 时需要通过 XML 或者 log4j.properties 配置相关信息,还需要引入 对应的 log 依赖,经常出现 NoSuchMethod 的冲突,很不方便,spark 自 2.4+ 引入了 Logging,其基于 SLF4j 定义了一个 Trait,使得日志使用只需要继承接口即可。
编辑
trait Logging { // Make the log field transient so that objects with Logging can // be serialized and used on another machine @transient private var log_ : Logger = null ... }
可以看到这里 Logger 用 @transient 关键字修饰保证其序列化时不会报错。
1.输出不同类型日志
import org.apache.spark.internal.Logging object LogUtil extends Logging { def main(args: Array[String]): Unit = { logInfo("LogInfo") logWarning("LogWarning") logError("LogError") } }
使用对应类继承 Logging 类,对应的函数即可输出对应 level 的日志,LogInfo 会输出日志到 Stdout 中,LogWarning,LogError 会输出日志到 Stderr 中,可以根据自己的需要控制输出日志 level。
编辑
2.设置日志 Level
除了使用 Logging 输出不同 level 类型日志外,spark 也支持设定 LogLevel。
val sc = spark.sparkContext sc.setLogLevel("error")
setLogLevel 函数允许我们定义 spark 相关日志的级别,该方法将覆盖任何用户定义的日志级别,通过字符串的类型配置,支持如下日志 level:
ALL, DEBUG, ERROR, FATAL, INFO, OFF, TRACE, WARN 。
def setLogLevel(logLevel: String) { // let's allow lowercase or mixed case too val upperCased = logLevel.toUpperCase(Locale.ROOT) require(SparkContext.VALID_LOG_LEVELS.contains(upperCased), s"Supplied level $logLevel did not match one of:" + s" ${SparkContext.VALID_LOG_LEVELS.mkString(",")}") Utils.setLogLevel(org.apache.log4j.Level.toLevel(upperCased)) }
四.总结
1.日志输出
Logging 仅适用于 Spark 任务日志,下述方法单独使用 log 函数不会输出任何日志。
def main(args: Array[String]): Unit = { logInfo("LogInfo") logWarning("LogWarning") logError("LogError") }
2.日志类型
Logging 使用 SLF4J,extends Logging 接口后,任务启动后会提示:
编辑
3.日志级别
Spark setLevel 方法会覆盖用户定义的其他 logLevel,所以需要注意覆盖关系。
编辑