scala - sparkcore - spark spark jar




Anwendungsprotokolle in Logback von Spark trennen loggt in log4j (2)

Ich habe ein Scala Maven-Projekt, das Spark verwendet, und ich versuche, Protokollierung mit Logback zu implementieren. Ich kompiliere meine Anwendung in einem Jar und stelle sie auf einer EC2-Instanz bereit, auf der die Spark-Distribution installiert ist. Meine pom.xml enthält Abhängigkeiten für Spark und Logback wie folgt:

        <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>

Wenn ich meine Spark-Anwendung einreiche, drucke ich die Slf4j-Bindung in der Befehlszeile aus. Wenn ich den Jar-Code mit Java ausfühle, ist die Bindung an Logback. Wenn ich Spark (dh Spark-Submit) verwende, ist die Bindung jedoch an log4j gebunden.

  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)

Erträge

Logger Instance: org.slf4j.impl.[email protected]
Logger Class Type: org.slf4j.impl.Log4jLoggerFactory

Ich verstehe, dass sowohl log4j-1.2.17.jar als auch slf4j-log4j12-1.7.16.jar in / usr / local / spark / slf4j-log4j12-1.7.16.jar sind, und dass Spark höchstwahrscheinlich auf diese slf4j-log4j12-1.7.16.jar verweist, trotz des Ausschlusses in meiner pom.xml, denn wenn ich sie lösche, bekomme ich eine ClassNotFoundException zur Laufzeit von spark-submit.

Meine Frage ist: Gibt es eine Möglichkeit, natives Logging in meiner Anwendung mit Logback zu implementieren, während die internen Protokollierungsfunktionen von Spark erhalten bleiben. Im Idealfall möchte ich meine Logback-Anwendungsprotokolle in eine Datei schreiben und zulassen, dass Spark-Logs weiterhin unter STDOUT angezeigt werden.


Ich hatte das gleiche Problem: Ich habe versucht, eine Logback-Konfigurationsdatei zu verwenden. Ich habe viele Permutationen versucht, aber ich habe es nicht zur Arbeit gebracht.

Ich habe über grizzled-slf4j mit dieser SBT-Abhängigkeit auf Logback zugegriffen:

"org.clapper" %% "grizzled-slf4j" % "1.3.0",

Sobald ich die log4j Konfigurationsdatei hinzugefügt habe:

src/main/resources/log4j.properties/log4j.properties files.

Mein Logging hat gut funktioniert.


Ich hatte ein sehr ähnliches Problem.

Unser Build war ähnlich wie sbt (aber wir verwendeten sbt ) und wird im Detail hier beschrieben: https://.com/a/45479379/1549135

Die logback dieser Lösung funktioniert logback , aber nach dem logback spark werden alle Ausschlüsse und das neue Protokollierungsframework ( logback ) logback da der Klassenpfad von Spark Vorrang vor dem bereitgestellten jar hat. Und da es log4j 1.2.xx enthält, log4j 1.2.xx es es einfach und ignoriert unser Setup.

Lösung

Ich habe mehrere Quellen benutzt. Aber zitiert Spark 1.6.1 Docs (gilt auch für Spark neueste / 2.2.0 ):

spark.driver.extraClassPath

Zusätzliche Klassenpfadeinträge, die dem Klassenpfad des Treibers vorangestellt werden. Hinweis: Im Client-Modus darf diese Konfiguration nicht direkt über die SparkConf in Ihrer Anwendung festgelegt werden, da die Treiber-JVM bereits an dieser Stelle gestartet wurde. Setzen Sie dies stattdessen über die Befehlszeilenoption --driver-class-path oder in der Standardeigenschaftendatei.

spark.executor.extraClassPath

Zusätzliche Classpath-Einträge, die dem Classpath von Executoren vorangestellt werden. Dies liegt hauptsächlich an der Rückwärtskompatibilität mit älteren Spark-Versionen. Benutzer sollten diese Option normalerweise nicht festlegen müssen.

Was hier nicht geschrieben ist, ist, dass extraClassPath Vorrang vor dem Klassenpfad von Spark hat!

So, jetzt sollte die Lösung ziemlich offensichtlich sein.

1. Laden Sie diese Gläser herunter:

- log4j-over-slf4j-1.7.25.jar
- logback-classic-1.2.3.jar
- logback-core-1.2.3.jar

2. Führen Sie die 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

Ich bin mir nur noch nicht sicher, ob Sie diese Gläser auf HDFS setzen können. Wir haben sie lokal neben dem Anwendungsglas.

userClassPathFirst

Merkwürdigerweise habe ich Spark 1.6.1 auch in Docs gefunden:

spark.driver.userClassPathFirst , spark.executor.userClassPathFirst

(Experimentell) Gibt an, ob vom Benutzer hinzugefügte Gläser Vorrang vor den eigenen Gläsern von Spark haben sollen, wenn Klassen im Treiber geladen werden. Diese Funktion kann verwendet werden, um Konflikte zwischen Sparks Abhängigkeiten und Benutzerabhängigkeiten zu reduzieren. Es ist derzeit ein experimentelles Merkmal. Dies wird nur im Cluster-Modus verwendet.

Aber einfach einstellen:

--conf "spark.driver.userClassPathFirst=true" \
--conf "spark.executor.userClassPathFirst=true" \

Hat nicht für mich gearbeitet. Also ich nutze extraClassPath !

Prost!

logback.xml

Wenn Sie Probleme beim Laden von logback.xml in Spark haben, könnte meine Frage hier hilfreich sein: logback.xml Sie die logback.xml an Spark- logback.xml und lesen Sie die Datei aus dem Klassenpfad oder dem benutzerdefinierten Pfad





jar