1 | package dmg.util.logback; |
2 | |
3 | import ch.qos.logback.classic.Level; |
4 | import org.slf4j.LoggerFactory; |
5 | import org.slf4j.Logger; |
6 | |
7 | import java.util.Collection; |
8 | import java.util.ArrayList; |
9 | import java.util.Map; |
10 | import java.util.HashMap; |
11 | import java.util.Set; |
12 | import java.util.HashSet; |
13 | import java.util.Collections; |
14 | import java.util.Comparator; |
15 | |
16 | /** |
17 | * Implementation of FilterThresholds that supports to types of |
18 | * inheritance: |
19 | * |
20 | * - Inheritance from a parent FilterThresholds |
21 | * - Inheritance from parent loggers |
22 | * |
23 | * If a threshold is not defined for a given combination of logger and |
24 | * filter then the parent InheritableFilterThresholds is consulted |
25 | * recursively. If not defined in the parent then threshold of the |
26 | * parent logger is used recursively. |
27 | */ |
28 | public class FilterThresholds |
29 | { |
30 | private final FilterThresholds _parent; |
31 | |
32 | private final Set<String> _filters = new HashSet<String>(); |
33 | |
34 | /* Logger x Filter -> Level */ |
35 | private final Map<LoggerName,Map<String,Level>> _rules = |
36 | new HashMap<LoggerName,Map<String,Level>>(); |
37 | |
38 | /* Logger x Filter -> Level */ |
39 | private final Map<LoggerName,Map<String,Level>> _effectiveMaps = |
40 | new HashMap<LoggerName,Map<String,Level>>(); |
41 | |
42 | /* Logger -> Level */ |
43 | private final Map<LoggerName,Level> _effectiveLevels = |
44 | new HashMap<LoggerName,Level>(); |
45 | |
46 | private static final Comparator<Level> LEVEL_ORDER = |
47 | new Comparator<Level>() { |
48 | public int compare(Level o1, Level o2) |
49 | { |
50 | if (!o1.isGreaterOrEqual(o2)) { |
51 | return -1; |
52 | } else if (!o2.isGreaterOrEqual(o1)) { |
53 | return 1; |
54 | } else { |
55 | return 0; |
56 | } |
57 | } |
58 | }; |
59 | |
60 | public FilterThresholds() |
61 | { |
62 | this(null); |
63 | } |
64 | |
65 | public FilterThresholds(FilterThresholds parent) |
66 | { |
67 | _parent = parent; |
68 | } |
69 | |
70 | public synchronized void addFilter(String filter) |
71 | { |
72 | if (filter == null) { |
73 | throw new IllegalArgumentException("Null value not allowed"); |
74 | } |
75 | _filters.add(filter); |
76 | } |
77 | |
78 | public synchronized Collection<String> getFilters() |
79 | { |
80 | if (_parent == null) { |
81 | return new ArrayList<String>(_filters); |
82 | } else { |
83 | Collection<String> filters = _parent.getFilters(); |
84 | filters.addAll(_filters); |
85 | return filters; |
86 | } |
87 | } |
88 | |
89 | public synchronized boolean hasFilter(String filter) |
90 | { |
91 | return _filters.contains(filter) || |
92 | (_parent != null && _parent.hasFilter(filter)); |
93 | } |
94 | |
95 | public synchronized Level get(LoggerName logger, String filter) |
96 | { |
97 | return getMap(logger).get(filter); |
98 | } |
99 | |
100 | public synchronized void setThreshold(LoggerName logger, String filter, Level level) |
101 | { |
102 | if (logger == null || filter == null || level == null) { |
103 | throw new IllegalArgumentException("Null value not allowed"); |
104 | } |
105 | |
106 | if (!hasFilter(filter)) { |
107 | throw new IllegalArgumentException("Filter does not exist"); |
108 | } |
109 | |
110 | Map<String,Level> map = _rules.get(logger); |
111 | if (map == null) { |
112 | map = new HashMap<String,Level>(); |
113 | _rules.put(logger, map); |
114 | } |
115 | map.put(filter, level); |
116 | |
117 | clearCache(); |
118 | } |
119 | |
120 | public synchronized void remove(LoggerName logger, String filter) |
121 | { |
122 | Map<String,Level> map = _rules.get(logger); |
123 | if (map != null) { |
124 | map.remove(filter); |
125 | if (map.isEmpty()) { |
126 | _rules.remove(logger); |
127 | } |
128 | clearCache(); |
129 | } |
130 | } |
131 | |
132 | public synchronized void clear() |
133 | { |
134 | _rules.clear(); |
135 | clearCache(); |
136 | } |
137 | |
138 | private synchronized void clearCache() |
139 | { |
140 | _effectiveLevels.clear(); |
141 | _effectiveMaps.clear(); |
142 | } |
143 | |
144 | /** |
145 | * Returns a map from filters to levels for a logger. |
146 | * |
147 | * Neither the parent levels nor parent loggers are consulted. |
148 | */ |
149 | private synchronized Map<String,Level> getMap(LoggerName logger) |
150 | { |
151 | Map<String,Level> map = _rules.get(logger); |
152 | return (map == null) ? Collections.EMPTY_MAP : map; |
153 | } |
154 | |
155 | /** |
156 | * Returns a map from filters to levels for a logger. |
157 | * |
158 | * The map contains inherited levels from parent levels. |
159 | */ |
160 | public synchronized Map<String,Level> getInheritedMap(LoggerName logger) |
161 | { |
162 | if (_parent == null) { |
163 | return new HashMap<String,Level>(getMap(logger)); |
164 | } else { |
165 | Map<String,Level> map = _parent.getInheritedMap(logger); |
166 | map.putAll(getMap(logger)); |
167 | return map; |
168 | } |
169 | } |
170 | |
171 | /** |
172 | * Returns a map from filters to levels for a logger. |
173 | * |
174 | * The map contains the effective log levels, that is, the levels |
175 | * used for filtering log events. |
176 | */ |
177 | private synchronized Map<String,Level> getEffectiveMap(LoggerName logger) |
178 | { |
179 | Map<String,Level> map = _effectiveMaps.get(logger); |
180 | if (map == null) { |
181 | LoggerName parent = logger.getParent();; |
182 | if (parent == null) { |
183 | map = getInheritedMap(logger); |
184 | } else { |
185 | map = new HashMap<String,Level>(getEffectiveMap(parent)); |
186 | map.putAll(getInheritedMap(logger)); |
187 | } |
188 | _effectiveMaps.put(logger, map); |
189 | } |
190 | return map; |
191 | } |
192 | |
193 | /** |
194 | * Returns a map from filters to levels for a logger. |
195 | * |
196 | * The map contains the effective log levels, that is, the levels |
197 | * used for filtering log events. |
198 | */ |
199 | public synchronized Level getThreshold(LoggerName logger, String filter) |
200 | { |
201 | return getEffectiveMap(logger).get(filter); |
202 | } |
203 | |
204 | public synchronized Level getThreshold(LoggerName logger) |
205 | { |
206 | if (_effectiveLevels.containsKey(logger)) { |
207 | return _effectiveLevels.get(logger); |
208 | } |
209 | |
210 | Map<String,Level> map = getEffectiveMap(logger); |
211 | Level level = |
212 | map.isEmpty() ? null : Collections.min(map.values(), LEVEL_ORDER); |
213 | _effectiveLevels.put(logger, level); |
214 | return level; |
215 | } |
216 | } |