1
1
package izumi .logstage .api .routing
2
2
3
3
import izumi .logstage .api .Log
4
- import izumi .logstage .api .config .{LogConfigService , LogEntryConfig , LoggerConfig , LoggerPathConfig }
4
+ import izumi .logstage .api .config .{LogConfigService , LogEntryConfig , LoggerConfig , LoggerPath , LoggerPathRule }
5
5
import izumi .logstage .api .routing .LogConfigServiceImpl .{ConfiguredLogTreeNode , LogTreeNode }
6
6
7
7
import scala .annotation .tailrec
8
8
9
9
class LogConfigServiceImpl (loggerConfig : LoggerConfig ) extends LogConfigService {
10
10
override def threshold (e : Log .LoggerId ): Log .Level = {
11
- configFor(e) .threshold
11
+ configFor(e, - 1 ).config .threshold
12
12
}
13
13
14
14
override def config (e : Log .Entry ): LogEntryConfig = {
15
- LogEntryConfig (configFor(e.context.static.id).sinks)
15
+ val config = configFor(e.context.static.id, e.context.static.position.line)
16
+ if (e.context.dynamic.level >= config.config.threshold) {
17
+ LogEntryConfig (config.sinks)
18
+ } else {
19
+ LogEntryConfig (List .empty)
20
+ }
16
21
}
17
22
18
23
private val configTree = LogConfigServiceImpl .build(loggerConfig)
19
24
20
- @ inline private def configFor (e : Log .LoggerId ): LoggerPathConfig = {
21
- val configPath = findConfig(e.id.split('.' ).toList, List .empty, configTree)
25
+ @ inline private def configFor (e : Log .LoggerId , line : Int ): LoggerPathRule = {
26
+ val configPath = findConfig(e.id.split('.' ).toList, line, List .empty, configTree)
27
+
22
28
configPath
23
29
.collect {
24
30
case c : ConfiguredLogTreeNode => c
25
31
}.last.config
26
32
}
27
33
28
34
@ tailrec
29
- private final def findConfig (outPath : List [String ], inPath : List [LogTreeNode ], current : LogTreeNode ): List [LogTreeNode ] = {
35
+ private final def findConfig (outPath : List [String ], line : Int , inPath : List [LogTreeNode ], current : LogTreeNode ): List [LogTreeNode ] = {
30
36
outPath match {
31
37
case head :: tail =>
32
- current.sub.get(head) match {
33
- case Some (value) =>
34
- findConfig(tail, inPath :+ current, value)
35
- case None =>
36
- inPath :+ current
38
+ current match {
39
+ case _ =>
40
+ current.sub.get(LoggerPath (head, Some (line))).orElse(current.sub.get(LoggerPath (head, None ))) match {
41
+ case Some (value) =>
42
+ findConfig(tail, line, inPath :+ current, value)
43
+ case None =>
44
+ inPath :+ current
45
+ }
37
46
}
47
+
38
48
case Nil =>
39
49
inPath :+ current
40
50
}
41
51
}
42
52
43
- // override def close(): Unit = {
44
- // (loggerConfig.root.sinks ++ loggerConfig.entries.values.flatMap(_.sinks)).foreach(_.close())
45
- // }
46
-
47
53
private def print (node : LogTreeNode , level : Int ): String = {
48
54
val sub = node.sub.values.map(s => print(s, level + 1 ))
49
55
50
- def reprCfg (cfg : LoggerPathConfig ) = {
51
- s " ${cfg.threshold} -> ${cfg.sinks}"
56
+ def reprCfg (cfg : LoggerPathRule ) = {
57
+ s " ${cfg.config. threshold} -> ${cfg.sinks}"
52
58
}
53
59
54
60
val repr = node match {
55
61
case LogConfigServiceImpl .LogTreeRootNode (config, _) =>
56
62
s " [ ${reprCfg(config)}] "
57
63
case LogConfigServiceImpl .LogTreeEmptyNode (id, _) =>
58
64
s " $id"
59
- case LogConfigServiceImpl .LogTreeMainNode (id, config, _) =>
60
- s " $id: ${reprCfg(config)}"
65
+ case LogConfigServiceImpl .LogTreeMainNode (id, line, config, _) =>
66
+ s " $id[L= $line ] : ${reprCfg(config)}"
61
67
}
62
68
63
69
val out = (List (repr) ++ sub).mkString(" \n " )
@@ -76,41 +82,52 @@ class LogConfigServiceImpl(loggerConfig: LoggerConfig) extends LogConfigService
76
82
77
83
object LogConfigServiceImpl {
78
84
sealed trait LogTreeNode {
79
- def sub : Map [String , IdentifiedLogTreeNode ]
85
+ def sub : Map [LoggerPath , IdentifiedLogTreeNode ]
80
86
}
81
87
sealed trait IdentifiedLogTreeNode extends LogTreeNode {
82
88
def id : String
83
89
}
84
90
85
91
sealed trait ConfiguredLogTreeNode extends LogTreeNode {
86
- def config : LoggerPathConfig
92
+ def config : LoggerPathRule
87
93
}
88
94
89
- case class LogTreeRootNode (config : LoggerPathConfig , sub : Map [String , IdentifiedLogTreeNode ]) extends LogTreeNode with ConfiguredLogTreeNode
90
- case class LogTreeEmptyNode (id : String , sub : Map [String , IdentifiedLogTreeNode ]) extends IdentifiedLogTreeNode
91
- case class LogTreeMainNode (id : String , config : LoggerPathConfig , sub : Map [String , IdentifiedLogTreeNode ]) extends IdentifiedLogTreeNode with ConfiguredLogTreeNode
95
+ case class LogTreeRootNode (config : LoggerPathRule , sub : Map [LoggerPath , IdentifiedLogTreeNode ]) extends LogTreeNode with ConfiguredLogTreeNode
96
+ case class LogTreeEmptyNode (id : String , sub : Map [LoggerPath , IdentifiedLogTreeNode ]) extends IdentifiedLogTreeNode
97
+ case class LogTreeMainNode (id : String , line : Option [Int ], config : LoggerPathRule , sub : Map [LoggerPath , IdentifiedLogTreeNode ])
98
+ extends IdentifiedLogTreeNode
99
+ with ConfiguredLogTreeNode
92
100
93
101
def build (config : LoggerConfig ): LogTreeRootNode = {
94
- val p = config.entries.iterator.map { case (k, v) => (k.split('.' ).toList, v) }.toList
102
+ val p = config.entries.iterator.map {
103
+ case (k, v) =>
104
+ val parts = k.id.split('.' ).toList
105
+ (parts.init.map(p => LoggerPath (p, None )) ++ List (LoggerPath (parts.last, k.line)), v)
106
+ }.toList
95
107
LogTreeRootNode (config.root, buildLookupSubtree(p))
96
108
}
97
109
98
- private def buildLookupSubtree (entries : List [(List [String ], LoggerPathConfig )]): Map [String , IdentifiedLogTreeNode ] = {
99
- buildSubtrees(entries).map(node => (node.id, node)).toMap
110
+ private def buildLookupSubtree (entries : List [(List [LoggerPath ], LoggerPathRule )]): Map [LoggerPath , IdentifiedLogTreeNode ] = {
111
+ buildSubtrees(entries).map {
112
+ case m : LogTreeMainNode =>
113
+ (LoggerPath (m.id, m.line), m)
114
+ case o =>
115
+ (LoggerPath (o.id, None ), o)
116
+ }.toMap
100
117
}
101
118
102
- private def buildSubtrees (entries : List [(List [String ], LoggerPathConfig )]): List [IdentifiedLogTreeNode ] = {
119
+ private def buildSubtrees (entries : List [(List [LoggerPath ], LoggerPathRule )]): List [IdentifiedLogTreeNode ] = {
103
120
entries
104
121
.groupBy(_._1.head).map {
105
122
case (cp, entries) =>
106
123
val truncatedEntries = entries.map { case (p, c) => (p.tail, c) }
107
124
val (current, sub) = truncatedEntries.partition(_._1.isEmpty)
108
- val subTree : Map [String , IdentifiedLogTreeNode ] = if (sub.isEmpty) Map .empty else buildLookupSubtree(sub)
125
+ val subTree : Map [LoggerPath , IdentifiedLogTreeNode ] = if (sub.isEmpty) Map .empty else buildLookupSubtree(sub)
109
126
current match {
110
127
case Nil =>
111
- LogTreeEmptyNode (cp, subTree)
128
+ LogTreeEmptyNode (cp.id , subTree)
112
129
case head :: Nil =>
113
- LogTreeMainNode (cp, head._2, subTree)
130
+ LogTreeMainNode (cp.id, cp.line , head._2, subTree)
114
131
case list =>
115
132
throw new RuntimeException (s " BUG: More than one logger config bound to one path at $cp: $list" )
116
133
}
0 commit comments