Skip to content

Commit ab73d64

Browse files
cacocojenkins
authored and
jenkins
committed
util-slf4j-bridge: Add Slf4jBridge trait for handler installation in class construction
Problem Installation of the SLF4JBridgeHandler should happen as early as possible, ideally during the construction of the main application. Solution Add a mixin which can be composed into extensions of `c.t.app.App` which will attempt installation of the bridge handler via the `Slf4jBridgeUtility` as part of class construction. Move TwitterServer to use the mixin in util-slf4j-jul-bridge. Result A simple way for extensions of `c.t.app.App` to ensure installation of the SLF4JBridgeHandler is attempted during the constructor of the `App`. Differential Revision: https://phabricator.twitter.biz/D827493
1 parent b696fdf commit ab73d64

File tree

5 files changed

+45
-18
lines changed

5 files changed

+45
-18
lines changed

Diff for: CHANGELOG.rst

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ New Features
1616
eden space, sheap, metaspace, survivor space, and old gen) and open file descriptors count in StatsReceiver.
1717
``PHAB_ID=D820472``
1818

19+
* util-slf4j-jul-bridge: Add `Slf4jBridge` trait which can be mixed into extensions of `c.t.app.App` in
20+
order to attempt installation of the `SLF4JBridgeHandler` via the `Slf4jBridgeUtility` in the constructor
21+
of the `c.t.app.App` instance. ``PHAB_ID=D827493``
22+
1923
Runtime Behavior Changes
2024
~~~~~~~~~~~~~~~~~~~~~~~~
2125

Diff for: build.sbt

+14-15
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ val scalacheckLib = "org.scalacheck" %% "scalacheck" % "1.15.4" % "test"
2828
val slf4jApi = "org.slf4j" % "slf4j-api" % slf4jVersion
2929
val snakeyaml = "org.yaml" % "snakeyaml" % "1.24"
3030

31-
3231
def travisTestJavaOptions: Seq[String] = {
3332
// We have some custom configuration for the Travis environment
3433
// https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
@@ -214,10 +213,9 @@ val sharedSettings =
214213
val sharedScala3EnabledSettings =
215214
baseSettings ++
216215
defaultScala3EnabledSettings ++
217-
Seq(libraryDependencies ++= scala3Dependencies) ++
216+
Seq(libraryDependencies ++= scala3Dependencies) ++
218217
Seq(excludeDependencies ++= Seq("org.scala-lang.modules" % "scala-collection-compat_3"))
219218

220-
221219
lazy val noPublishSettings = Seq(
222220
publish / skip := true
223221
)
@@ -245,7 +243,7 @@ def scalatestScalacheckVersionedDep(scalaVersion: String) = {
245243
)
246244
}
247245
}
248-
246+
249247
lazy val util = Project(
250248
id = "util",
251249
base = file(".")
@@ -529,7 +527,7 @@ lazy val utilJvm = Project(
529527
name := "util-jvm",
530528
libraryDependencies ++= Seq(
531529
"org.mockito" % "mockito-core" % mockitoVersion % "test",
532-
) ++ scalatestMockitoVersionedDep(scalaVersion.value)
530+
) ++ scalatestMockitoVersionedDep(scalaVersion.value)
533531
).dependsOn(utilApp, utilCore, utilStats)
534532

535533
lazy val utilLint = Project(
@@ -617,7 +615,7 @@ lazy val utilSlf4jJulBridge = Project(
617615
).settings(
618616
name := "util-slf4j-jul-bridge",
619617
libraryDependencies ++= Seq(slf4jApi, "org.slf4j" % "jul-to-slf4j" % slf4jVersion)
620-
).dependsOn(utilCore, utilSlf4jApi)
618+
).dependsOn(utilCore, utilApp, utilSlf4jApi)
621619

