1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.message;
18
19 import org.apache.logging.log4j.util.IndexedStringMap;
20 import org.apache.logging.log4j.util.PropertiesUtil;
21 import org.apache.logging.log4j.util.StringBuilderFormattable;
22 import org.apache.logging.log4j.util.StringBuilders;
23
24 import java.math.BigDecimal;
25 import java.util.Collection;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 enum MapMessageJsonFormatter {;
49
50 public static final int MAX_DEPTH = readMaxDepth();
51
52 private static final char DQUOTE = '"';
53
54 private static final char RBRACE = ']';
55
56 private static final char LBRACE = '[';
57
58 private static final char COMMA = ',';
59
60 private static final char RCURLY = '}';
61
62 private static final char LCURLY = '{';
63
64 private static final char COLON = ':';
65
66 private static int readMaxDepth() {
67 final int maxDepth = PropertiesUtil
68 .getProperties()
69 .getIntegerProperty("log4j2.mapMessage.jsonFormatter.maxDepth", 8);
70 if (maxDepth < 0) {
71 throw new IllegalArgumentException(
72 "was expecting a positive maxDepth, found: " + maxDepth);
73 }
74 return maxDepth;
75 }
76
77 static void format(final StringBuilder sb, final Object object) {
78 format(sb, object, 0);
79 }
80
81 private static void format(
82 final StringBuilder sb,
83 final Object object,
84 final int depth) {
85
86 if (depth >= MAX_DEPTH) {
87 throw new IllegalArgumentException("maxDepth has been exceeded");
88 }
89
90
91 if (object == null) {
92 sb.append("null");
93 }
94
95
96 else if (object instanceof IndexedStringMap) {
97 final IndexedStringMap map = (IndexedStringMap) object;
98 formatIndexedStringMap(sb, map, depth);
99 } else if (object instanceof Map) {
100 @SuppressWarnings("unchecked")
101 final Map<Object, Object> map = (Map<Object, Object>) object;
102 formatMap(sb, map, depth);
103 }
104
105
106 else if (object instanceof List) {
107 @SuppressWarnings("unchecked")
108 final List<Object> list = (List<Object>) object;
109 formatList(sb, list, depth);
110 } else if (object instanceof Collection) {
111 @SuppressWarnings("unchecked")
112 final Collection<Object> collection = (Collection<Object>) object;
113 formatCollection(sb, collection, depth);
114 }
115
116
117 else if (object instanceof Number) {
118 final Number number = (Number) object;
119 formatNumber(sb, number);
120 } else if (object instanceof Boolean) {
121 final boolean booleanValue = (boolean) object;
122 formatBoolean(sb, booleanValue);
123 }
124
125
126 else if (object instanceof StringBuilderFormattable) {
127 final StringBuilderFormattable formattable = (StringBuilderFormattable) object;
128 formatFormattable(sb, formattable);
129 }
130
131
132 else if (object instanceof char[]) {
133 final char[] charValues = (char[]) object;
134 formatCharArray(sb, charValues);
135 } else if (object instanceof boolean[]) {
136 final boolean[] booleanValues = (boolean[]) object;
137 formatBooleanArray(sb, booleanValues);
138 } else if (object instanceof byte[]) {
139 final byte[] byteValues = (byte[]) object;
140 formatByteArray(sb, byteValues);
141 } else if (object instanceof short[]) {
142 final short[] shortValues = (short[]) object;
143 formatShortArray(sb, shortValues);
144 } else if (object instanceof int[]) {
145 final int[] intValues = (int[]) object;
146 formatIntArray(sb, intValues);
147 } else if (object instanceof long[]) {
148 final long[] longValues = (long[]) object;
149 formatLongArray(sb, longValues);
150 } else if (object instanceof float[]) {
151 final float[] floatValues = (float[]) object;
152 formatFloatArray(sb, floatValues);
153 } else if (object instanceof double[]) {
154 final double[] doubleValues = (double[]) object;
155 formatDoubleArray(sb, doubleValues);
156 } else if (object instanceof Object[]) {
157 final Object[] objectValues = (Object[]) object;
158 formatObjectArray(sb, objectValues, depth);
159 }
160
161
162 else {
163 formatString(sb, object);
164 }
165
166 }
167
168 private static void formatIndexedStringMap(
169 final StringBuilder sb,
170 final IndexedStringMap map,
171 final int depth) {
172 sb.append(LCURLY);
173 final int nextDepth = depth + 1;
174 for (int entryIndex = 0; entryIndex < map.size(); entryIndex++) {
175 final String key = map.getKeyAt(entryIndex);
176 final Object value = map.getValueAt(entryIndex);
177 if (entryIndex > 0) {
178 sb.append(COMMA);
179 }
180 sb.append(DQUOTE);
181 final int keyStartIndex = sb.length();
182 sb.append(key);
183 StringBuilders.escapeJson(sb, keyStartIndex);
184 sb.append(DQUOTE).append(COLON);
185 format(sb, value, nextDepth);
186 }
187 sb.append(RCURLY);
188 }
189
190 private static void formatMap(
191 final StringBuilder sb,
192 final Map<Object, Object> map,
193 final int depth) {
194 sb.append(LCURLY);
195 final int nextDepth = depth + 1;
196 final boolean[] firstEntry = {true};
197 map.forEach((final Object key, final Object value) -> {
198 if (key == null) {
199 throw new IllegalArgumentException("null keys are not allowed");
200 }
201 if (firstEntry[0]) {
202 firstEntry[0] = false;
203 } else {
204 sb.append(COMMA);
205 }
206 sb.append(DQUOTE);
207 final String keyString = String.valueOf(key);
208 final int keyStartIndex = sb.length();
209 sb.append(keyString);
210 StringBuilders.escapeJson(sb, keyStartIndex);
211 sb.append(DQUOTE).append(COLON);
212 format(sb, value, nextDepth);
213 });
214 sb.append(RCURLY);
215 }
216
217 private static void formatList(
218 final StringBuilder sb,
219 final List<Object> items,
220 final int depth) {
221 sb.append(LBRACE);
222 final int nextDepth = depth + 1;
223 for (int itemIndex = 0; itemIndex < items.size(); itemIndex++) {
224 if (itemIndex > 0) {
225 sb.append(COMMA);
226 }
227 final Object item = items.get(itemIndex);
228 format(sb, item, nextDepth);
229 }
230 sb.append(RBRACE);
231 }
232
233 private static void formatCollection(
234 final StringBuilder sb,
235 final Collection<Object> items,
236 final int depth) {
237 sb.append(LBRACE);
238 final int nextDepth = depth + 1;
239 final boolean[] firstItem = {true};
240 items.forEach((final Object item) -> {
241 if (firstItem[0]) {
242 firstItem[0] = false;
243 } else {
244 sb.append(COMMA);
245 }
246 format(sb, item, nextDepth);
247 });
248 sb.append(RBRACE);
249 }
250
251 private static void formatNumber(final StringBuilder sb, final Number number) {
252 if (number instanceof BigDecimal) {
253 final BigDecimal decimalNumber = (BigDecimal) number;
254 sb.append(decimalNumber.toString());
255 } else if (number instanceof Double) {
256 final double doubleNumber = (Double) number;
257 sb.append(doubleNumber);
258 } else if (number instanceof Float) {
259 final float floatNumber = (float) number;
260 sb.append(floatNumber);
261 } else if (number instanceof Byte ||
262 number instanceof Short ||
263 number instanceof Integer ||
264 number instanceof Long) {
265 final long longNumber = number.longValue();
266 sb.append(longNumber);
267 } else {
268 final long longNumber = number.longValue();
269 final double doubleValue = number.doubleValue();
270 if (Double.compare(longNumber, doubleValue) == 0) {
271 sb.append(longNumber);
272 } else {
273 sb.append(doubleValue);
274 }
275 }
276 }
277
278 private static void formatBoolean(final StringBuilder sb, final boolean booleanValue) {
279 sb.append(booleanValue);
280 }
281
282 private static void formatFormattable(
283 final StringBuilder sb,
284 final StringBuilderFormattable formattable) {
285 sb.append(DQUOTE);
286 final int startIndex = sb.length();
287 formattable.formatTo(sb);
288 StringBuilders.escapeJson(sb, startIndex);
289 sb.append(DQUOTE);
290 }
291
292 private static void formatCharArray(final StringBuilder sb, final char[] items) {
293 sb.append(LBRACE);
294 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
295 if (itemIndex > 0) {
296 sb.append(COMMA);
297 }
298 final char item = items[itemIndex];
299 sb.append(DQUOTE);
300 final int startIndex = sb.length();
301 sb.append(item);
302 StringBuilders.escapeJson(sb, startIndex);
303 sb.append(DQUOTE);
304 }
305 sb.append(RBRACE);
306 }
307
308 private static void formatBooleanArray(final StringBuilder sb, final boolean[] items) {
309 sb.append(LBRACE);
310 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
311 if (itemIndex > 0) {
312 sb.append(COMMA);
313 }
314 final boolean item = items[itemIndex];
315 sb.append(item);
316 }
317 sb.append(RBRACE);
318 }
319
320 private static void formatByteArray(final StringBuilder sb, final byte[] items) {
321 sb.append(LBRACE);
322 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
323 if (itemIndex > 0) {
324 sb.append(COMMA);
325 }
326 final byte item = items[itemIndex];
327 sb.append(item);
328 }
329 sb.append(RBRACE);
330 }
331
332 private static void formatShortArray(final StringBuilder sb, final short[] items) {
333 sb.append(LBRACE);
334 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
335 if (itemIndex > 0) {
336 sb.append(COMMA);
337 }
338 final short item = items[itemIndex];
339 sb.append(item);
340 }
341 sb.append(RBRACE);
342 }
343
344 private static void formatIntArray(final StringBuilder sb, final int[] items) {
345 sb.append(LBRACE);
346 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
347 if (itemIndex > 0) {
348 sb.append(COMMA);
349 }
350 final int item = items[itemIndex];
351 sb.append(item);
352 }
353 sb.append(RBRACE);
354 }
355
356 private static void formatLongArray(final StringBuilder sb, final long[] items) {
357 sb.append(LBRACE);
358 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
359 if (itemIndex > 0) {
360 sb.append(COMMA);
361 }
362 final long item = items[itemIndex];
363 sb.append(item);
364 }
365 sb.append(RBRACE);
366 }
367
368 private static void formatFloatArray(final StringBuilder sb, final float[] items) {
369 sb.append(LBRACE);
370 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
371 if (itemIndex > 0) {
372 sb.append(COMMA);
373 }
374 final float item = items[itemIndex];
375 sb.append(item);
376 }
377 sb.append(RBRACE);
378 }
379
380 private static void formatDoubleArray(
381 final StringBuilder sb,
382 final double[] items) {
383 sb.append(LBRACE);
384 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
385 if (itemIndex > 0) {
386 sb.append(COMMA);
387 }
388 final double item = items[itemIndex];
389 sb.append(item);
390 }
391 sb.append(RBRACE);
392 }
393
394 private static void formatObjectArray(
395 final StringBuilder sb,
396 final Object[] items,
397 final int depth) {
398 sb.append(LBRACE);
399 final int nextDepth = depth + 1;
400 for (int itemIndex = 0; itemIndex < items.length; itemIndex++) {
401 if (itemIndex > 0) {
402 sb.append(COMMA);
403 }
404 final Object item = items[itemIndex];
405 format(sb, item, nextDepth);
406 }
407 sb.append(RBRACE);
408 }
409
410 private static void formatString(final StringBuilder sb, final Object value) {
411 sb.append(DQUOTE);
412 final int startIndex = sb.length();
413 final String valueString = String.valueOf(value);
414 sb.append(valueString);
415 StringBuilders.escapeJson(sb, startIndex);
416 sb.append(DQUOTE);
417 }
418
419 }