16
16
17
17
package org .typelevel .log4cats .slf4j .internal
18
18
19
- import org .typelevel .log4cats .*
20
- import cats .syntax .all .*
21
19
import cats .effect .*
22
- import org .slf4j .Logger as JLogger
23
- import org .slf4j .MDC
24
-
25
- import scala .annotation .nowarn
20
+ import org .slf4j .{Logger as JLogger , MDC }
21
+ import org .typelevel .log4cats .*
26
22
27
23
private [slf4j] object Slf4jLoggerInternal {
28
24
@@ -36,106 +32,127 @@ private[slf4j] object Slf4jLoggerInternal {
36
32
def apply (t : Throwable )(msg : => String ): F [Unit ]
37
33
}
38
34
39
- // Need this to make sure MDC is correctly cleared before logging
40
- private [this ] def noContextLog [F [_]](isEnabled : F [Boolean ], logging : () => Unit )(implicit
41
- F : Sync [F ]
42
- ): F [Unit ] =
43
- contextLog[F ](isEnabled, Map .empty, logging)
44
-
45
- private [this ] def contextLog [F [_]](
46
- isEnabled : F [Boolean ],
47
- ctx : Map [String , String ],
48
- logging : () => Unit
49
- )(implicit F : Sync [F ]): F [Unit ] = {
50
-
51
- val ifEnabled = F .delay {
52
- val backup =
53
- try MDC .getCopyOfContextMap()
54
- catch {
55
- case e : IllegalStateException =>
56
- // MDCAdapter is missing, no point in doing anything with
57
- // the MDC, so just hope the logging backend can salvage
58
- // something.
59
- logging()
60
- throw e
61
- }
62
-
63
- try {
64
- // Once 2.12 is no longer supported, change this to MDC.setContextMap(ctx.asJava)
65
- MDC .clear()
66
- ctx.foreach { case (k, v) => MDC .put(k, v) }
67
- logging()
68
- } finally
69
- if (backup eq null ) MDC .clear()
70
- else MDC .setContextMap(backup)
71
- }
72
-
73
- isEnabled.ifM(
74
- ifEnabled,
75
- F .unit
76
- )
77
- }
78
-
79
- @ nowarn(" msg=used" )
80
- final class Slf4jLogger [F [_]](val logger : JLogger , sync : Sync .Type = Sync .Type .Delay )(implicit
35
+ final class Slf4jLogger [F [_]](
36
+ val logger : JLogger ,
37
+ sync : Sync .Type ,
38
+ defaultCtx : Map [String , String ]
39
+ )(implicit
81
40
F : Sync [F ]
82
41
) extends SelfAwareStructuredLogger [F ] {
83
42
43
+ def this (logger : JLogger , sync : Sync .Type = Sync .Type .Delay )(F : Sync [F ]) =
44
+ this (logger, sync, Map .empty)(F )
45
+
84
46
@ deprecated(" Use constructor with sync" , " 2.6.0" )
85
47
def this (logger : JLogger )(
86
48
F : Sync [F ]
87
49
) =
88
50
this (logger, Sync .Type .Delay )(F )
89
51
90
- override def isTraceEnabled : F [Boolean ] = F .delay(logger.isTraceEnabled)
91
- override def isDebugEnabled : F [Boolean ] = F .delay(logger.isDebugEnabled)
92
- override def isInfoEnabled : F [Boolean ] = F .delay(logger.isInfoEnabled)
93
- override def isWarnEnabled : F [Boolean ] = F .delay(logger.isWarnEnabled)
94
- override def isErrorEnabled : F [Boolean ] = F .delay(logger.isErrorEnabled)
52
+ private val isTraceEnabledUnsafe = () => logger.isTraceEnabled
53
+ private val isDebugEnabledUnsafe = () => logger.isDebugEnabled
54
+ private val isInfoEnabledUnsafe = () => logger.isInfoEnabled
55
+ private val isWarnEnabledUnsafe = () => logger.isWarnEnabled
56
+ private val isErrorEnabledUnsafe = () => logger.isErrorEnabled
57
+
58
+ override def addContext (ctx : Map [String , String ]): SelfAwareStructuredLogger [F ] =
59
+ new Slf4jLogger [F ](logger, sync, defaultCtx ++ ctx)
60
+
61
+ override def isTraceEnabled : F [Boolean ] =
62
+ F .delay(withPreparedMDCUnsafe(Map .empty, isTraceEnabledUnsafe))
63
+ override def isDebugEnabled : F [Boolean ] =
64
+ F .delay(withPreparedMDCUnsafe(Map .empty, isDebugEnabledUnsafe))
65
+ override def isInfoEnabled : F [Boolean ] =
66
+ F .delay(withPreparedMDCUnsafe(Map .empty, isInfoEnabledUnsafe))
67
+ override def isWarnEnabled : F [Boolean ] =
68
+ F .delay(withPreparedMDCUnsafe(Map .empty, isWarnEnabledUnsafe))
69
+ override def isErrorEnabled : F [Boolean ] =
70
+ F .delay(withPreparedMDCUnsafe(Map .empty, isErrorEnabledUnsafe))
95
71
96
72
override def trace (t : Throwable )(msg : => String ): F [Unit ] =
97
- noContextLog(isTraceEnabled , () => logger.trace(msg, t))
73
+ noContextLog(isTraceEnabledUnsafe , () => logger.trace(msg, t))
98
74
override def trace (msg : => String ): F [Unit ] =
99
- noContextLog(isTraceEnabled , () => logger.trace(msg))
75
+ noContextLog(isTraceEnabledUnsafe , () => logger.trace(msg))
100
76
override def trace (ctx : Map [String , String ])(msg : => String ): F [Unit ] =
101
- contextLog(isTraceEnabled , ctx, () => logger.trace(msg))
77
+ contextLog(isTraceEnabledUnsafe , ctx, () => logger.trace(msg))
102
78
override def trace (ctx : Map [String , String ], t : Throwable )(msg : => String ): F [Unit ] =
103
- contextLog(isTraceEnabled , ctx, () => logger.trace(msg, t))
79
+ contextLog(isTraceEnabledUnsafe , ctx, () => logger.trace(msg, t))
104
80
105
81
override def debug (t : Throwable )(msg : => String ): F [Unit ] =
106
- noContextLog(isDebugEnabled , () => logger.debug(msg, t))
82
+ noContextLog(isDebugEnabledUnsafe , () => logger.debug(msg, t))
107
83
override def debug (msg : => String ): F [Unit ] =
108
- noContextLog(isDebugEnabled , () => logger.debug(msg))
84
+ noContextLog(isDebugEnabledUnsafe , () => logger.debug(msg))
109
85
override def debug (ctx : Map [String , String ])(msg : => String ): F [Unit ] =
110
- contextLog(isDebugEnabled , ctx, () => logger.debug(msg))
86
+ contextLog(isDebugEnabledUnsafe , ctx, () => logger.debug(msg))
111
87
override def debug (ctx : Map [String , String ], t : Throwable )(msg : => String ): F [Unit ] =
112
- contextLog(isDebugEnabled , ctx, () => logger.debug(msg, t))
88
+ contextLog(isDebugEnabledUnsafe , ctx, () => logger.debug(msg, t))
113
89
114
90
override def info (t : Throwable )(msg : => String ): F [Unit ] =
115
- noContextLog(isInfoEnabled , () => logger.info(msg, t))
91
+ noContextLog(isInfoEnabledUnsafe , () => logger.info(msg, t))
116
92
override def info (msg : => String ): F [Unit ] =
117
- noContextLog(isInfoEnabled , () => logger.info(msg))
93
+ noContextLog(isInfoEnabledUnsafe , () => logger.info(msg))
118
94
override def info (ctx : Map [String , String ])(msg : => String ): F [Unit ] =
119
- contextLog(isInfoEnabled , ctx, () => logger.info(msg))
95
+ contextLog(isInfoEnabledUnsafe , ctx, () => logger.info(msg))
120
96
override def info (ctx : Map [String , String ], t : Throwable )(msg : => String ): F [Unit ] =
121
- contextLog(isInfoEnabled , ctx, () => logger.info(msg, t))
97
+ contextLog(isInfoEnabledUnsafe , ctx, () => logger.info(msg, t))
122
98
123
99
override def warn (t : Throwable )(msg : => String ): F [Unit ] =
124
- noContextLog(isWarnEnabled , () => logger.warn(msg, t))
100
+ noContextLog(isWarnEnabledUnsafe , () => logger.warn(msg, t))
125
101
override def warn (msg : => String ): F [Unit ] =
126
- noContextLog(isWarnEnabled , () => logger.warn(msg))
102
+ noContextLog(isWarnEnabledUnsafe , () => logger.warn(msg))
127
103
override def warn (ctx : Map [String , String ])(msg : => String ): F [Unit ] =
128
- contextLog(isWarnEnabled , ctx, () => logger.warn(msg))
104
+ contextLog(isWarnEnabledUnsafe , ctx, () => logger.warn(msg))
129
105
override def warn (ctx : Map [String , String ], t : Throwable )(msg : => String ): F [Unit ] =
130
- contextLog(isWarnEnabled , ctx, () => logger.warn(msg, t))
106
+ contextLog(isWarnEnabledUnsafe , ctx, () => logger.warn(msg, t))
131
107
132
108
override def error (t : Throwable )(msg : => String ): F [Unit ] =
133
- noContextLog(isErrorEnabled , () => logger.error(msg, t))
109
+ noContextLog(isErrorEnabledUnsafe , () => logger.error(msg, t))
134
110
override def error (msg : => String ): F [Unit ] =
135
- noContextLog(isErrorEnabled , () => logger.error(msg))
111
+ noContextLog(isErrorEnabledUnsafe , () => logger.error(msg))
136
112
override def error (ctx : Map [String , String ])(msg : => String ): F [Unit ] =
137
- contextLog(isErrorEnabled , ctx, () => logger.error(msg))
113
+ contextLog(isErrorEnabledUnsafe , ctx, () => logger.error(msg))
138
114
override def error (ctx : Map [String , String ], t : Throwable )(msg : => String ): F [Unit ] =
139
- contextLog(isErrorEnabled, ctx, () => logger.error(msg, t))
115
+ contextLog(isErrorEnabledUnsafe, ctx, () => logger.error(msg, t))
116
+
117
+ private def withPreparedMDCUnsafe [A ](extraCtx : Map [String , String ], body : () => A ): A = {
118
+ val ctx = defaultCtx ++ extraCtx
119
+ val backup =
120
+ try MDC .getCopyOfContextMap()
121
+ catch {
122
+ case e : IllegalStateException =>
123
+ // MDCAdapter is missing, no point in doing anything with
124
+ // the MDC, so just hope the logging backend can salvage
125
+ // something.
126
+ body()
127
+ throw e
128
+ }
129
+
130
+ try {
131
+ // Once 2.12 is no longer supported, change this to MDC.setContextMap(ctx.asJava)
132
+ MDC .clear()
133
+ ctx.foreach { case (k, v) => MDC .put(k, v) }
134
+ body()
135
+ } finally
136
+ if (backup eq null ) MDC .clear()
137
+ else MDC .setContextMap(backup)
138
+ }
139
+
140
+ private def noContextLog (isEnabledUnsafe : () => Boolean , logging : () => Unit ): F [Unit ] =
141
+ contextLog(isEnabledUnsafe, Map .empty, logging)
142
+
143
+ private def contextLog (
144
+ isEnabledUnsafe : () => Boolean ,
145
+ ctx : Map [String , String ],
146
+ logging : () => Unit
147
+ ): F [Unit ] =
148
+ F .delay(
149
+ withPreparedMDCUnsafe(
150
+ ctx,
151
+ () =>
152
+ if (isEnabledUnsafe()) {
153
+ logging()
154
+ }
155
+ )
156
+ )
140
157
}
141
158
}
0 commit comments