scala - Separación de los registros de la aplicación en Logback desde Spark Logs en log4j
maven logging (2)
Tuve el mismo problema: estaba tratando de usar un archivo de configuración de logback. Intenté muchas permutaciones, pero no conseguí que funcionara.
Estaba accediendo a logback a través de grizzled-slf4j usando esta dependencia SBT:
"org.clapper" %% "grizzled-slf4j" % "1.3.0",
Una vez que agregué el archivo de configuración log4j:
src/main/resources/log4j.properties/log4j.properties files.
mi registro funcionó bien.
Tengo un proyecto de Scala Maven usando Spark, y estoy intentando implementar el registro usando Logback. Estoy compilando mi aplicación en un contenedor y desplegándola en una instancia EC2 donde está instalada la distribución Spark. Mi pom.xml incluye dependencias para Spark y Logback de la siguiente manera:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${scala.binary.version}</artifactId>
<version>${spark.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Cuando envío mi aplicación Spark, imprimo el enlace slf4j en la línea de comando. Si ejecuto el código de los jars usando java, el enlace es a Logback. Si uso Spark (es decir, spark-submit), sin embargo, el enlace es para log4j.
val logger: Logger = LoggerFactory.getLogger(this.getClass)
val sc: SparkContext = new SparkContext()
val rdd = sc.textFile("myFile.txt")
val slb: StaticLoggerBinder = StaticLoggerBinder.getSingleton
System.out.println("Logger Instance: " + slb.getLoggerFactory)
System.out.println("Logger Class Type: " + slb.getLoggerFactoryClassStr)
rendimientos
Logger Instance: org.slf4j.impl.Log4jLoggerFactory@a64e035
Logger Class Type: org.slf4j.impl.Log4jLoggerFactory
Entiendo que tanto log4j-1.2.17.jar
como slf4j-log4j12-1.7.16.jar
están en / usr / local / spark / jars, y que Spark probablemente está haciendo referencia a estos jar a pesar de la exclusión en mi pom.xml, porque si los elimino me dan una ClassNotFoundException en el tiempo de ejecución de spark-submit.
Mi pregunta es: ¿hay alguna manera de implementar el registro nativo en mi aplicación usando Logback mientras se conservan las capacidades de registro interno de Spark? Idealmente, me gustaría escribir mis registros de aplicación de Logback en un archivo y permitir que los registros de Spark sigan mostrándose en STDOUT.
Me encontré con un problema muy similar.
Nuestra compilación fue similar a la suya (pero usamos sbt
) y se describe en detalle aquí: https://.com/a/45479379/1549135
Ejecutar esta solución localmente funciona bien , pero luego spark-submit
ignoraría todas las exclusiones y el nuevo marco de registro ( logback
) porque el classpath de spark tiene prioridad sobre el jar desplegado. Y dado que contiene log4j 1.2.xx
, simplemente lo cargará e ignorará nuestra configuración.
Solución
He usado varias fuentes. Pero citando Spark 1.6.1 documentos (se aplica a Spark latest / 2.2.0 también):
spark.driver.extraClassPath
Entradas de ruta de clases adicionales para anteponer a la ruta de clase del controlador. Nota: En el modo cliente, esta configuración no se debe establecer a través del SparkConf directamente en su aplicación, porque la JVM del controlador ya ha comenzado en ese punto. En su lugar, establezca esto mediante la opción de línea de comando --driver-class-path o en su archivo de propiedades predeterminado.
spark.executor.extraClassPath
Entradas de classpath adicionales para anteponer a classpath de ejecutores. Esto existe principalmente por compatibilidad con versiones anteriores de Spark. Los usuarios generalmente no deberían necesitar establecer esta opción.
Sin embargo, lo que no está escrito aquí es que extraClassPath
tiene prioridad antes de la ruta de clases predeterminada de Spark.
Entonces, la solución debería ser bastante obvia.
1. Descarga esos frascos:
- log4j-over-slf4j-1.7.25.jar
- logback-classic-1.2.3.jar
- logback-core-1.2.3.jar
2. Ejecute el spark-submit
:
libs="/absolute/path/to/libs/*"
spark-submit /
...
--master yarn /
--conf "spark.driver.extraClassPath=$libs" /
--conf "spark.executor.extraClassPath=$libs" /
...
/my/application/application-fat.jar /
param1 param2
Todavía no estoy seguro si puedes poner esos frascos en HDFS. Los tenemos localmente junto al tarro de la aplicación.
userClassPathFirst
Por extraño que parezca, con Spark 1.6.1
también he encontrado esta opción en documentos:
spark.driver.userClassPathFirst , spark.executor.userClassPathFirst
(Experimental) Si se debe dar preferencia a los jars agregados por el usuario sobre los propios jar de Spark al cargar las clases en el controlador. Esta característica se puede usar para mitigar conflictos entre las dependencias de Spark y las dependencias de los usuarios. Actualmente es una característica experimental. Esto se usa solo en modo de clúster.
Simplemente configurando
--conf "spark.driver.userClassPathFirst=true" /
--conf "spark.executor.userClassPathFirst=true" /
No funcionó para mí ¡Así que estoy extraClassPath
usar extraClassPath
!
¡Aclamaciones!
Cargando logback.xml
Si tiene algún problema al cargar logback.xml
a Spark, mi pregunta aquí podría logback.xml
de ayuda: Pase la propiedad del sistema a la chispa-envíe y lea el archivo de classpath o ruta personalizada