622620
lazy val utilSecurity = Project(
623621
id = "util-security",
@@ -655,18 +653,19 @@ lazy val utilStats = Project(
655653
scalacheckLib,
656654
"com.fasterxml.jackson.core" % "jackson-core" % jacksonVersion,
657655
"com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion,
658-
("com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion exclude ("com.google.guava", "guava")).cross(CrossVersion.for3Use2_13),
656+
("com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion exclude ("com.google.guava", "guava"))
657+
.cross(CrossVersion.for3Use2_13),
659658
"org.mockito" % "mockito-core" % mockitoVersion % "test"
660659
) ++ scalatestMockitoVersionedDep(scalaVersion.value)
661-
++ scalatestScalacheckVersionedDep(scalaVersion.value)
662-
++ {
663-
CrossVersion.partialVersion(scalaVersion.value) match {
664-
case Some((2, major)) if major <= 12 =>
665-
Seq()
666-
case _ =>
667-
Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.3" % "test")
660+
++ scalatestScalacheckVersionedDep(scalaVersion.value)
661+
++ {
662+
CrossVersion.partialVersion(scalaVersion.value) match {
663+
case Some((2, major)) if major <= 12 =>
664+
Seq()
665+
case _ =>
666+
Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.3" % "test")
667+
}
668668
}
669-
}
670669
).dependsOn(utilApp, utilCore, utilLint)
671670

672671
lazy val utilTest = Project(

Diff for: util-slf4j-jul-bridge/src/main/scala/com/twitter/util/logging/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ scala_library(
1010
dependencies = [
1111
"3rdparty/jvm/org/slf4j:jul-to-slf4j",
1212
"3rdparty/jvm/org/slf4j:slf4j-api",
13+
"util/util-app/src/main/scala",
1314
"util/util-core/src/main/scala/com/twitter/concurrent",
1415
"util/util-slf4j-api/src/main/scala/com/twitter/util/logging",
1516
],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.twitter.util.logging
2+
3+
import com.twitter.app.App
4+
5+
/**
6+
* Installing the `SLF4JBridgeHandler` should be done as early as possible in order to capture any
7+
* log statements emitted to JUL. Generally it is best to install the handler in the constructor of
8+
* the main class of your application.
9+
*
10+
* This trait can be mixed into a [[com.twitter.app.App]] type and will attempt to install the
11+
* `SLF4JBridgeHandler` via the [[Slf4jBridgeUtility]] as part of the constructor of the resultant
12+
* class.
13+
* @see [[Slf4jBridgeUtility]]
14+
* @see [[org.slf4j.bridge.SLF4JBridgeHandler]]
15+
* @see [[https://www.slf4j.org/legacy.html Bridging legacy APIs]]
16+
*/
17+
trait Slf4jBridge { self: App =>
18+
19+
/** Attempt Slf4jBridgeHandler installation */
20+
Slf4jBridgeUtility.attemptSlf4jBridgeHandlerInstallation()
21+
}

Diff for: util-slf4j-jul-bridge/src/main/scala/com/twitter/util/logging/Slf4jBridgeUtility.scala

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import org.slf4j.bridge.SLF4JBridgeHandler
1717
* manner. However, using the [[https://logback.qos.ch/manual/configuration.html#LevelChangePropagator Logback LevelChangePropagator]]
1818
* (> 0.9.25) can eliminate this performance impact.
1919
*
20+
* @see [[org.slf4j.bridge.SLF4JBridgeHandler]]
21+
* @see [[https://www.slf4j.org/legacy.html Bridging legacy APIs]]
2022
* @see [[https://www.slf4j.org/legacy.html#jul-to-slf4j SLF4J: jul-to-slf4j bridge]]
2123
*/
2224
object Slf4jBridgeUtility extends Logging {
@@ -30,7 +32,7 @@ object Slf4jBridgeUtility extends Logging {
3032

3133
/* Private */
3234

33-
private val install = Once {
35+
private[this] val install = Once {
3436
if (!SLF4JBridgeHandler.isInstalled && canInstallBridgeHandler) {
3537
SLF4JBridgeHandler.removeHandlersForRootLogger()
3638
SLF4JBridgeHandler.install()
@@ -42,7 +44,7 @@ object Slf4jBridgeUtility extends Logging {
4244
* We do not want to install the bridge handler if the
4345
* `org.slf4j.impl.JDK14LoggerFactory` exists on the classpath.
4446
*/
45-
private def canInstallBridgeHandler: Boolean = {
47+
private[this] def canInstallBridgeHandler: Boolean = {
4648
try {
4749
Class.forName("org.slf4j.impl.JDK14LoggerFactory", false, this.getClass.getClassLoader)
4850
LoggerFactory
@@ -53,7 +55,7 @@ object Slf4jBridgeUtility extends Logging {
5355
)
5456
false
5557
} catch {
56-
case e: ClassNotFoundException =>
58+
case _: ClassNotFoundException =>
5759
true
5860
}
5961
}

0 commit comments

Comments
 (0)