1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package org.apache.spark.internal 19 20import org.apache.log4j.{Level, LogManager, PropertyConfigurator} 21import org.slf4j.{Logger, LoggerFactory} 22import org.slf4j.impl.StaticLoggerBinder 23 24import org.apache.spark.util.Utils 25 26/** 27 * Utility trait for classes that want to log data. Creates a SLF4J logger for the class and allows 28 * logging messages at different levels using methods that only evaluate parameters lazily if the 29 * log level is enabled. 30 */ 31private[spark] trait Logging { 32 33 // Make the log field transient so that objects with Logging can 34 // be serialized and used on another machine 35 @transient private var log_ : Logger = null 36 37 // Method to get the logger name for this object 38 protected def logName = { 39 // Ignore trailing $'s in the class names for Scala objects 40 this.getClass.getName.stripSuffix("$") 41 } 42 43 // Method to get or create the logger for this object 44 protected def log: Logger = { 45 if (log_ == null) { 46 initializeLogIfNecessary(false) 47 log_ = LoggerFactory.getLogger(logName) 48 } 49 log_ 50 } 51 52 // Log methods that take only a String 53 protected def logInfo(msg: => String) { 54 if (log.isInfoEnabled) log.info(msg) 55 } 56 57 protected def logDebug(msg: => String) { 58 if (log.isDebugEnabled) log.debug(msg) 59 } 60 61 protected def logTrace(msg: => String) { 62 if (log.isTraceEnabled) log.trace(msg) 63 } 64 65 protected def logWarning(msg: => String) { 66 if (log.isWarnEnabled) log.warn(msg) 67 } 68 69 protected def logError(msg: => String) { 70 if (log.isErrorEnabled) log.error(msg) 71 } 72 73 // Log methods that take Throwables (Exceptions/Errors) too 74 protected def logInfo(msg: => String, throwable: Throwable) { 75 if (log.isInfoEnabled) log.info(msg, throwable) 76 } 77 78 protected def logDebug(msg: => String, throwable: Throwable) { 79 if (log.isDebugEnabled) log.debug(msg, throwable) 80 } 81 82 protected def logTrace(msg: => String, throwable: Throwable) { 83 if (log.isTraceEnabled) log.trace(msg, throwable) 84 } 85 86 protected def logWarning(msg: => String, throwable: Throwable) { 87 if (log.isWarnEnabled) log.warn(msg, throwable) 88 } 89 90 protected def logError(msg: => String, throwable: Throwable) { 91 if (log.isErrorEnabled) log.error(msg, throwable) 92 } 93 94 protected def isTraceEnabled(): Boolean = { 95 log.isTraceEnabled 96 } 97 98 protected def initializeLogIfNecessary(isInterpreter: Boolean): Unit = { 99 if (!Logging.initialized) { 100 Logging.initLock.synchronized { 101 if (!Logging.initialized) { 102 initializeLogging(isInterpreter) 103 } 104 } 105 } 106 } 107 108 private def initializeLogging(isInterpreter: Boolean): Unit = { 109 // Don't use a logger in here, as this is itself occurring during initialization of a logger 110 // If Log4j 1.2 is being used, but is not initialized, load a default properties file 111 val binderClass = StaticLoggerBinder.getSingleton.getLoggerFactoryClassStr 112 // This distinguishes the log4j 1.2 binding, currently 113 // org.slf4j.impl.Log4jLoggerFactory, from the log4j 2.0 binding, currently 114 // org.apache.logging.slf4j.Log4jLoggerFactory 115 val usingLog4j12 = "org.slf4j.impl.Log4jLoggerFactory".equals(binderClass) 116 if (usingLog4j12) { 117 val log4j12Initialized = LogManager.getRootLogger.getAllAppenders.hasMoreElements 118 // scalastyle:off println 119 if (!log4j12Initialized) { 120 val defaultLogProps = "org/apache/spark/log4j-defaults.properties" 121 Option(Utils.getSparkClassLoader.getResource(defaultLogProps)) match { 122 case Some(url) => 123 PropertyConfigurator.configure(url) 124 System.err.println(s"Using Spark's default log4j profile: $defaultLogProps") 125 case None => 126 System.err.println(s"Spark was unable to load $defaultLogProps") 127 } 128 } 129 130 if (isInterpreter) { 131 // Use the repl's main class to define the default log level when running the shell, 132 // overriding the root logger's config if they're different. 133 val rootLogger = LogManager.getRootLogger() 134 val replLogger = LogManager.getLogger(logName) 135 val replLevel = Option(replLogger.getLevel()).getOrElse(Level.WARN) 136 if (replLevel != rootLogger.getEffectiveLevel()) { 137 System.err.printf("Setting default log level to \"%s\".\n", replLevel) 138 System.err.println("To adjust logging level use sc.setLogLevel(newLevel). " + 139 "For SparkR, use setLogLevel(newLevel).") 140 rootLogger.setLevel(replLevel) 141 } 142 } 143 // scalastyle:on println 144 } 145 Logging.initialized = true 146 147 // Force a call into slf4j to initialize it. Avoids this happening from multiple threads 148 // and triggering this: http://mailman.qos.ch/pipermail/slf4j-dev/2010-April/002956.html 149 log 150 } 151} 152 153private object Logging { 154 @volatile private var initialized = false 155 val initLock = new Object() 156 try { 157 // We use reflection here to handle the case where users remove the 158 // slf4j-to-jul bridge order to route their logs to JUL. 159 val bridgeClass = Utils.classForName("org.slf4j.bridge.SLF4JBridgeHandler") 160 bridgeClass.getMethod("removeHandlersForRootLogger").invoke(null) 161 val installed = bridgeClass.getMethod("isInstalled").invoke(null).asInstanceOf[Boolean] 162 if (!installed) { 163 bridgeClass.getMethod("install").invoke(null) 164 } 165 } catch { 166 case e: ClassNotFoundException => // can't log anything yet so just fail silently 167 } 168} 169